文档章节

深入log4j源码

javahongxi
 javahongxi
发布于 2017/08/26 06:28
字数 1413
阅读 9
收藏 0

 

 slf4j即Simple logging facade for Java,其作用类似于JDBC,作为一个日志抽象层,它允许你在后台使用任意一个日志类库,比如log4j。如果是在编写供内外部都可以使用的API或者通用类库,那么你真不会希望使用你类库的客户端必须使用你选择的日志类库。常用的日志类库有log4j、logback等,本文就来深入了解一下log4j。

 开发代码中,我们只需要在src下放上log4j.xml或log4j.properties,log4j就能自动找到该配置文件,web工程在spring环境下,我们还可以在web.xml中自定义上述配置文件的路径。

 

<context-param>   
      <param-name>log4jConfigLocation</param-name>   
      <param-value>WEB-INF/log4j.properties</param-value>   
  </context-param>   
  
  <context-param>   
      <param-name>log4jRefreshInterval</param-name>   
      <param-value>6000</param-value>   
  </context-param>   
  
  <listener>   
      <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>   
  </listener>

 那么log4j默认是怎么加载配置文件的呢?每一个Logger实例在log里是怎么安排存放的呢?

 

 Log4j由三个重要的组成构成:日志记录器(Loggers),输出端(Appenders)和日志格式化器(Layout)。
1.日志记录器(Loggers):控制要输出哪些日志记录语句,对日志信息进行级别限制。
2.输出端(Appenders):指定了日志将打印到控制台还是文件中。

3.日志格式化器(Layout):控制日志信息的显示格式。

 log4j初始化

从架构上我们可以看出logger的实现是从logManager来具体完成的,因此初始化在logManager的static块中,如下:

 

static {
    // By default we use a DefaultRepositorySelector which always returns 'h'.
    Hierarchy h = new Hierarchy(new RootLogger(Level.DEBUG));
    repositorySelector = new DefaultRepositorySelector(h);

    /** Search for the properties file log4j.properties in the CLASSPATH.  */
    String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
                               null);

    // if there is no default init override, then get the resource
    // specified by the user or the default config file.
    if(override == null || "false".equalsIgnoreCase(override)) {

      String configurationOptionStr = OptionConverter.getSystemProperty(
                              DEFAULT_CONFIGURATION_KEY, 
                              null);

      String configuratorClassName = OptionConverter.getSystemProperty(
                                                   CONFIGURATOR_CLASS_KEY, 
                           null);

      URL url = null;

      // if the user has not specified the log4j.configuration
      // property, we search first for the file "log4j.xml" and then
      // "log4j.properties"
      if(configurationOptionStr == null) {    
    url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
    if(url == null) {
      url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
    }
      } else {
    try {
      url = new URL(configurationOptionStr);
    } catch (MalformedURLException ex) {
      // so, resource is not a URL:
      // attempt to get the resource from the class path
      url = Loader.getResource(configurationOptionStr); 
    }    
      }
      
      // If we have a non-null url, then delegate the rest of the
      // configuration to the OptionConverter.selectAndConfigure
      // method.
      if(url != null) {
        LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
        try {
            OptionConverter.selectAndConfigure(url, configuratorClassName,
                       LogManager.getLoggerRepository());
        } catch (NoClassDefFoundError e) {
            LogLog.warn("Error during default initialization", e);
        }
      } else {
        LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
      }
    } else {
        LogLog.debug("Default initialization of overridden by " + 
            DEFAULT_INIT_OVERRIDE_KEY + "property."); 
    }  
  }

 让我们深入进去看看是怎么初始化的?

 

第一步:创建一个默认的RepositorySelector,RepositorySelector在logManager中使用,它的实现类对特定的应用上下文提供了一个LoggerRespository。LoggerRespository的实现类负责追踪应用上下文。ResponsitorySelector提供了一个方法:

public LoggerRepository getLoggerRepository();

LoggerRepository从字面上理解,它是一个Logger的容器,它会创建并缓存Logger实例,从而具有相同名字的Logger实例不会多次创建,以提高性能。它的这种特性有点类似Spring的IOC概念。Log4J支持两种配置文件:properties文件和xml文件。Configurator解析配置文件,并将解析后的信息添加到LoggerRepository中。LogManager最终将LoggerRepository和Configurator整合在一起。

LoggerRepository同时它也维护了Logger之间的关系,因为在Log4J中,所有Logger都组装成以RootLogger为根的一棵树,树的层次由Logger的Name来决定,其中以’.’分隔。

除了作为一个Logger容器,它还有一个Threshold属性,用于过滤所有在Threshold级别以下的日志。以及其他和Logger操作相关的方法和属性。

 

public interface LoggerRepository {
public void addHierarchyEventListener(HierarchyEventListener listener);
 boolean isDisabled(int level);
 public void setThreshold(Level level);
 public void setThreshold(String val);
public void emitNoAppenderWarning(Category cat);
 public Level getThreshold();
 public Logger getLogger(String name);
public Logger getLogger(String name, LoggerFactory factory);
 public Logger getRootLogger();
public abstract Logger exists(String name);
public abstract void shutdown();
public Enumeration getCurrentLoggers();
 public abstract void fireAddAppenderEvent(Category logger, Appender appender);
 public abstract void resetConfiguration();
}

 Hierarchy类

 

Hierarchy是Log4J中默认对LoggerRepository的实现类,它用于表达其内部的Logger是以层次结构存储的。在对LoggerRepository接口的实现中,getLogger()方法是其最核心的实现,因而首先从这个方法开始。Hierarchy中用一个Hashtable来存储所有Logger实例,它以CategoryKey作为key,Logger作为value,其中CategoryKey是对Logger中Name字符串的封装,之所以要引入这个类是出于性能考虑,因为它会缓存Name字符串的hash code,这样在查找过程中计算hash code时就可以直接取得而不用每次都计算。

