为什么要看logback源码
项目里面log.info log.error 在请求量大的时候某个请求出问题,很难定位到相关日志,所以针对前端统一返回一个id后端日志自动拼接上这个id
slf4j的理解
我的理解slf4j是一个抽象的日志接口,并没有具体实现。我们可以通过slf4j集成各种日志框架logback,log4j,common-logging等框架都实现了这些接口
什么是logback
Logback是由log4j创始人设计的另一个开源日志组件,官方网站: http://logback.qos.ch 是log4j的改良版本
具有更快的实现:Logback的内核重写了,在一些关键执行路径上性能提升10倍以上。而且logback不仅性能提升了,初始化内存加载也更小了。
初始化过程
首先我们看一段使用例子
<1>
protected Logger logger = LoggerFactory.getLogger(this.getClass()); @Test void testInfo() {
logger.info("testffffffffffffff"); }
从入口往下看
LoggerFactory
<1>getLogger
org.slf4j.LoggerFactory#getLogge最终传入class name调以下方法
public static Logger getLogger(String name) { //<2>每种日志框架都实现了LoggerFactory 这里就是根据集成的日志框架获得对应的factory ILoggerFactory iLoggerFactory = getILoggerFactory(); return iLoggerFactory.getLogger(name); }
<2>getILoggerFactory
org.slf4j.LoggerFactory#getLogger
->
org.slf4j.LoggerFactory#getILoggerFactory
public static ILoggerFactory getILoggerFactory() { /** * 0:未初始化 * 1:准备初始化 * 2:类没有实现LoggerFactoryBinder 相关方法 * 3:获取binder成功 * 4:没有找到相关类 */ static volatile int INITIALIZATION_STATE = 0; //这个工厂创建NOPLogger实例 是个空实现 static final NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory(); public static ILoggerFactory getILoggerFactory() { /** * 判断是否初始化 */ if (INITIALIZATION_STATE == 0) { Class var0 = LoggerFactory.class; //加锁并判断 防止初始化后释放锁 等待的进来重复加载 synchronized(LoggerFactory.class) { if (INITIALIZATION_STATE == 0) { //标识正在初始化 INITIALIZATION_STATE = 1; //<4>执行初始化化绑定 performInitialization(); } } } switch(INITIALIZATION_STATE) { case 1: return SUBST_FACTORY; case 2: throw new IllegalStateException("org.slf4j.LoggerFactory in failed state. Original exception was thrown EARLIER. See also http://www.slf4j.org/codes.html#unsuccessfulInit"); case 3: //<5>可以看到此处是根据StaticLoggerBinder 这是一个slf4j继承点 为logback实现 下面会讲 return StaticLoggerBinder.getSingleton().getLoggerFactory(); case 4: return NOP_FALLBACK_FACTORY;//如果没有找到相关绑定类 则默认返回空的Factory default: throw new IllegalStateException("Unreachable code"); } } }
<3>findPossibleStaticLoggerBinderPathSet
org.slf4j.LoggerFactory#findPossibleStaticLoggerBinderPathSet
private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class"; static Set<URL> findPossibleStaticLoggerBinderPathSet() { LinkedHashSet staticLoggerBinderPathSet = new LinkedHashSet(); try { ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader(); Enumeration paths; if (loggerFactoryClassLoader == null) { //搜索位置查找给定资源名称的所有系统资源,以加载类 paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH); } else { //搜索位置查找给定资源名称的所有系统资源,以加载类 paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH); } while(paths.hasMoreElements()) { URL path = (URL)paths.nextElement(); staticLoggerBinderPathSet.add(path); } } catch (IOException var4) { Util.report("Error getting resources from path", var4); } return staticLoggerBinderPathSet; }
<4> performInitialization
org.slf4j.LoggerFactory#performInitialization
private static final void performInitialization() { //<6>执行绑定 bind(); //3表示成功获取binder实现 if (INITIALIZATION_STATE == 3) { //这里会获取binder的REQUESTED_API_VERSION 里面的静态变量的版本 跟self4j 做比较 versionSanityCheck(); } }
<6> bind
org.slf4j.LoggerFactory#bind
private static final void bind() { String msg; try { Set<URL> staticLoggerBinderPathSet = null; //判断系统变量:-Djava.vendor.url 是否包含android 默认是不会包含的 if (!isAndroid()) { /** *<3>在classpath查找 org/slf4j/impl/StaticLoggerBinder.class */ staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet(); /** * 检查是否找到多个binder */ reportMultipleBindingAmbiguity(staticLoggerBinderPathSet); } /** *1.先触发类加载<8>
*2.获取调用getSingleton 并执行静态初始化逻辑 binder必须有这个方法<7> */ StaticLoggerBinder.getSingleton(); //表示获取binder成功 INITIALIZATION_STATE = 3; //重复校验 如果找到多个会报错 reportActualBinding(staticLoggerBinderPathSet); fixSubstituteLoggers(); replayEvents(); SUBST_FACTORY.clear(); } catch (NoClassDefFoundError var2) { msg = var2.getMessage(); if (!messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) { failedBinding(var2); throw var2; } 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."); } catch (NoSuchMethodError var3) { msg = var3.getMessage(); if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) { 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 var3; } catch (Exception var4) { failedBinding(var4); throw new IllegalStateException("Unexpected initialization failure", var4); } }
代码<1>处就是自定义binder返回自定义Logger工厂的扩展点.可以发现binder必须拥有getSingleton 以及上面的版本控制performInitialization获取的 StaticLoggerBinder.REQUESTED_API_VERSION 静态版本变量
StaticLoggerBinder
<5>init
org.slf4j.impl.StaticLoggerBinder#init
void init() { try { try { //<2>委托ContextInitializer初始化LoggerContext 具体后面讲 直通车:点击跳转 (new ContextInitializer(this.defaultLoggerContext)).autoConfig(); } catch (JoranException var2) { Util.report("Failed to auto configure default logger context", var2); } /** * 如果没有配置文件则使用默认配置文件 */ if (!StatusUtil.contextHasStatusListener(this.defaultLoggerContext)) { StatusPrinter.printInCaseOfErrorsOrWarnings(this.defaultLoggerContext); } /** * 首先看系统变量是否有配置-Dlogback.ContextSelector="JNDI'配置了返回ContextJNDISelector * 如果不等于JNDI则当做自定义ContextSelector 会通过类加载 必须拥有一个参数的构造函数LoggerContext * 默认会使用DefaultContextSelector */ this.contextSelectorBinder.init(this.defaultLoggerContext, KEY); //标识为初始化成功 this.initialized = true; } catch (Exception var3) { Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", var3); } }
这里初始化成功上面则会调用
org.slf4j.LoggerFactory#getLogger#getILoggerFactory
->
org.slf4j.impl.StaticLoggerBinder#getLoggerFactory
public ILoggerFactory getLoggerFactory() { //是否初始化成功 if (!this.initialized) { //如果没有返回默认的LoggerContext return this.defaultLoggerContext; } else if (this.contextSelectorBinder.getContextSelector() == null) { throw new IllegalStateException("contextSelector cannot be null. See also http://logback.qos.ch/codes.html#null_CS"); } else { //最终根据contextSelectorBinder 获取LoggerContext return this.contextSelectorBinder.getContextSelector().getLoggerContext(); } }
<7>getSingleton
private static StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); public static StaticLoggerBinder getSingleton() { return SINGLETON; }
<8>
//<5>静态域初始化StaticLoggerBinder static { SINGLETON.init(); }
总结
1.slf4j根据查找是否有StaticLoggerBinder来为集成点必须要有getSingleton()返回当前实例 以及getLoggerFactory()返回工厂对象以及静态变量REQUESTED_API_VERSION logback也有对应的实现
2.log StaticLoggerBinder基于static{}做一些初始化动作 getFactory方法委托ContextSelectorBinder返回工厂对象 可以扩展
4.StaticLoggerBinder的init方法 初始化配置文件是委托给ContextInitializer.init做的