/**
* This file is part of the source code and related artifacts for eGym Application.
*
* Copyright © 2013 eGym GmbH
*/
package de.egym.logqueue.slf4j;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.Marker;
import org.slf4j.helpers.MessageFormatter;
import com.google.inject.Inject;
import de.egym.logqueue.EgymLogLevel;
import de.egym.logqueue.EgymLogLevels;
import de.egym.logqueue.EgymLogQueue;
import de.egym.logqueue.EgymLogRecord;
import de.egym.logqueue.formatter.EgymLogFormatterUtil;
/**
* The egym logger implementation. This is bound to slf4j in {@link EgymLoggerFactory} and handles <em>all</em> the log messages passed into
* slf4j.
*/
public class EgymLogger implements Logger {
/** Defines the log level threshold. Everything below this threshold will be ignored. */
private static final EgymLogLevel THRESHOLD = EgymLogLevel.DEBUG;
/**
* Defines logging thresholds based on logger names. This is useful to ignore certain packages which log excessively in the DEBUG level.
*/
private static final Map<String, EgymLogLevel> THRESHOLDS;
/** The log queue. Statically injected by Guice. This is null in the early phase of the application initialization. */
@Inject
static EgymLogQueue logQueue;
/** The logger name. */
private final String name;
/** Logger specific threshold. */
private final EgymLogLevel threshold;
static {
final Map<String, EgymLogLevel> thresholds = new HashMap<String, EgymLogLevel>();
// To avoid excessive logging we ignore everything from Hibernate which is below INFO.
// TODO: This should be moved into the pipeline configuration.
thresholds.put("org.hibernate", EgymLogLevel.INFO);
THRESHOLDS = Collections.unmodifiableMap(thresholds);
}
/**
* @param name
* the logger name.
*/
EgymLogger(String name) {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
}
this.name = name;
EgymLogLevel threshold = THRESHOLD;
for (String key : THRESHOLDS.keySet()) {
if (name.startsWith(key)) {
final EgymLogLevel specificThreshold = THRESHOLDS.get(key);
if (specificThreshold.ordinal() > threshold.ordinal()) {
threshold = specificThreshold;
}
}
}
this.threshold = threshold;
}
@Override
public String getName() {
return name;
}
@Override
public boolean isTraceEnabled() {
return isSufficientLogLevel(EgymLogLevel.TRACE);
}
@Override
public void trace(String msg) {
enqueue(EgymLogLevel.TRACE, msg);
}
@Override
public void trace(String format, Object arg) {
trace(format(format, arg));
}
@Override
public void trace(String format, Object arg1, Object arg2) {
trace(format(format, arg1, arg2));
}
@Override
public void trace(String format, Object... arguments) {
trace(format(format, arguments));
}
@Override
public void trace(String msg, Throwable t) {
enqueue(EgymLogLevel.TRACE, msg, t);
}
@Override
public boolean isTraceEnabled(Marker marker) {
return isSufficientLogLevel(EgymLogLevel.TRACE);
}
@Override
public void trace(Marker marker, String msg) {
trace(msg);
}
@Override
public void trace(Marker marker, String format, Object arg) {
trace(format, arg);
}
@Override
public void trace(Marker marker, String format, Object arg1, Object arg2) {
trace(format, arg1, arg2);
}
@Override
public void trace(Marker marker, String format, Object... argArray) {
trace(format, argArray);
}
@Override
public void trace(Marker marker, String msg, Throwable t) {
trace(msg, t);
}
@Override
public boolean isDebugEnabled() {
return isSufficientLogLevel(EgymLogLevel.DEBUG);
}
@Override
public void debug(String msg) {
enqueue(EgymLogLevel.DEBUG, msg);
}
@Override
public void debug(String format, Object arg) {
debug(format(format, arg));
}
@Override
public void debug(String format, Object arg1, Object arg2) {
debug(format(format, arg1, arg2));
}
@Override
public void debug(String format, Object... arguments) {
debug(format(format, arguments));
}
@Override
public void debug(String msg, Throwable t) {
enqueue(EgymLogLevel.DEBUG, msg, t);
}
@Override
public boolean isDebugEnabled(Marker marker) {
return isSufficientLogLevel(EgymLogLevel.DEBUG);
}
@Override
public void debug(Marker marker, String msg) {
debug(msg);
}
@Override
public void debug(Marker marker, String format, Object arg) {
debug(format, arg);
}
@Override
public void debug(Marker marker, String format, Object arg1, Object arg2) {
debug(format, arg1, arg2);
}
@Override
public void debug(Marker marker, String format, Object... arguments) {
debug(format, arguments);
}
@Override
public void debug(Marker marker, String msg, Throwable t) {
debug(msg, t);
}
@Override
public boolean isInfoEnabled() {
return isSufficientLogLevel(EgymLogLevel.INFO);
}
@Override
public void info(String msg) {
enqueue(EgymLogLevel.INFO, msg);
}
@Override
public void info(String format, Object arg) {
info(format(format, arg));
}
@Override
public void info(String format, Object arg1, Object arg2) {
info(format(format, arg1, arg2));
}
@Override
public void info(String format, Object... arguments) {
info(format(format, arguments));
}
@Override
public void info(String msg, Throwable t) {
enqueue(EgymLogLevel.INFO, msg, t);
}
@Override
public boolean isInfoEnabled(Marker marker) {
return isSufficientLogLevel(EgymLogLevel.INFO);
}
@Override
public void info(Marker marker, String msg) {
info(msg);
}
@Override
public void info(Marker marker, String format, Object arg) {
info(format, arg);
}
@Override
public void info(Marker marker, String format, Object arg1, Object arg2) {
info(format, arg1, arg2);
}
@Override
public void info(Marker marker, String format, Object... arguments) {
info(format, arguments);
}
@Override
public void info(Marker marker, String msg, Throwable t) {
info(msg, t);
}
@Override
public boolean isWarnEnabled() {
return isSufficientLogLevel(EgymLogLevel.WARN);
}
@Override
public void warn(String msg) {
enqueue(EgymLogLevel.WARN, msg);
}
@Override
public void warn(String format, Object arg) {
warn(format(format, arg));
}
@Override
public void warn(String format, Object... arguments) {
warn(format(format, arguments));
}
@Override
public void warn(String format, Object arg1, Object arg2) {
warn(format(format, arg1, arg2));
}
@Override
public void warn(String msg, Throwable t) {
enqueue(EgymLogLevel.WARN, msg, t);
}
@Override
public boolean isWarnEnabled(Marker marker) {
return isSufficientLogLevel(EgymLogLevel.WARN);
}
@Override
public void warn(Marker marker, String msg) {
warn(msg);
}
@Override
public void warn(Marker marker, String format, Object arg) {
warn(format, arg);
}
@Override
public void warn(Marker marker, String format, Object arg1, Object arg2) {
warn(format, arg1, arg2);
}
@Override
public void warn(Marker marker, String format, Object... arguments) {
warn(format, arguments);
}
@Override
public void warn(Marker marker, String msg, Throwable t) {
warn(msg, t);
}
@Override
public boolean isErrorEnabled() {
return isSufficientLogLevel(EgymLogLevel.ERROR);
}
@Override
public void error(String msg) {
enqueue(EgymLogLevel.ERROR, msg);
}
@Override
public void error(String format, Object arg) {
error(format(format, arg));
}
@Override
public void error(String format, Object arg1, Object arg2) {
error(format(format, arg1, arg2));
}
@Override
public void error(String format, Object... arguments) {
error(format(format, arguments));
}
@Override
public void error(String msg, Throwable t) {
enqueue(EgymLogLevel.ERROR, msg, t);
}
@Override
public boolean isErrorEnabled(Marker marker) {
return isSufficientLogLevel(EgymLogLevel.ERROR);
}
@Override
public void error(Marker marker, String msg) {
error(msg);
}
@Override
public void error(Marker marker, String format, Object arg) {
error(format, arg);
}
@Override
public void error(Marker marker, String format, Object arg1, Object arg2) {
error(format, arg1, arg2);
}
@Override
public void error(Marker marker, String format, Object... arguments) {
error(format, arguments);
}
@Override
public void error(Marker marker, String msg, Throwable t) {
error(msg, t);
}
/**
* Enqueues the specified log message.
*
* @param logLevel
* the log level. Must not be null.
* @param msg
* the log message. May be null.
*/
void enqueue(EgymLogLevel logLevel, String msg) {
enqueue(logLevel, msg, null);
}
/**
* Enqueues the specified log message and throwable.
*
* @param logLevel
* the log level. Must not be null.
* @param msg
* the log message. May be null.
* @param t
* the throwable. May be null.
*/
void enqueue(EgymLogLevel logLevel, String msg, Throwable t) {
if (logLevel == null) {
throw new IllegalArgumentException("logLevel must not be null");
}
// Skip everything which does not fulfill the log level threshold.
if (!isSufficientLogLevel(logLevel)) {
return;
}
final EgymLogRecord logRecord = new EgymLogRecord(DateTime.now(), this, logLevel, msg, t);
if (logQueue == null) {
// Fallback if log queue isn't initialized yet.
System.out.println(EgymLogFormatterUtil.formatLogRecord(logRecord, "[NO LOG QUEUE] "));
} else {
logQueue.log(logRecord);
}
}
/**
* Tests whether the given log level is equal to or exceeds the global threshold.
*
* @param logLevel
* the log level to test. Must not be null.
* @return True if the record's log level is equal to or exceeds the global threshold.
*/
boolean isSufficientLogLevel(EgymLogLevel logLevel) {
return EgymLogLevels.isSufficientLogLevel(logLevel, threshold);
}
/**
* Formats a log message with parameters.
*
* @param format
* the format string / template. Must not be null.
* @param arg
* the argument.
* @return the formatted log message.
*/
private String format(String format, Object arg) {
return MessageFormatter.format(format, arg).getMessage();
}
/**
* Formats a log message with parameters.
*
* @param format
* the format string / template. Must not be null.
* @param arg1
* the first argument.
* @param arg2
* the second argument.
* @return the formatted log message.
*/
private String format(String format, Object arg1, Object arg2) {
return MessageFormatter.format(format, arg1, arg2).getMessage();
}
/**
* Formats a log message with parameters.
*
* @param format
* the format string / template. Must not be null.
* @param args
* the arguments.
* @return the formatted log message.
*/
private String format(String format, Object... args) {
return MessageFormatter.arrayFormat(format, args).getMessage();
}
}