ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

slf4j日志框架绑定机制

2019-02-22 13:48:08  阅读:353  来源: 互联网

标签:StaticLoggerBinder 绑定 Util slf4j report org 日志 log4j


一、环境搭建

我们以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\t%d{ISO8601}\t%r\t%c\t[%t]\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写入。

 

标签:StaticLoggerBinder,绑定,Util,slf4j,report,org,日志,log4j
来源: https://www.cnblogs.com/yeyang/p/10417922.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有