第二步:从classpath路径查找log4j.properties属性配置文件。

   1. 判断配置文件有没有重写?

 

/** Search for the properties file log4j.properties in the CLASSPATH.  */
    String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,null); 
//public static final String DEFAULT_INIT_OVERRIDE_KEY = "log4j.defaultInitOverride";

 

publicstatic String getSystemProperty(String key, String def) {
    try {
      return System.getProperty(key, def);
    } catch(Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx
      LogLog.debug("Was not allowed to read system property \""+key+"\".");
      return def;
    }
  }

 2. override为null或者为false时没有重写,然后从系统属性中查找key:log4j.configuration和log4j.configuratorClass属性。如果没有设置log4j.configuration属性,就查找log4j.xml,然后查找log4j.properties文件。使用方法:

 

 

if(configurationOptionStr == null) {    
    url = Loader.getResource(DEFAULT_XML_CONFIGURATION_FILE);
    if(url == null) {
      url = Loader.getResource(DEFAULT_CONFIGURATION_FILE);
    }

 使用java2的线程上下文类加载器来查找资源,如果查找失败,则使用加载该类(loader)的类加载器来加载资源。

 

3.如果设置了log4j.configuration属性,则使用url形式读取,如果资源不是url,则从classpath获取资源:

 

try {
      url = new URL(configurationOptionStr);
    } catch (MalformedURLException ex) {
      // so, resource is not a URL:
      // attempt to get the resource from the class path
      url = Loader.getResource(configurationOptionStr); 
    }

 4. 如果log4j.configuration属性为url形式:

 

// If we have a non-null url, then delegate the rest of the
      // configuration to the OptionConverter.selectAndConfigure
      // method.
      if(url != null) {
        LogLog.debug("Using URL ["+url+"] for automatic log4j configuration.");
        try {
            OptionConverter.selectAndConfigure(url, configuratorClassName,
                       LogManager.getLoggerRepository());
        } catch (NoClassDefFoundError e) {
            LogLog.warn("Error during default initialization", e);
        }
      } else {
        LogLog.debug("Could not find resource: ["+configurationOptionStr+"].");
      }

 

参考文献:

1. http://www.2cto.com/kf/201207/139798.html  - 深入Log4j源码之LoggerRepository和Configurator

2. http://logging.apache.org/log4j/1.2/manual.html

3. whatsmars.com

© 著作权归作者所有

javahongxi
粉丝 168
博文 259
码字总数 779422
作品 0
朝阳
程序员
私信 提问
Apache LOG4J 2.11.0-rc1 发布,Java 日志组件

Apache LOG4J 2.11.0 的首个 RC 版已发布,下面来看看 2.11.0 的更新日志: 新模块 log4j-cvs Group ID: Artifact ID: Old package: New package: log4j-jdbc Group ID: Artifact ID: Old p......

淡漠悠然
2018/03/12
770
4
Log4j for C++ 实用指南

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011012932/article/details/80796813 课程介绍 日志是一个优秀系统不可或缺的组成部分,利用它我们可以记录系...

一去丶二三里
2018/06/25
0
0
Spring3 MyBatis3 日志配置

//org.apache.ibatis.logging.LogFactory; static { } 查看Mybatis源码发现,他日志框架的寻找顺序:slf4j-->commons logging-->log4j 不能直接引入log4j jar包,因为即使我不导入slf4j的包,...

xingda
2012/04/17
3.6K
0
jdk-logging、log4j、logback日志介绍及原理

系列文章已完成,目录如下: - jdk-logging、log4j、logback日志介绍及原理- commons-logging与jdk-logging、log4j1、log4j2、logback的集成原理- slf4j与jdk-logging、log4j1、log4j2、log...

乒乓狂魔
2015/04/27
14.5K
17
java web项目使用log4j的使用笔记

新建一个JAVA WEB 项目,就是一个动态网站。 例名字为sms (一)去http://logging.apache.org/log4j/1.2/下载log4j版本。 把log4j-1.2.17.jar放到WEB-INF/lib目录下 (二)java源码目录下的s...

独钓渔
2015/10/26
360
0

没有更多内容

加载失败,请刷新页面

加载更多

Activity启动模式二

上篇文章Activity启动模式一主要介绍了Activity的四种启动模式,这些启动模式都是在AndroidManifest中进行配置的。除此之外,Android系统还通过Intent类提供了一些标志位,同样可以指定Activ...

ltlovezh
22分钟前
4
0
三原色还原

1、Color Filter Array — CFA 随着数码相机、手机的普及,CCD/CMOS 图像传感器近年来得到广泛的关注和应用。 图像传感器一般都采用一定的模式来采集图像数据,常用的有 BGR 模式和 CFA 模式...

天王盖地虎626
33分钟前
3
0
kubernetes pod exec接口调用

正文 一般生产环境上由于网络安全策略,大多数端口是不能为集群外部访问的。多个集群之间一般都是通过k8s的ApiServer组件提供的接口通信,如https://192.168.1.101:6443。所以在做云平台时,...

码农实战
今天
8
0
3_数组

3_数组

行者终成事
今天
8
0
经典系统设计面试题解析:如何设计TinyURL(二)

原文链接:https://www.educative.io/courses/grokking-the-system-design-interview/m2ygV4E81AR 编者注:本文以一道经典的系统设计面试题:《如何设计TinyURL》的参考答案和解析为例,帮助...

APEMESH
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部