Log4j初始化详解:[url]http://donald-draper.iteye.com/blog/2332385[/url]
Log4j日志输出详解 :cry: :cry: :[url]http://donald-draper.iteye.com/blog/2332395[/url]
slf4j + Log4j的使用:[url]http://donald-draper.iteye.com/blog/2332407[/url]
上一篇讲了slf4j + Log4j的使用,其中获取Logger的一句为
private static Logger log = LoggerFactory.getLogger(testSFL4J.class);
下面来看这一句的具体含义:
public final class LoggerFactory
{
static final String CODES_PREFIX = "http://www.slf4j.org/codes.html";
static final String NO_STATICLOGGERBINDER_URL = "http://www.slf4j.org/codes.html#StaticLoggerBinder";
static final String MULTIPLE_BINDINGS_URL = "http://www.slf4j.org/codes.html#multiple_bindings";
static final String NULL_LF_URL = "http://www.slf4j.org/codes.html#null_LF";
static final String VERSION_MISMATCH = "http://www.slf4j.org/codes.html#version_mismatch";
static final String SUBSTITUTE_LOGGER_URL = "http://www.slf4j.org/codes.html#substituteLogger";
static final String LOGGER_NAME_MISMATCH_URL = "http://www.slf4j.org/codes.html#loggerNameMismatch";
static final String UNSUCCESSFUL_INIT_URL = "http://www.slf4j.org/codes.html#unsuccessfulInit";
static final String UNSUCCESSFUL_INIT_MSG = "org.slf4j.LoggerFactory could not be successfully initialized. See also http://www.slf4j.org/codes.html#unsuccessfulInit";
static final int UNINITIALIZED = 0;
static final int ONGOING_INITIALIZATION = 1;
static final int FAILED_INITIALIZATION = 2;
static final int SUCCESSFUL_INITIALIZATION = 3;
static final int NOP_FALLBACK_INITIALIZATION = 4;
static int INITIALIZATION_STATE = 0;
static SubstituteLoggerFactory TEMP_FACTORY = new SubstituteLoggerFactory();
static NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory();
static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch";
static boolean DETECT_LOGGER_NAME_MISMATCH = Boolean.getBoolean("slf4j.detectLoggerNameMismatch");
private static final String API_COMPATIBILITY_LIST[] = {
"1.6", "1.7"
};
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
//根据class,获取Logger
public static Logger getLogger(Class clazz)
{
Logger logger = getLogger(clazz.getName());
if(DETECT_LOGGER_NAME_MISMATCH)
{
Class autoComputedCallingClass = Util.getCallingClass();
if(nonMatchingClasses(clazz, autoComputedCallingClass))
{
Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", new Object[] {
logger.getName(), autoComputedCallingClass.getName()
}));
Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
}
}
return logger;
}
//根据class name 获取Logger
public static Logger getLogger(String name)
{
//获取LoggerFactory
ILoggerFactory iLoggerFactory = getILoggerFactory();
//从LoggerFactory获取Logger
return iLoggerFactory.getLogger(name);
}
//获取LoggerFactory
public static ILoggerFactory getILoggerFactory()
{
if(INITIALIZATION_STATE == 0)
{
INITIALIZATION_STATE = 1;
//执行初始化
performInitialization();
}
switch(INITIALIZATION_STATE)
{
case 3: // '\003'
//返回Log4jLoggerFactory
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case 4: // '\004'
//如果状态为4,则返回NOPLoggerFactory
return NOP_FALLBACK_FACTORY;
case 2: // '\002'
throw new IllegalStateException("org.slf4j.LoggerFactory could not be successfully initialized. See also http://www.slf4j.org/codes.html#unsuccessfulInit");
//如果初始化状态为1,返回临时LoggerFactory,SubstituteLoggerFactory
case 1: // '\001'
return TEMP_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
//执行初始化
private static final void performInitialization()
{
//绑定日志工场
bind();
if(INITIALIZATION_STATE == 3)
//验证配置
versionSanityCheck();
}
//绑定日志工场
private static final void bind()
{
try
{
//获取具体LoggerBinder类,默认为StaticLoggerBinder,在slf4j-log4j12-1.7.9.jar 中
Set staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = 3;
reportActualBinding(staticLoggerBinderPathSet);
//从SubstituteLoggerFactory获取具体sfl4j的Logger实现,并用SubstituteLogger代理类去包装
fixSubstitutedLoggers();
}
catch(NoClassDefFoundError ncde)
{
String msg = ncde.getMessage();
if(messageContainsOrgSlf4jImplStaticLoggerBinder(msg))
{
//初始化状态为4,返回NOPLoggerFactory,无配置Logger
INITIALIZATION_STATE = 4;
Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.");
} else
{
failedBinding(ncde);
throw ncde;
}
}
catch(NoSuchMethodError nsme)
{
String msg = nsme.getMessage();
if(msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1)
{
//org.slf4j.LoggerFactory could not be successfully initialized
INITIALIZATION_STATE = 2;
Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
Util.report("Your binding is version 1.5.5 or earlier.");
Util.report("Upgrade your binding to version 1.6.x.");
}
throw nsme;
}
catch(Exception e)
{
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e);
}
}
//获取StaticLoggerBinderPathS
private static Set findPossibleStaticLoggerBinderPathSet()
{
Set staticLoggerBinderPathSet = new LinkedHashSet();
try
{
ClassLoader loggerFactoryClassLoader = org/slf4j/LoggerFactory.getClassLoader();
Enumeration paths;
if(loggerFactoryClassLoader == null)
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
else
// private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
URL path;
for(; paths.hasMoreElements(); staticLoggerBinderPathSet.add(path))
path = (URL)paths.nextElement();
}
return staticLoggerBinderPathSet;
}
// StaticLoggerBinder,是否有多个实现版本
private static boolean isAmbiguousStaticLoggerBinderPathSet(Set staticLoggerBinderPathSet)
{
return staticLoggerBinderPathSet.size() > 1;
}
//report多StaticLoggerBinder,并打印具体实现的package,jar地址
private static void reportMultipleBindingAmbiguity(Set staticLoggerBinderPathSet)
{
if(isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet))
{
Util.report("Class path contains multiple SLF4J bindings.");
URL path;
for(Iterator iterator = staticLoggerBinderPathSet.iterator(); iterator.hasNext(); Util.report((new StringBuilder()).append("Found binding in [").append(path).append("]").toString()))
path = (URL)iterator.next();
Util.report("See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.");
}
}
//report实际绑定,实际绑定的StaticLoggerBinder,是随机的。
private static void reportActualBinding(Set staticLoggerBinderPathSet)
{
if(isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet))
Util.report((new StringBuilder()).append("Actual binding is of type [").append(StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr()).append("]").toString());
}
//从SubstituteLoggerFactory获取具体sfl4j的Logger实现,并用SubstituteLogger代理类去包装
//如果日志Logger为sfl4j的Logger的实现,则用SubstituteLogger去代理具体的实现Logger
private static final void fixSubstitutedLoggers()
{
//从临时工厂SubstituteLoggerFactory,获取所有Loggers
List loggers = TEMP_FACTORY.getLoggers();
if(loggers.isEmpty())
return;
Util.report("The following set of substitute loggers may have been accessed");
Util.report("during the initialization phase. Logging calls during this");
Util.report("phase were not honored. However, subsequent logging calls to these");
Util.report("loggers will work as normally expected.");
Util.report("See also http://www.slf4j.org/codes.html#substituteLogger");
SubstituteLogger subLogger;
for(Iterator i$ = loggers.iterator(); i$.hasNext(); Util.report(subLogger.getName()))
{
subLogger = (SubstituteLogger)i$.next();
subLogger.setDelegate(getLogger(subLogger.getName()));
}
TEMP_FACTORY.clear();
}
//验证配置,校验文件
private static final void versionSanityCheck()
{
try
{
String requested = StaticLoggerBinder.REQUESTED_API_VERSION;
boolean match = false;
for(int i = 0; i < API_COMPATIBILITY_LIST.length; i++)
if(requested.startsWith(API_COMPATIBILITY_LIST[i]))
match = true;
if(!match)
{
Util.report((new StringBuilder()).append("The requested version ").append(requested).append(" by your slf4j binding is not compatible with ").append(Arrays.asList(API_COMPATIBILITY_LIST).toString()).toString());
Util.report("See http://www.slf4j.org/codes.html#version_mismatch for further details.");
}
}
}
}
下面来看一下StaticLoggerBinder
public class StaticLoggerBinder
implements LoggerFactoryBinder
{
public static final StaticLoggerBinder getSingleton()
{
return SINGLETON;
}
private StaticLoggerBinder()
{
Level level;
try
{
level = Level.TRACE;
}
}
public ILoggerFactory getLoggerFactory()
{
return loggerFactory;
}
public String getLoggerFactoryClassStr()
{
return loggerFactoryClassStr;
}
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
public static String REQUESTED_API_VERSION = "1.6.99";
private static final String loggerFactoryClassStr = org/slf4j/impl/Log4jLoggerFactory.getName();
//从这里可以看出,返回的为Log4jLoggerFactory
private final ILoggerFactory loggerFactory = new Log4jLoggerFactory();
}
再看Log4jLoggerFactory
//Log4jLoggerFactory
public class Log4jLoggerFactory
implements ILoggerFactory
{
public Log4jLoggerFactory()
{
loggerMap = new ConcurrentHashMap();
}
public Logger getLogger(String name)
{
//如果有slf4jLogger具体实现,则返回
Logger slf4jLogger = (Logger)loggerMap.get(name);
if(slf4jLogger != null)
return slf4jLogger;
org.apache.log4j.Logger log4jLogger;
if(name.equalsIgnoreCase("ROOT"))
log4jLogger = LogManager.getRootLogger();
else
//看到这一句是不是很熟悉,LogManager,初始配置,获取log4jLogger
//这个具体的我们在log4j初始化,那篇文章中有讲
log4jLogger = LogManager.getLogger(name);
//将log4jLogger包装成slf4jLogger
Logger newInstance = new Log4jLoggerAdapter(log4jLogger);
Logger oldInstance = (Logger)loggerMap.putIfAbsent(name, newInstance);
return oldInstance != null ? oldInstance : newInstance;
}
ConcurrentMap loggerMap;
}
//Log4jLoggerAdapter
import java.io.Serializable;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.slf4j.Marker;
import org.slf4j.helpers.*;
import org.slf4j.spi.LocationAwareLogger;
public final class Log4jLoggerAdapter extends MarkerIgnoringBase
implements LocationAwareLogger, Serializable
{
Log4jLoggerAdapter(Logger logger)
{
this.logger = logger;
name = logger.getName();
}
public void info(String msg)
{
//这里就是直接调用Log4J的log INFO
logger.log(FQCN, Level.INFO, msg, null);
}
private static final long serialVersionUID = 6182834493563598289L;
final transient Logger logger;
static final String FQCN = org/slf4j/impl/Log4jLoggerAdapter.getName();
final boolean traceCapable = isTraceCapable();
}
//LocationAwareLogger
import org.slf4j.Logger;
import org.slf4j.Marker;
public interface LocationAwareLogger
extends Logger
{
public abstract void log(Marker marker, String s, int i, String s1, Object aobj[], Throwable throwable);
public static final int TRACE_INT = 0;
public static final int DEBUG_INT = 10;
public static final int INFO_INT = 20;
public static final int WARN_INT = 30;
public static final int ERROR_INT = 40;
}
//SubstituteLogger,Logger具体实现的代理类
public class SubstituteLogger
implements Logger
{
public void setDelegate(Logger delegate)
{
_delegate = delegate;
}
private final String name;
private volatile Logger _delegate;
}
当StaticLoggerBinder,找不到默认的Log4J,则从临时工厂SubstituteLoggerFactory,去获取
合适的Logger
//SubstituteLoggerFactory
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
public class SubstituteLoggerFactory
implements ILoggerFactory
{
final ConcurrentMap loggers = new ConcurrentHashMap();
//从SubstituteLoggerFactory或sfl4j的具体实现Logger,如果工厂中不存在,
//则新建一个Logger,并放入SubstituteLoggerFactory中
public Logger getLogger(String name)
{
SubstituteLogger logger = (SubstituteLogger)loggers.get(name);
if(logger == null)
{
logger = new SubstituteLogger(name);
SubstituteLogger oldLogger = (SubstituteLogger)loggers.putIfAbsent(name, logger);
if(oldLogger != null)
logger = oldLogger;
}
return logger;
}
}
下面来看一下:NOPLoggerFactory
//NOPLoggerFactory
public class NOPLoggerFactory
implements ILoggerFactory
{
public NOPLoggerFactory()
{
}
public Logger getLogger(String name)
{
return NOPLogger.NOP_LOGGER;
}
}
//NOPLogger
public class NOPLogger extends MarkerIgnoringBase
{
public static final NOPLogger NOP_LOGGER = new NOPLogger();
}
//MarkerIgnoringBase
import org.slf4j.Logger;
import org.slf4j.Marker;
public abstract class MarkerIgnoringBase extends NamedLoggerBase
implements Logger
{
public void info(Marker marker, String msg)
{
info(msg);
}
public void info(Marker marker, String format, Object arg)
{
info(format, arg);
}
public void info(Marker marker, String format, Object arg1, Object arg2)
{
info(format, arg1, arg2);
}
public transient void info(Marker marker, String format, Object arguments[])
{
info(format, arguments);
}
public void info(Marker marker, String msg, Throwable t)
{
info(msg, t);
}
public volatile String getName()
{
return super.getName();
}
}
测试当有多个StaticLoggerBinder具体实现,实际bind,添加多个具体实现jar包,控制台会输出:
第一种情况:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/E:/lib/logback-classic-0.9.27.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/E:/lib/slf4j-log4j12-1.7.9.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
####实际绑定为logback-classic-0.9.27.jar的StaticLoggerBinder
SLF4J: Actual binding is of type [ch.qos.logback.classic.selector.DefaultContextSelector]
==================================================================
第二种情况:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/E:/lib/slf4j-log4j12-1.7.9.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/E:/lib/logback-classic-0.9.27.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
####实际绑定为slf4j-log4j12-1.7.9.jar的StaticLoggerBinder
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
从输出信息可以看出,slf4j 实际bind StaticLoggerBinder,以java build path 中引用的jar的顺序有关,测试结果是第一个发现的jar。
总结:
[color=blue]从上面可以分析,可以看出sfl4j,通过LoggerFactory,来获取实际的Logger实现,默认会找Log4jLoggerFactory,从Log4jLoggerFactory获取log4jLogger,具体为log4jLogger的适配器Log4jLoggerAdapter。当无法找到Log4jLoggerFactory,则从SubstituteLoggerFactory,获取sfl4j的具体实现,并通过SubstituteLogger取代;如果无法找到sfl4j的具体实现,则从NOPLoggerFactory获取Logger。当Logger为Log4jLoggerAdapter时,则调用log4j的日志打印;当Logger为SubstituteLogger,则通过SubstituteLogger,打印日志;如果上面两种,都没有则使用NOPLogger,去打印日志。[/color]