精通Log4j配置
2012年11月29日

 

一、loggerappenderlayout

 

Log4j can send your log messages to the console, a text file, an html file, an xml file, and so on.

 

日志制造者

logger: send your message strings to destinations or targets.

Log4j can log the message you send, log the date, time, message priority, Java class name, source code line number, method name, Java thread name and much more.

 

日志目标

appender: logging destinations are called "appenders".

Some common appender classes are ConsoleAppender, FileAppender, SMTPAppender.

 

指定格式

layout: An appender uses a layout to format your message before actually writing it to the log. For example, the HTMLLayout will format all your messages into a nice HTML table.

 

定义优先级

priority: Five priority constants in the Priority class are

FATAL

ERROR

WARN

INFO

DEBUG

in the order of decreasing priority.You can make more by subclassing if you want.

 

二、Configuring Log4j


The default file which configures log4j is log4j.properties. Place it anywhere in the application classpath.

指定格式

Here is an example output using PatternLayout with the conversion pattern 

"%r [%t] %-5p %c{2} %x - %m%n"

效果如下:

176 [main] INFO  examples.Sort - Populating an array of 2 elements in reverse order.

225 [main] INFO  examples.SortAlgo - Entered the sort method.

解释:

%r 代表系统启动的时间

[%t] 代表输出消息的那个线程

%-5p 代表消息的级别

%c{2} 代表截取完整类名的后两个名,例如com.zollty.Sort,截取右两位就是zollty.Sort

%x 代表the nested diagnostic context (NDC)

%m%n 代表消息内容

几种格式对比:

1.时间

%d

2012-11-04 17:19:06,428

%d{ABSOLUTE}

17:19:06,428

%r

428

%-4r

2428

时间还可以格式化为:

%d{dd MMM yyyy HH:mm:ss,SSS}

官方文档推荐用以下三种格式

"ABSOLUTE", "DATE" and "ISO8601"(default)

我推荐使用%d{ABSOLUTE},输出日志文件时按天生成文件,例如zollty.log.2012-09-03

[%t]和%x不推荐使用.

%-5p是推荐的格式,-5代表,左对齐,取5位,例如

DEBUG [main]: Message 1

WARN [main]: Message 2

虽然WARN只有4个单词,但是占5位,这样就能和DEBUG对齐。

 

%c的使用要看情况,其实本来是很好用的,但是速度比较慢。官方文档中说到:

WARNING Generating the caller class information is slow. Thus, use should be avoided unless execution speed is not an issue.

可见,在速度不是很重要的情况下,可以使用%c


再调试时,可以用以下格式

%c{1}:%L

即输出类名和行号。其实输出行号和类名意义也不大,特别是对于INFODEBUG级别的信息。

 

我推荐的格式

控制台标准格式:(生成时务必注释掉,否则影响性能)

%d{ABSOLUTE} %-5p %c{1}:%L - %m%n

日志文件标准格式:(性能优先)

%d %p - %m%n


可以把ERRORDEBUG级别的日志分开,否则在一大堆INFO中找ERROR比较难。

 

输出到文件,示例:

<appender name="DAILY" class="org.apache.log4j.DailyRollingFileAppender">
  <param name="file" value="D:/logs/StrutsGA/StrutsGA.log" />
  <param name="DatePattern" value="'.'yyyy-MM-dd" />
  <param name="threshold" value="info" />
  <param name="append" value="true" />
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%d %p - %m%n" />
  </layout>
</appender>


其中

<param name="DatePattern" value="'.'yyyy-MM-dd" />

代表:

Rollover at midnight each day.

即日志按天保存,例如/logs/cqrd.log.2012-05-08,这是默认值,不设置也是一样的。

 

另外常用的还有

'.'yyyy-MM

代表日志按月保存,适合数据量较小的日志。

 

再看

<param name="threshold" value="info"/>

其意思是忽略比info级别低的信息。官方说明如下:

All log events with lower level than the threshold level are ignored by the appender

其作用和下面的过滤器差不多:

<filter class="org.apache.log4j.varia.LevelRangeFilter">

<param name="LevelMin" value="INFO" />

<param name="LevelMax" value="FATAL" />

</filter>

