log4j是阿帕奇日志服务(Apache Logging Services)旗下的一款强大的开源日志输出工具。log4j使用上简洁便利,高效且拓展性强,几乎是Java编程的必备依赖包。除Java专用的log4j,阿帕奇日志服务网站还有log4net、log4php等其他编程语言对应的包。
项目使用log4j作为日志组件,出于细分日志的需求,要对配置文件做较大变动。之前对一些概念理解不是很到位,趁此机会抽空回顾官方的教程,收获不少。因项目使用的1.2系列的jar包,本文整理自1.2版本的官方文档。
重要概念
先回顾log4j中的三个重要概念:logger、appender和layout。三者合力决定日志是否应该输出、输出到哪里、输出格式是什么。
Logger
logger是输出日志的对象实例。除根logger外,其余均是命名logger,通常以调用的类名为其名字。名字中的点(.)是log4j划分层级的依据(与包package的组织方式相同),例如名字为com.tlanyan
的logger是com.tlanyan.service
的logger的父级。
根logger是logger中的特殊存在,原因有三:
- 它总是存在,无需手动创建;
- 它的输出等级不能为空(null);
- 不能通过名字获取其引用,只能通过
Logger.getRootLogger
获取。
信息分为六种等级:trace、debug、info、warn、error和fatal,分别对应Logger类的六个打印方法。等级之间有大小关系,trace等级最低,fatal最高。
理解logger的层级和继承是正确使用log4j的关键,即log4j不能确定某个值时,默认会向上回溯直到找到根logger。例如根logger的appender默认总是被子logger继承,会导致子logger中的信息多次输出,冗余又低效;子级的level继承自父级,低于父级的信息会被无意间过滤,等等。
Appender
appender是日志输出的目的地,每个appender是实现了Appender
接口的类具现化实例。常用的appender类有:
- FileAppender及其子类:将日志输出到文件中;
- ConsoleAppender,将日志输出到标准输出;
- JDBCAppender,将日志保存到数据库。
除了配置常规属性值,appender中一个重要的特性是过滤器(filter)。过滤器对到达appender的信息做进一步过滤,最终确定是否输出。常用的过滤器有LevelRangeFilter
和StringMatchFilter
。
Layout
layout(布局)隶属于appender,对信息进行输出前的格式化。例如增加打印时间,调用的文件名、线程等,或者按照xml格式输出日志。最常用的布局是PatternLayout
,可配置的成员变量是ConversionPattern
,格式与C语言中的printf函数相同,具体含义请参考官方文档。
配置
配置log4j的方式主要有三种:1. 通过程序代码;2. 键值对形式的properties配置文件;3. xml配置文件。后两者简单易懂,且支持修改文件后配置即时生效,建议采用。
layout在appender中配置,所以配置文件主要由两部分组成:logger和appender。xml文件格式良好,层级关系更明显,相对properties文件本人更偏爱xml格式。下面是log4j的一个简单xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="INFO" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="./logs/app-info.log"/>
<param name="Append" value="true"/>
<param name="MaxFileSize" value="50MB"/>
<param name="MaxBackupIndex" value="10"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%-5r][%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l %m%n"/>
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="INFO"/>
<param name="LevelMax" value="INFO"/>
</filter>
</appender>
<appender name="pay" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="./logs/pay-data.log"/>
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%-5r][%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l %m%n"/>
</layout>
</appender>
<appender name="ERROR" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="./logs/app-error.log"/>
<param name="Append" value="true"/>
<param name="MaxFileSize" value="50MB" />
<param name="MaxBackupIndex" value="20" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%-5r][%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l %m%n"/>
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="WARN"/>
<param name="LevelMax" value="ERROR"/>
</filter>
</appender>
<logger name="com.tlanyan.pay" additivity="false">
<level value="info"/>
<appender-ref ref="pay"/>
</logger>
<root>
<level value="info"/>
<appender-ref ref="INFO"/>
<appender-ref ref="ERROR"/>
</root>
</log4j:configuration>
配置文件定义了三个appender,两个logger。注意根logger没有名字,要用root来引用。名字为pay的logger不继承父级(additivity="false"
),所以其中的信息不会输出到app-info.log中。
建议在程序入口配置log4j并监听配置文件:
DOMConfigurator.configureAndWatch("config/log4j.xml", 10000L);
通过监听文件变化,可实现配置在修改后即时生效,无需改动代码,也无需重启程序。
发表回复