/*
* Copyright (c) 2010-2013 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.evolveum.midpoint.util.logging;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import ch.qos.logback.classic.Level;
import org.apache.commons.lang.Validate;
/**
*
* @author lazyman
*
*/
public class LoggingUtils {
/**
* Standard way of logging exception: message is presented at ERROR level, stack trace on DEBUG.
*/
public static void logException(Trace LOGGER, String message, Throwable ex, Object... objects) {
logExceptionInternal(Level.ERROR, Level.DEBUG, LOGGER, message, ex, objects);
}
/**
* When logging unexpected exception, we always want to see the stack trace (so everything is logged on ERROR level)
*/
public static void logUnexpectedException(Trace LOGGER, String message, Throwable ex, Object... objects) {
logExceptionInternal(Level.ERROR, Level.ERROR, LOGGER, message, ex, objects);
}
/**
* Non-critical exceptions (warnings, with details as debug)
*/
public static void logExceptionAsWarning(Trace LOGGER, String message, Throwable ex, Object... objects) {
logExceptionInternal(Level.WARN, Level.DEBUG, LOGGER, message, ex, objects);
}
/**
* Exceptions that shouldn't be even visible on INFO level.
*/
public static void logExceptionOnDebugLevel(Trace LOGGER, String message, Throwable ex, Object... objects) {
logExceptionInternal(Level.DEBUG, Level.TRACE, LOGGER, message, ex, objects);
}
private static void logExceptionInternal(Level first, Level second, Trace LOGGER, String message, Throwable ex, Object... objects) {
Validate.notNull(LOGGER, "Logger can't be null.");
Validate.notNull(ex, "Exception can't be null.");
List<Object> args = new ArrayList<>();
args.addAll(Arrays.asList(objects));
args.add(ex.getMessage() + " (" + ex.getClass() + ")");
if (!first.equals(second)) {
log(LOGGER, first, message + ", reason: {}", args.toArray());
}
// Add exception to the list. It will be the last argument without {} in the message,
// therefore the stack trace will get logged
args.add(ex);
log(LOGGER, second, message + ".", args.toArray());
}
private static void log(Trace logger, Level level, String message, Object[] arguments) {
if (level == Level.ERROR) {
logger.error(message, arguments);
} else if (level == Level.WARN) {
logger.warn(message, arguments);
} else if (level == Level.INFO) {
logger.info(message, arguments);
} else if (level == Level.DEBUG) {
logger.debug(message, arguments);
} else if (level == Level.TRACE) {
logger.trace(message, arguments);
} else {
throw new IllegalArgumentException("Unknown level: " + level);
}
}
public static void logStackTrace(final Trace LOGGER, String message) {
if (LOGGER.isTraceEnabled()) {
if (message != null) {
LOGGER.trace(message+":\n{}", dumpStackTrace(LoggingUtils.class));
} else {
LOGGER.trace("{}", dumpStackTrace(LoggingUtils.class));
}
}
}
public static String dumpStackTrace(Class... classesToSkip) {
StackTraceElement[] fullStack = Thread.currentThread().getStackTrace();
String immediateClass = null;
String immediateMethod = null;
boolean firstFrameLogged = false;
StringBuilder sb = new StringBuilder();
OUTER: for (StackTraceElement stackElement: fullStack) {
if (!firstFrameLogged) {
if (stackElement.getClassName().equals(Thread.class.getName())) {
// skip call to thread.getStackTrace();
continue;
}
if (classesToSkip != null) {
for (Class classToSkip: classesToSkip) {
if (stackElement.getClassName().equals(classToSkip.getName())) {
continue OUTER;
}
}
}
}
firstFrameLogged = true;
sb.append(stackElement.toString());
sb.append("\n");
}
return sb.toString();
}
}