slf4j + Logback详解
程序员文章站
2022-07-03 16:59:12
...
Log4j初始化详解:[url]http://donald-draper.iteye.com/blog/2332385[/url]
Log4j日志输出详解:[url]http://donald-draper.iteye.com/admin/blogs/2332395[/url]
slf4j + Log4j的使用:[url]http://donald-draper.iteye.com/admin/blogs/2332407[/url]
slf4j + Log4j 详解:[url]http://donald-draper.iteye.com/admin/blogs/2332417[/url]
使用logback轻松管理日志 [url]http://blog.csdn.net/mydeman/article/details/6716925[/url]
Logback日志使用详解:[url]http://www.cnblogs.com/davidwang456/p/4448011.html[/url]
logback的介绍-配置:[url]http://sunney2010.iteye.com/blog/1404723[/url]
slf4j + Logback的使用:[url]http://donald-draper.iteye.com/admin/blogs/2332438[/url]
上一篇讲了slf4j + Logback的使用,其中获取Logger的一句为
[url]private static Logger log = LoggerFactory.getLogger(testLogback.class);[/url]
下面来看这一句的具体含义:
//StaticLoggerBinder
//ContextInitializer
//JoranConfigurator
//JoranConfiguratorBase
//GenericConfigurator
//LoggerContext
//ch.qos.logback.classic.Logger
//如果无配置文件,则使用BasicConfigurator,简单的控制台输出
总结:
从上面可以看出logback与sfl4j的整合,实际上是通过实现类StaticLoggerBinder,LoggerFactory加载
StaticLoggerBinder,StaticLoggerBinder通过静态语句块来,初始化LoggerContext,而LoggerContext实现
的ILoggerFactory接口,从LoggerContext获取的Logger实际为ch.qos.logback.classic.Logger,
即org.slf4j.Logger的实现类。
Log4j日志输出详解:[url]http://donald-draper.iteye.com/admin/blogs/2332395[/url]
slf4j + Log4j的使用:[url]http://donald-draper.iteye.com/admin/blogs/2332407[/url]
slf4j + Log4j 详解:[url]http://donald-draper.iteye.com/admin/blogs/2332417[/url]
使用logback轻松管理日志 [url]http://blog.csdn.net/mydeman/article/details/6716925[/url]
Logback日志使用详解:[url]http://www.cnblogs.com/davidwang456/p/4448011.html[/url]
logback的介绍-配置:[url]http://sunney2010.iteye.com/blog/1404723[/url]
slf4j + Logback的使用:[url]http://donald-draper.iteye.com/admin/blogs/2332438[/url]
上一篇讲了slf4j + Logback的使用,其中获取Logger的一句为
[url]private static Logger log = LoggerFactory.getLogger(testLogback.class);[/url]
下面来看这一句的具体含义:
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;
}
//report多bind
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实际绑定
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 String REQUESTED_API_VERSION = "1.6";
static final String NULL_CS_URL = "http://logback.qos.ch/codes.html#null_CS";
private static StaticLoggerBinder SINGLETON;
private static Object KEY = new Object();
private boolean initialized;
private LoggerContext defaultLoggerContext;
private final ContextSelectorStaticBinder contextSelectorBinder = ContextSelectorStaticBinder.getSingleton();
static
{
SINGLETON = new StaticLoggerBinder();
//初始化
SINGLETON.init();
}
private StaticLoggerBinder()
{
initialized = false;
defaultLoggerContext = new LoggerContext();
defaultLoggerContext.setName("default");
}
public static StaticLoggerBinder getSingleton()
{
return SINGLETON;
}
//初始化
void init()
{
try
{
try
{
//配置defaultLoggerContext
(new ContextInitializer(defaultLoggerContext)).autoConfig();
}
catch(JoranException je)
{
Util.report("Failed to auto configure default logger context", je);
}
StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);
contextSelectorBinder.init(defaultLoggerContext, KEY);
initialized = true;
}
catch(Throwable t)
{
Util.report((new StringBuilder()).append("Failed to instantiate [").append(ch/qos/logback/classic/LoggerContext.getName()).append("]").toString(), t);
}
}
}
//ContextInitializer
public class ContextInitializer
{
public static final String GROOVY_AUTOCONFIG_FILE = "logback.groovy";
public static final String AUTOCONFIG_FILE = "logback.xml";
public static final String TEST_AUTOCONFIG_FILE = "logback-test.xml";
public static final String CONFIG_FILE_PROPERTY = "logback.configurationFile";
public static final String STATUS_LISTENER_CLASS = "logback.statusListenerClass";
public static final String SYSOUT = "SYSOUT";
final LoggerContext loggerContext;
public ContextInitializer(LoggerContext loggerContext)
{
this.loggerContext = loggerContext;
}
public void autoConfig()
throws JoranException
{
StatusListenerConfigHelper.installIfAsked(loggerContext);
//获取配置资源,先找logback.groovy,logback-test.xml,logback.xml
URL url = findURLOfDefaultConfigurationFile(true);
if(url != null)
//根据资源配置LogContext
configureByResource(url);
else
BasicConfigurator.configure(loggerContext);
}
//获取配置资源,先找logback.groovy,logback-test.xml,logback.xml
public URL findURLOfDefaultConfigurationFile(boolean updateStatus)
{
ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
if(url != null)
return url;
url = getResource("logback.groovy", myClassLoader, updateStatus);
if(url != null)
return url;
url = getResource("logback-test.xml", myClassLoader, updateStatus);
if(url != null)
return url;
else
return getResource("logback.xml", myClassLoader, updateStatus);
}
//根据资源配置LogContext
public void configureByResource(URL url)
throws JoranException
{
if(url == null)
throw new IllegalArgumentException("URL argument cannot be null");
if(url.toString().endsWith("groovy"))
if(EnvUtil.isGroovyAvailable())
{
GafferUtil.runGafferConfiguratorOn(loggerContext, this, url);
} else
{
StatusManager sm = loggerContext.getStatusManager();
sm.add(new ErrorStatus("Groovy classes are not available on the class path. ABORTING INITIALIZATION.", loggerContext));
}
if(url.toString().endsWith("xml"))
{
JoranConfigurator configurator = new JoranConfigurator();
//设置LogContext
configurator.setContext(loggerContext);
//根据资源配置LogContext
configurator.doConfigure(url);
}
}
}
//JoranConfigurator
public class JoranConfigurator extends JoranConfiguratorBase
{
public void addInstanceRules(RuleStore rs)
{
super.addInstanceRules(rs);
rs.addRule(new Pattern("configuration"), new ConfigurationAction());
rs.addRule(new Pattern("configuration/contextName"), new ContextNameAction());
rs.addRule(new Pattern("configuration/contextListener"), new LoggerContextListenerAction());
rs.addRule(new Pattern("configuration/insertFromJNDI"), new InsertFromJNDIAction());
rs.addRule(new Pattern("configuration/evaluator"), new EvaluatorAction());
rs.addRule(new Pattern("configuration/appender/sift"), new SiftAction());
rs.addRule(new Pattern("configuration/appender/sift/*"), new NOPAction());
rs.addRule(new Pattern("configuration/logger"), new LoggerAction());
rs.addRule(new Pattern("configuration/logger/level"), new LevelAction());
rs.addRule(new Pattern("configuration/root"), new RootLoggerAction());
rs.addRule(new Pattern("configuration/root/level"), new LevelAction());
rs.addRule(new Pattern("configuration/logger/appender-ref"), new AppenderRefAction());
rs.addRule(new Pattern("configuration/root/appender-ref"), new AppenderRefAction());
rs.addRule(new Pattern("*/if"), new IfAction());
rs.addRule(new Pattern("*/if/then"), new ThenAction());
rs.addRule(new Pattern("*/if/then/*"), new NOPAction());
rs.addRule(new Pattern("*/if/else"), new ElseAction());
rs.addRule(new Pattern("*/if/else/*"), new NOPAction());
if(PlatformInfo.hasJMXObjectName())
rs.addRule(new Pattern("configuration/jmxConfigurator"), new JMXConfiguratorAction());
rs.addRule(new Pattern("configuration/include"), new IncludeAction());
rs.addRule(new Pattern("configuration/consolePlugin"), new ConsolePluginAction());
}
protected void addDefaultNestedComponentRegistryRules(DefaultNestedComponentRegistry registry)
{
DefaultNestedComponentRules.addDefaultNestedComponentRegistryRules(registry);
}
}
//JoranConfiguratorBase
public abstract class JoranConfiguratorBase extends GenericConfigurator
//GenericConfigurator
public abstract class GenericConfigurator extends ContextAwareBase
{
//根据资源配置LogContext
public final void doConfigure(URL url)
throws JoranException
{
try
{
//设置LogContext的URL
informContextOfURLUsedForConfiguration(url);
URLConnection urlConnection = url.openConnection();
urlConnection.setUseCaches(false);
InputStream in = urlConnection.getInputStream();
//根据输入流,配置LogContext
doConfigure(in);
in.close();
}
catch(IOException ioe)
{
String errMsg = (new StringBuilder()).append("Could not open URL [").append(url).append("].").toString();
addError(errMsg, ioe);
throw new JoranException(errMsg, ioe);
}
}
//设置LogContext的URL
protected void informContextOfURLUsedForConfiguration(URL url)
{
getContext().putObject(CoreConstants.URL_OF_LAST_CONFIGURATION_VIA_JORAN, url);
}
public final void doConfigure(InputStream inputStream)
throws JoranException
{
doConfigure(new InputSource(inputStream));
}
//根据输入流源,配置LogContext
public final void doConfigure(InputSource inputSource)
throws JoranException
{
SaxEventRecorder recorder = new SaxEventRecorder();
recorder.setContext(context);
recorder.recordEvents(inputSource);
buildInterpreter();
synchronized(context.getConfigurationLock())
{
interpreter.play(recorder.saxEventList);
}
}
protected Interpreter interpreter;
}
//LoggerContext
public class LoggerContext extends ContextBase
implements ILoggerFactory, LifeCycle
{
public LoggerContext()
{
noAppenderWarning = 0;
packagingDataEnabled = true;
maxCallerDataDepth = 8;
started = false;
resetCount = 0;
loggerCache = new Hashtable();
loggerContextRemoteView = new LoggerContextVO(this);
root.setLevel(Level.DEBUG);
loggerCache.put("ROOT", root);
initEvaluatorMap();
size = 1;
}
//获取Logger,ch.qos.logback.classic.Logger
public volatile Logger getLogger(String x0)
{
return getLogger(x0);
}
final ch.qos.logback.classic.Logger root = new ch.qos.logback.classic.Logger("ROOT", null, this);
private int size;
private int noAppenderWarning;
private final List loggerContextListenerList = new ArrayList();
private Hashtable loggerCache;
private LoggerContextVO loggerContextRemoteView;
private final TurboFilterList turboFilterList = new TurboFilterList();
private boolean packagingDataEnabled;
private int maxCallerDataDepth;
boolean started;
int resetCount;
}
//ch.qos.logback.classic.Logger
public final class Logger
implements org.slf4j.Logger, LocationAwareLogger, AppenderAttachable, Serializable
{
Logger(String name, Logger parent, LoggerContext loggerContext)
{
additive = true;
this.name = name;
this.parent = parent;
this.loggerContext = loggerContext;
buildRemoteView();
instanceCount++;
}
public final Level getEffectiveLevel()
{
return Level.toLevel(effectiveLevelInt);
}
//产生Info日志
public void info(String msg)
{
filterAndLog_0_Or3Plus(FQCN, null, Level.INFO, msg, null, null);
}
private final void filterAndLog_0_Or3Plus(String localFQCN, Marker marker, Level level, String msg, Object params[], Throwable t)
{
FilterReply decision = loggerContext.getTurboFilterChainDecision_0_3OrMore(marker, this, level, msg, params, t);
if(decision == FilterReply.NEUTRAL)
{
if(effectiveLevelInt > level.levelInt)
return;
} else
if(decision == FilterReply.DENY)
return;
buildLoggingEventAndAppend(localFQCN, marker, level, msg, params, t);
}
}
//如果无配置文件,则使用BasicConfigurator,简单的控制台输出
public class BasicConfigurator
{
public static void configure(LoggerContext lc)
{
StatusManager sm = lc.getStatusManager();
if(sm != null)
sm.add(new InfoStatus("Setting up default configuration.", lc));
ConsoleAppender ca = new ConsoleAppender();
ca.setContext(lc);
ca.setName("console");
PatternLayoutEncoder pl = new PatternLayoutEncoder();
pl.setContext(lc);
pl.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
pl.start();
ca.setEncoder(pl);
ca.start();
Logger rootLogger = lc.getLogger("ROOT");
rootLogger.addAppender(ca);
}
public static void configureDefaultContext()
{
LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
configure(lc);
}
static final BasicConfigurator hiddenSingleton = new BasicConfigurator();
}
总结:
从上面可以看出logback与sfl4j的整合,实际上是通过实现类StaticLoggerBinder,LoggerFactory加载
StaticLoggerBinder,StaticLoggerBinder通过静态语句块来,初始化LoggerContext,而LoggerContext实现
的ILoggerFactory接口,从LoggerContext获取的Logger实际为ch.qos.logback.classic.Logger,
即org.slf4j.Logger的实现类。
上一篇: 【vue】cookie保存用户登陆信息
下一篇: TypeScript进阶(泛型)