zoukankan      html  css  js  c++  java
  • slf4j日志框架绑定机制

    一、环境搭建

    我们以log4j为例,探寻slf4j与log4j的绑定过程。

    1.Java类

    public class Slf4jBind {
        public static void main(String[] args) {
            Logger LOGGER = LoggerFactory.getLogger(Slf4jBind.class);
            LOGGER.info("slf4j hello world");
        }
    }

    2.log4j.properties文件

    来自https://docs.oracle.com/cd/E29578_01/webhelp/cas_webcrawler/src/cwcg_config_log4j_file.html

    log4j.rootLogger=ERROR,stdout
    log4j.logger.com.endeca=INFO
    # Logger for crawl metrics
    log4j.logger.com.endeca.itl.web.metrics=INFO
    ​
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%p	%d{ISO8601}	%r	%c	[%t]	%m%n

    3.Maven的pom.xml中添加如下依赖

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.6.4</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.6.4</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.16</version>
    </dependency>

    其中,slf4j-api定义接口的包。

    slf4j-log4j12为slf4j与logj之间的桥接包。

    log4j为log4j的具体实现包。

    4.单步跟踪

    在main函数处打断点,debug模式下单步跟踪即可

    二、slf4j绑定log4j流程

    main函数中调用LoggerFactory.getLogger时,将依次执行下面的函数。

    slf4j对LoggerFactroy的说明如下:

    LoggerFactory是为各个日志API生成Logger的帮助类。

    如log4j,logback,jdk 1.4 logging,也支持NOPLogger,SimpleLogger。

    LoggerFactory内部封装了ILoggerFactory,具体的ILoggerFactory与LoggerFactory在编译期(complile time)绑定。

    public static Logger getLogger(Class clazz) {
      return getLogger(clazz.getName());
    }
     
    public static Logger getLogger(String name) {
      ILoggerFactory iLoggerFactory = getILoggerFactory();
      return iLoggerFactory.getLogger(name);
    }
    ​
    /
     * ILoggerFactory instance is bound with this class at compile time.
     * 
     * @return the ILoggerFactory instance in use
     */
    public static ILoggerFactory getILoggerFactory() {
      if (INITIALIZATION_STATE == UNINITIALIZED) {
        INITIALIZATION_STATE = ONGOING_INITILIZATION;
        performInitialization();
    ​
      }
      switch (INITIALIZATION_STATE) {
      case SUCCESSFUL_INITILIZATION:
        return StaticLoggerBinder.getSingleton().getLoggerFactory();
      case NOP_FALLBACK_INITILIZATION:
        return NOP_FALLBACK_FACTORY;
      case FAILED_INITILIZATION:
        throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
      case ONGOING_INITILIZATION:
        // support re-entrant behavior.
        // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
        return TEMP_FACTORY;
      }
      throw new IllegalStateException("Unreachable code");
    }
    private final static void performInitialization() {
      //对具体的日志框架实现是否仅有一个进行check
      singleImplementationSanityCheck();
      //与具体的日志框架绑定
      bind();
      if (INITIALIZATION_STATE == SUCCESSFUL_INITILIZATION) {
      //版本依赖兼容性check
        versionSanityCheck();
      }
    }

    1.对具体的日志框架实现是否仅有一个进行check。

    1).判断classpath下是否有多个org/slf4j/impl/StaticLoggerBinder.class

    2).如果有多个,将提示有多个SLF4J的绑定包。

    private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
    ​
    private static void singleImplementationSanityCheck() {
      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);
        }
        // use Set instead of list in order to deal with  bug #138
        // LinkedHashSet appropriate here because it preserves insertion order during iteration
        Set implementationSet = new LinkedHashSet();
        while (paths.hasMoreElements()) {
          URL path = (URL) paths.nextElement();
          implementationSet.add(path);
        }
        if (implementationSet.size() > 1) {
          Util.report("Class path contains multiple SLF4J bindings.");
          Iterator iterator = implementationSet.iterator();
          while(iterator.hasNext()) {
            URL path = (URL) iterator.next();
            Util.report("Found binding in [" + path + "]");
          }
          Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
        }
      } catch (IOException ioe) {
        Util.report("Error getting resources from path", ioe);
      }
    }

    2.绑定具体的日志框架

    根据找到的org/slf4j/impl/StaticLoggerBinder.class,执行StaticLoggerBinder.getSingleton()进行绑定。

    private final static void bind() {
      try {
        // the next line does the binding
        StaticLoggerBinder.getSingleton();//绑定
        INITIALIZATION_STATE = SUCCESSFUL_INITILIZATION;
        emitSubstituteLoggerWarning();
      } catch (NoClassDefFoundError ncde) {
        String msg = ncde.getMessage();
        if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
          INITIALIZATION_STATE = NOP_FALLBACK_INITILIZATION;
          Util
              .report("Failed to load class "org.slf4j.impl.StaticLoggerBinder".");
          Util.report("Defaulting to no-operation (NOP) logger implementation");
          Util.report("See " + NO_STATICLOGGERBINDER_URL
              + " for further details.");
        } else {
          failedBinding(ncde);
          throw ncde;
        }
      } catch(java.lang.NoSuchMethodError nsme) {
        String msg = nsme.getMessage();
        if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {
          INITIALIZATION_STATE = FAILED_INITILIZATION;
          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. or 2.0.x");
        }
        throw nsme;
      } catch (Exception e) {
        failedBinding(e);
        throw new IllegalStateException("Unexpected initialization failure", e);
      }
    }

    因为具体的日志框架为log4j,StaticLoggerBinder返回的为Log4j的LoggerFactory。

    private final ILoggerFactory loggerFactory;
    ​
    private StaticLoggerBinder() {
      loggerFactory = new Log4jLoggerFactory();
      try {
        Level level = Level.TRACE;
      } catch (NoSuchFieldError nsfe) {
        Util
            .report("This version of SLF4J requires log4j version 1.2.12 or later. See also http://www.slf4j.org/codes.html#log4j_version");
      }
    }
      

    经过以上步骤,slf4j将于具体的日志框架log4j绑定。

    如下所示,ILoggerFactory实际返回类型为Log4jLoggerFactory。

    并调用Log4jLoggerFactory中的getLogger方法返回Log4jLogger用于log写入。

  • 相关阅读:
    Unity热更新03-C#调用XLua-06-将Lua表 映射到C#的列表和字典
    Unity热更新03-C#调用XLua-05-C#调用Lua函数
    Unity热更新03-C#调用XLua-04-C#调用Lua全局变量
    Unity热更新03-C#调用XLua-03-LuaMgr
    Unity热更新03-C#调用XLua-02-用户自定义加载Lua脚本
    Unity热更新02-Lua基础-016-Lua垃圾回收
    Unity热更新02-Lua基础-015-Lua自带库
    Unity热更新02-Lua基础-014-Lua"面向对象"总结
    Unity热更新02-Lua基础-014-Lua初识"面向对象"
    Unity热更新02-Lua基础-013-Lua元表
  • 原文地址:https://www.cnblogs.com/yeyang/p/10417922.html
Copyright © 2011-2022 走看看