从源码角度深入分析log4j配置文件使用

log4j在日常开发中经常使用,但有时候对 配置文件应该放到什么位置有疑惑。现在我们通过从代码的角度来看待这个问题,

看完后你也许会恍然大悟哦。

开始吧。

Log4j的组成及架构:

  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的容器,它负责创建、缓存Logger实例,同时它也维护了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+"].");
      }

小结:

The exact default initialization algorithm is defined as follows:

  1. Setting the log4j.defaultInitOverride system property to any other value then "false" will cause log4j to skip the default initialization procedure (this procedure).
  2. Set the resource string variable to the value of the log4j.configuration system property. The preferred way to specify the default initialization file is through the log4j.configuration system property. In case the system property log4j.configuration is not defined, then set the string variable resourceto its default value "log4j.properties".
  3. Attempt to convert the resource variable to a URL.
  4. If the resource variable cannot be converted to a URL, for example due to a MalformedURLException, then search for the resource from the classpath by calling org.apache.log4j.helpers.Loader.getResource(resource, Logger.class) which returns a URL. Note that the string "log4j.properties" constitutes a malformed URL.

    See Loader.getResource(java.lang.String) for the list of searched locations.

  5. If no URL could not be found, abort default initialization. Otherwise, configure log4j from the URL.

    The PropertyConfigurator will be used to parse the URL to configure log4j unless the URL ends with the ".xml" extension, in which case the DOMConfiguratorwill be used. You can optionaly specify a custom configurator. The value of the log4j.configuratorClass system property is taken as the fully qualified class name of your custom configurator. The custom configurator you specify must implement the Configurator interface.

 

 

参考文献:

1. http://www.2cto.com/kf/201207/139798.html

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

 

转载于:https://www.cnblogs.com/davidwang456/p/4243161.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
“我的钱花到哪里去了?”   让Money Logger来帮你解答这个难题吧!使用Money Logger,您可以随时随地快捷地记录下每项花费和收入。Money Logger提供全面的收支分析功能,助你轻松掌握自己的资金动向。 “我已经在用记账理财软件了!”   使用传统的记账理财软件,您必须在一天繁忙之余,抽时间坐在电脑前面,通过回想将已经发生过的收支情况记录下来。这是一件挺痛苦的事情吧!花费时间不说,如果不够毅力或者记性不太好,还常常会漏记了不少收支情况。   还有一些理财软件可以运行在手机和PDA里,您可以用它随时随地记录收支情况,免去了回想收支情况的痛苦。但这些软件功能又太过简单,而且还有各种各样的限制,比如说支持的手机型号有限、存储的数据有限、操作很不方便...   还是试试Money Logger吧!   Money Logger提供了一种新的记账理财服务。Money Logger包括两个部分,手机软件和网站服务。您可以下载适合您机型的手机记账软件,随时随地记录收支情况,然后定期成批上传到网站上。网站上提供了全面的收支管理和统计分析功能,让您轻松了解自己的收支情况。   您可以使用电脑访问www.moneylogger.com使用网站服务,也可以使用手机浏览器访问moneylogger.com或 www.moneylogger.com使用网站服务。若您的手机不支持XHTML,请访问wap.moneylogger.com “Money Logger的服务收费吗?”   Money Logger服务完全免费!您可以免费下载、运行手机记账软件,免费在本网站注册帐号,免费使用网站提供的各项功能!还等什么,赶快来注册吧!   注:当您用手机上传收支记录时,移动运营商(如中国移动、中国联通)会对产生的数据流量收取基本通信费。该费用由移动运营商收取,Money Logger不另外加收任何费用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值