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写入。

  • 相关阅读:
    June. 26th 2018, Week 26th. Tuesday
    June. 25th 2018, Week 26th. Monday
    June. 24th 2018, Week 26th. Sunday
    June. 23rd 2018, Week 25th. Saturday
    June. 22 2018, Week 25th. Friday
    June. 21 2018, Week 25th. Thursday
    June. 20 2018, Week 25th. Wednesday
    【2018.10.11 C与C++基础】C Preprocessor的功能及缺陷(草稿)
    June.19 2018, Week 25th Tuesday
    June 18. 2018, Week 25th. Monday
  • 原文地址:https://www.cnblogs.com/yeyang/p/10417922.html
Copyright © 2011-2022 走看看