Log4j 2的好处就不和大家说了,如果你搜了2,说明你对他已经有一定的了解,并且想用它,所以这里直接就上手了。
1. 去官方
)
我们这里看到了配置文件里面是name很重要,没错,这个name可不能随便起(其实可以随便起)。这个机制意思很简单。就是类似于java package一样,比如我们的一个包:cn.lsw.base.log4j2。而且,可以发现我们前面生成Logger对象的时候,命名都是通过 Hello.class.getName(); 这样的方法,为什么要这样呢? 很简单,因为有所谓的Logger 继承的问题。比如 如果你给cn.lsw.base定义了一个logger,那么他也适用于cn.lsw.base.lgo4j2这个logger。名称的继承是通过点(.)分隔的。然后你可以猜测上面loggers里面有一个子节点不是logger而是root,而且这个root没有name属性。这个root相当于根节点。你所有的logger都适用与这个logger,所以,即使你在很多类里面通过 类名.class.getName() 得到很多的logger,而且没有在配置文件的loggers下面做配置,他们也都能够输出,因为他们都继承了root的log配置。
我们上面的这个配置文件里面还定义了一个logger,他的名称是 cn.lsw.base.log4j2.Hello ,这个名称其实就是通过前面的Hello.class.getName(); 得到的,我们为了给他单独做配置,这里就生成对于这个类的logger,上面的配置基本的意思是只有cn.lsw.base.log4j2.Hello 这个logger输出trace信息,也就是他的日志级别是trace,其他的logger则继承root的日志配置,日志级别是error,只能打印出ERROR及以上级别的日志。如果这里logger 的name属性改成cn.lsw.base,则这个包下面的所有logger都会继承这个log配置(这里的包是log4j的logger name的“包”的含义,不是java的包,你非要给Hello生成一个名称为“myhello”的logger,他也就没法继承cn.lsw.base这个配置了。
那有人就要问了,他不是也应该继承了root的配置了么,那么会不会输出两遍呢?我们在配置文件中给了解释,如果你设置了additivity="false",就不会输出两遍,否则,看下面的输出:
这里要在加入一个类做对比:
复制代码
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Test {
private static Logger logger = LogManager.getLogger(Test.class.getName());
public static void main(String[] args) {
logger.trace("开始程序.");
Hello hello= new Hello();
// for (int i = 0; i < 10000;i++){
if (!hello.hello()) {
logger.error("hello");
}
// }
logger.trace("退出程序.");
}
}
复制代码
这里先把配置文件改一下方便对照,一个是刚才第一个logger的名称还是cn.lsw.base.log4j2.Hello,additivity去掉或改为true(因为默认是true,所以可以去掉),第二是把root的level改为info方便观察。
然后运行Test,看控制台的日志输出:
复制代码
2013-12-20 19:59:42.538 [main] INFO cn.lsw.base.log4j2.Test - test
2013-12-20 19:59:42.541 [main] TRACE cn.lsw.base.log4j2.Hello - entry
2013-12-20 19:59:42.541 [main] TRACE cn.lsw.base.log4j2.Hello - entry
2013-12-20 19:59:42.542 [main] ERROR cn.lsw.base.log4j2.Hello - Did it again!
2013-12-20 19:59:42.542 [main] ERROR cn.lsw.base.log4j2.Hello - Did it again!
2013-12-20 19:59:42.542 [main] INFO cn.lsw.base.log4j2.Hello - 我是info信息
2013-12-20 19:59:42.542 [main] INFO cn.lsw.base.log4j2.Hello - 我是info信息
2013-12-20 19:59:42.542 [main] DEBUG cn.lsw.base.log4j2.Hello - 我是debug信息
2013-12-20 19:59:42.542 [main] DEBUG cn.lsw.base.log4j2.Hello - 我是debug信息
2013-12-20 19:59:42.542 [main] WARN cn.lsw.base.log4j2.Hello - 我是warn信息
2013-12-20 19:59:42.542 [main] WARN cn.lsw.base.log4j2.Hello - 我是warn信息
2013-12-20 19:59:42.542 [main] FATAL cn.lsw.base.log4j2.Hello - 我是fatal信息
2013-12-20 19:59:42.542 [main] FATAL cn.lsw.base.log4j2.Hello - 我是fatal信息
2013-12-20 19:59:42.542 [main] DEBUG cn.lsw.base.log4j2.Hello - 我是debug信息
2013-12-20 19:59:42.542 [main] DEBUG cn.lsw.base.log4j2.Hello - 我是debug信息
2013-12-20 19:59:42.543 [main] TRACE cn.lsw.base.log4j2.Hello - exit
2013-12-20 19:59:42.543 [main] TRACE cn.lsw.base.log4j2.Hello - exit
2013-12-20 19:59:42.543 [main] ERROR cn.lsw.base.log4j2.Test - hello
复制代码
可以看出,Test的trace日志没有输出,因为他继承了root的日志配置,只输出info即以上级别的日志。Hello 输出了trace及以上级别的日志,但是每个都输出了两遍。你可以试一下,把第一个logger的level该为error,那么error以上的级别也是输出两遍。这时候,只要加上additivity为false就可以避免这个问题了。
当然,你可以为每个logger 都在配置文件下面做不同的配置,也可以通过继承机制,对不同包下面的日志做不同的配置。因为loggers下面可以写很多歌logger。
下面在看一个稍微复杂的例子:
复制代码
filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
复制代码
说复杂,其实也不复杂,这一个例子主要是为了讲一下appenders。
这里定义了三个appender,Console,File,RollingFile,看意思基本也明白,第二个是写入文件,第三个是“循环”的日志文件,意思是日志文件大于阀值的时候,就开始写一个新的日志文件。
这里我们的配置文件里面的注释算比较详细的了。所以就大家自己看了。有一个比较有意思的是ThresholdFilter ,一个过滤器,其实每个appender可以定义很多个filter,这个功能很有用。如果你要选择控制台只能输出ERROR以上的类别,你就用ThresholdFilter,把level设置成ERROR,onMatch="ACCEPT" onMismatch="DENY" 的意思是匹配就接受,否则直接拒绝,当然有其他选择了,比如交给其他的过滤器去处理了之类的,详情大家自己去琢磨吧。
为什么要加一个这样的配置文件呢?其实这个配置文件我感觉挺好的,他的实用性就在下面:
8. 一个实用的配置文件:
我们用日志一方面是为了记录程序运行的信息,在出错的时候排查之类的,有时候调试的时候也喜欢用日志。所以,日志如果记录的很乱的话,看起来也不方便。所以我可能有下面一些需求:
1)我正在调试某个类,所以,我不想让其他的类或者包的日志输出,否则会很多内容,所以,你可以修改上面root的级别为最高(或者谨慎起见就用ERROR),然后,加一个针对该类的logger配置,比如第一个配置文件中的设置,把他的level设置trace或者debug之类的,然后我们给一个appender-ref是定义的File那个appender(共三个appender,还记得吗),这个appender的好处是有一个append为false的属性,这样,每次运行都会清空上次的日志,这样就不会因为一直在调试而增加这个文件的内容,查起来也方便,这个和输出到控制台就一个效果了。
2)我已经基本上部署好程序了,然后我要长时间运行了。我需要记录下面几种日志,第一,控制台输出所有的error级别以上的信息。第二,我要有一个文件输出是所有的debug或者info以上的信息,类似做程序记录什么的。第三,我要单独为ERROR以上的信息输出到单独的文件,如果出了错,只查这个配置文件就好了,不会去处理太多的日志,看起来头都大了。怎么做呢,很简单。
>首先,在appenders下面加一个Console类型的appender,通过加一个ThresholdFilter设置level为error。(直接在配置文件的Console这个appender中修改)
>其次,增加一个File类型的appender(也可以是RollingFile或者其他文件输出类型),然后通过设置ThresholdFilter的level为error,设置成File好在,你的error日志应该不会那么多,不需要有多个error级别日志文件的存在,否则你的程序基本上可以重写了。
这里可以添加一个appender,内容如下:
并在loggers中的某个logger(如root)中引用(root节点加入这一行作为子节点)。