只不过,过滤器可以两头控制,而threshold只能控制最低的那一端。通常来说,用threshold足够了。

 

 

输出到控制台,示例:

<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
  <param name="Target" value="System.out"/>
  <layout class="org.apache.log4j.PatternLayout">
    <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p %c{1}:%L - %m%n"/>
  </layout>
  <filter class="org.apache.log4j.varia.LevelRangeFilter">
    <param name="LevelMin" value="INFO" />
    <param name="LevelMax" value="FATAL" />
  </filter>
</appender>

其中

<param name="Target" value="System.out"/>

这个target有两个值可选System.out(默认)System.err。

System.out是默认值,不设置也是一样的。

 

 

下面来看看categorylogger的配置

dtd验证如下:

 <!ELEMENT category (param*,(priority|level)?,appender-ref*)>

<!ATTLIST category

  class         CDATA   #IMPLIED

  name  CDATA #REQUIRED

  additivity (true|false) "true"  

>

 

<!ELEMENT logger (param*,level?,appender-ref*)>

<!ATTLIST logger

  class         CDATA   #IMPLIED

  name  CDATA #REQUIRED

  additivity (true|false) "true"  

>

 

可见它们都有三个参数:classnameadditivity

其中additivity可为空,其默认值为true,代表可以多次输出。一般建议见其设置为false,这样信息就只输出一次。

 

有三个子标签:param*(priority|level)?和appender-ref*

*”代表0到多个,?代表一个,也就是说可以用0到多个paramappender-ref,而prioritylevel只能有其中一个。注意logger中只有level,不能定义priority

 

 

例如:

<logger name="org.hibernate" additivity="false">

    <level value="INFO" />

    <appender-ref ref="stdout" />

</logger>

 

categorylogger的区别:

    这个我也不太清楚,好像categorylogger的前身,logger是后面版本才推出的,其作用应该和category差不多。

 

levelpriority的区别:

   好像没区别,都是表示一个范围,输出>=设定级别的信息,老版本的category可以使用priority,但是logger中只能用level了。可见logger简化了category的使用。

 

logger、cateoryappender都可以定义优先级,那么以哪个的优先级为准呢?

 

应该是取最高级别的那个。例如,上例中的那个loggerlevelINFO,它的appender-ref指向stdout,如果这个名叫stdoutappenderthreshold设置为WARN,则就以WARN为准。

另外,appender中还可以设置filter,filter是最后一道检查的关卡。

即:日志级别检查顺序为
logger(level或者priority) -- appender(  threshold  ) -- appender(  filter  )

注意:root也是一个logger,称之为rootlogger,注意到一点,如果logger的级别不为空,那么它会覆盖rootlogger的级别。以下是源码:
  public Level getEffectiveLevel() {
    for(Category c = this; c != null; c=c.parent) {
      if(c.level != null)
    return c.level;
    }
    return null;
  }
默认new出来的logger,level都是null的,但是如下这样配置的logger,
    <logger name="org.springframework.beans.factory">
        <level value="error" />
    </logger>
那么level就不为null,故这个level的级别会覆盖rootlogger的级别。rootlogger的级别就不起作用可。

实际上,还有一个最优先的级别——Repository,log4j是最优先检查这个级别的。

所以完整的检查级别是:

(注意logger和category等价,level和priority等价,不再单独说明)
([]的内容代表“可选”)
Repository(threshold)--[ logger(level) ] -- rootlogger
 -- appender(  threshold  ) -- appender(  filter  )


但是注意logger的范围只是定义在一个包中有用,而appender的定义是全局的。

总结:Log4j日志级别设置-各种设置的优先级

1、利用threshold或者filter设置,这种级别是最高的。而且以后用任何其他方式动态设置都不会再起作用。例如,在配置文件中配置了级别为ERROR,然后在程序中动态的修改某个logger的级别为INFO:logger.setLevel(Level.INFO); 这样是不会其作用的。

2、在配置root的时候用priority设置的级别,这种级别是最低的。会被其他方式设置的级别覆盖。

3、程序中使用logger.setLevel动态设置的级别,会覆盖配置文件中的priority的设置,但是不会覆盖threshold或者filter设置。如果设置了threshold或者filter设置,最终还是以它们的设置为准。