我的目标是授人以渔,而不是授人以鱼,我相信你仔细看完这篇文章,玩转log4j不成问题
先来一个log4j最简单的例子
public class MyApp {
static Logger logger = Logger.getLogger(MyApp.class.getName());
public static void main(String[] args) {
logger.info("Entering application.");
Bar bar = new Bar();
bar.doIt();
logger.info("Exiting application.");
}
}
public class Bar {
static Logger logger = Logger.getLogger(Bar.class);
public void doIt() {
logger.debug("Did it again!");
}
}
在类路径(src目录下)创建log4j的配置文件log4j.properties,里面的内容
log4j.rootLogger=DEBUG, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.SimpleLayout
运行一下,你会看到控制台有输出,这就是一个最简单的log4j配置的例子
来解释一下这3行配置
第一行:设置了根记录器,值的格式为: 日志级别, appender1, appender2...
log4j从低到高有这么几个日志级别 DEBUG < INFO < WARN < ERROR < FATAL. 配置成DEBUG就会把所有级别的日志都打印出来,反之配置成FATAL就只会打印FATAL级别的日志
appender1, appender2就是第二行配置的
第二行:表示输出到控制台,那除了ConsoleAppender就没有别的Appender了么,答案当然是有的,如图
只要实现了Appender接口的都可以,所以可以看到第一行里面的A1是在第二行定义的一个ConsoleAppender
第三行:log4j.appender.stdout一直到这里都知道,这就是第二行的appender,那么后面为什么要接一个layout呢?
里面是不是有一个属性还是什么呢?我们打开搜索一下,如图
可以看到里面有一个继承自AppenderSkeleton的layout属性,那么A1后面接的layout就是这个layout属性么?
从第三行看到赋了一个SimpleLayout给layout,看起来一切合理,但是我想说的是第三行里面的layout不是这个layout属性,而是继承自AppenderSkeleton里面的setLayout方法的layout,我曾经在配置spring的时候也思考过这样的问题,后来证明spring配置里面的属性配置是setXxx方法的Xxx,所以我99%的肯定这里的layout是setLayout的layout,要想验证也简单,自己把ConsoleAppender到AppenderSkeleton所经过的类(并不是直接继承)复制下来,然后把setLayout方法改一个名字,比如setLayout1,然后再用你自己的类配置,就知道这里的layout到底还是layout1了,也就是到底是属性还是setter方法里面的,我没有测试,如果有哪位同学测试得到了和我说的不一样的结果,欢迎告诉我。
ConsoleAppender的setLayout是继承自AppenderSkeleton的,而AppenderSkeleton是重写的Appender接口里面的setLayout方法,也就是所有的appender都需要配置layout
所有的appender都继承自AppenderSkeleton,来看一下这个类里面有哪些setter方法
可以看到有一个setThreshold方法,这个是配置日志级别的,也就是说每个appender都可以配置自己的日志级别,而不必使用统一的日志级别
基于我的这个结果,也就是说只要类里面有setter方法,都可以注入值,我们发现ConsoleAppender里面有一个setTarget(String value)
所以这个target也是可以配置的,像这样
log4j.appender.A1.target=System.out
填什么值还是要看一下api,从api可以看出,target有2个值,分别是System.out和System.err,默认是System.out
target表示输出的目标,System.err只输出错误信息,System.out输出所有信息
如果第三行配置成下面的
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
表示可以自定义的灵活布局,里面有一个setConversionPattern方法,传入转换模式就可以得到自定义的输出布局,可以看到setConversionPattern这个方法是PatternLayout独有的,其他的layout没有的,这是因为其他的layout的布局是固定的
如第三行的SimpleLayout表示简单布局,仅打印日志级别和日志信息,如DEBUG - Hello world
而PatternLayout的布局是需要自己定义的,所以需要加上一行转换默认的配置,比如可以这样配置
log4j.appender.A1.Layout.conversionPattern=%d{ABSOLUTE} %-4p [%t] %c{5} - %m%n
这一行表示什么意思呢?我们来看一下,可以看一下官方的说明
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html
不懂的自行有道翻译,还是翻译的不错的,至少我是翻译的,哈哈哈。。。
我取一些讲一下,每个转换字符都要用%开头,而且是区分大小写的,不要弄错了
%c 类的全路径,可以加参数使用,如果类路径是a.b.c.Test,那么%c{2}得到的结果是c.Test,表示只保留后面的2项
%C 和%c的作用是一样的,而且性能较差,所以我不知道为什么还要弄这个出来
%d 格式化时间,可以这样用%d{HH:mm:ss,SSS} or %d{dd MMM yyyy HH:mm:ss,SSS},这样是最终调用了SimpleDateFormat,
这样性能不好,所以应该这样用%d{ISO8601} or %d{ABSOLUTE} or %d{DATE},这3种出来的格式分别是
%d{ISO8601}: 2018-03-26 17:18:38,207
%d{ABSOLUTE}: 17:19:06,630
%d{DATE}: 26 三月 2018 17:13:12,056
%F 发出日志请求的文件名, 不推荐使用
%l 位置信息,不推荐使用
%m 日志信息
%n 换行
%p 日志级别
%r 从布局构建到日志记录事件创建的毫秒数
%t 线程
%x 用于输出与生成日志事件的线程关联的NDC(嵌套诊断上下文)
%% 输出一个%
敲黑板,敲黑板。重要的来了
在%和转换字符之间还可以配置对齐方式、最小字符宽度和最大字符宽度
默认右对齐,负号-表示左对齐
数字指定最小字符宽度,如果小于最小字符宽度则依据对齐规则在左边或右边添加空格
. 数字(点号接数字)表示最大字符宽度,如果大于最大字符宽度,则保留后面的最大字符宽度的字符
看几个例子
%20c 右对齐最小宽度20的类路径
%-20c 左对齐最小宽度20的类路径
%.30c 最大宽度为30的类路径,因为总是没有多余的空间,所以没有对齐方式,表现出来的对齐方式是左对齐
%20.30c 右对齐最小宽度为20,最大宽度为30的类路径
%-20.30c 左对齐最小宽度为20,最大宽度为30的类路径
现在知道上面例子中%-4p的意思了:左对齐最小宽度为4的日志级别
如果想让特定的包下的类或特定的类输出指定级别的日志,可以像这样配置
log4j.logger.com.foo=WARN
说明:log4j.logger.是固定的
com.foo是你要指定日志级别的包或类,这样com.foo包下的所有类(或com.foo类)的日志级别就是WARN,其他包或类不受影响
来看一下其他常用的Appener
DailyRollingFileAppender(日常翻滚文件Appender):以时间来翻滚的appender
就把里面的一个setDatePattern方法讲一下,其他的setter方法就不说了,可以直接配置的
DailyRollingFileAppender默认是每天创建一个新的日志文件,通过setDatePattern方法可以设置为每个月,每个星期,每个小时设置每分钟创建一个新的日志文件
RollingFileAppender(翻滚文件appender):以日志文件大小来翻滚
默认翻滚大小是10M,翻滚个数是1个,这都是可以通过里面里面的setter方法来设置的,就不再多说了
最后给一个2个appender的配置文件示例
log4j.rootLogger=DEBUG, A1, A2
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.SimpleLayout
log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A2.datePattern=‘.‘yyyy-MM-dd HH-mm
log4j.appender.A2.file=test.log
log4j.appender.A2.encoding=utf-8
#log4j.appender.A2.append=true
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.conversionPattern=%r [%t] %-5p (%.30c) [%x] - %m%n