log4j使⽤教程详解(怎么使⽤log4j2)
1. 去官⽅下载log4j 2,导⼊jar包,基本上你只需要导⼊下⾯两个jar包就可以了(xx是乱七⼋糟的版本号):
log4j-core-xx.jar
log4j-api-xx.jar
2. 导⼊到你的项⽬中:这个就不说了。
3. 开始使⽤:
我们知道,要在某个类中使⽤log4j记录⽇志,只需要申明下⾯的成员变量(其实不⼀定要是成员变量,只是为了⽅便调⽤⽽已)
复制代码代码如下:
private static Logger logger = Logger(Name());
⾥getLogger有⼀个参数指定的是这个logger的名称,这个名称在配置⽂件⾥⾯可是有需要的,这个待会⼉再说。
声明了Logger对象,我们就可以在代码中使⽤他了。
4. ⽇志的级别:
我们现在要调⽤logger的⽅法,不过在这个Logger对象中,有很多⽅法,所以要先了解log4j的⽇志级别,log4j规定了默认的⼏个级别:trace<debug<info<warn<error<fatal等。这⾥要说明⼀下:
1)级别之间是包含的关系,意思是如果你设置⽇志级别是trace,则⼤于等于这个级别的⽇志都会输出。
2)基本上默认的级别没多⼤区别,就是⼀个默认的设定。你可以通过它的API⾃⼰定义级别。你也可以随意调⽤这些⽅法,不过你要在配置⽂件⾥⾯好好处理了,否则就起不到⽇志的作⽤了,⽽且也不易读,相当于⼀个规范,你要完全定义⼀套也可以,不⽤没多⼤必要。
3)这不同的级别的含义⼤家都很容易理解,这⾥就简单介绍⼀下:
trace:是追踪,就是程序推进以下,你就可以写个trace输出,所以trace应该会特别多,不过没关系,我们可以设置最低⽇志级别不让他输出。
debug:调试么,我⼀般就只⽤这个作为最低级别,trace压根不⽤。是在没办法就⽤eclipse或者idea的debug功能就好了么。
info:输出⼀下你感兴趣的或者重要的信息,这个⽤的最多了。
warn:有些信息不是错误信息,但是也要给程序员的⼀些提⽰,类似于eclipse中代码的验证不是有error 和warn(不算错误但是也请注意,⽐如以下depressed的⽅法)。
error:错误信息。⽤的也⽐较多。
fatal:级别⽐较⾼了。重⼤错误,这种级别你可以直接停⽌程序了,是不应该出现的错误么!不⽤那么紧张,其实就是⼀个程度的问题。
5. ⽇志调⽤:
这⾥随便写个类,调⽤就是这么简单,log4j的核⼼在配置⽂件上。
复制代码代码如下:
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Hello {
static Logger logger = Logger(Name());
public boolean hello() {
<();  //trace级别的信息,单独列出来是希望你在某个⽅法或者程序逻辑开始的时候调⽤,和
<("Did it again!");  //error级别的信息,参数就是你输出的信息
logger.info("我是info信息");    //info级别的信息
logger.debug("我是debug信息");
logger.warn("我是warn信息");
logger.fatal("我是fatal信息");
logger.log(Level.DEBUG, "我是debug信息");  //这个就是制定Level类型的调⽤:谁闲着没事调⽤这个,也不⼀定哦!
return false;
}
}
如果没有⾃定义配置⽂件,上⾯这个类在写⼀个main⽅法,控制台会输⼊下⾯的样⼦:
复制代码代码如下:
19:09:40.256 [main] ERROR cn.lsw.base.log4j2.Hello - Did it again!
19:09:40.260 [main] FATAL cn.lsw.base.log4j2.Hello - 我是fatal信息
看到没,只有>=ERROR的⽇志输出来了(这是因为Log4j有⼀个默认的配置,它的⽇志级别是ERROR,输出只有控制台)。如果我已经定义好了⽇志,我把⽇志级别改成了TRACE,输出会变成下⾯这样:
复制代码代码如下:
19:11:36.941 TRACE cn.lsw.base.log4j2.Hello 12 hello - entry
19:11:36.951 ERROR cn.lsw.base.log4j2.Hello 13 hello - Did it again!
19:11:36.951 INFO  cn.lsw.base.log4j2.Hello 14 hello - 我是info信息
19:11:36.951 DEBUG cn.lsw.base.log4j2.Hello 15 hello - 我是debug信息
19:11:36.951 WARN  cn.lsw.base.log4j2.Hello 16 hello - 我是warn信息
19:11:36.952 FATAL cn.lsw.base.log4j2.Hello 17 hello - 我是fatal信息
19:11:36.952 DEBUG cn.lsw.base.log4j2.Hello 18 hello - 我是debug信息
19:11:36.952 TRACE cn.lsw.base.log4j2.Hello 19 hello - exit
所有的⽇志都打印出来了,⼤家可以对照上⾯的代码看⼀看。
6. 配置⽂件:
现在开始正题了。
本来以为Log4J 2应该有⼀个默认的配置⽂件的,不过好像没有到,下⾯这个配置⽂件等同于缺省配置:
复制代码代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
log4j2不打印日志
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</appenders>
<loggers>
<root level="error">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
⽽我们只要把configuration>loggers>root的level属性改为trace,就可以输出刚才写的所有信息了。相信⽤过Log4j的⼈对这个配置⽂件也不算陌⽣,Log4J传统的配置⼀直是.properties⽂件,键值对的形式,那种配置⽅式很不好看,但是基本上我们从这个配置⽂件也能看到Log4J 1的影⼦,⽆⾮是appender了,layout之类的,含义也基本⼀样的。
这⾥不准备仔细的讲配置⽂件,没什么必要,⼤家只要知道⼀些基本的配置就可以了。我这⾥写⼏个配置⽂件,并且给了⼀定的注释和讲解,基本上可以⽤了。
 第⼀个例⼦:
复制代码代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</appenders>
<loggers>
<!--我们只让这个logger输出trace信息,其他的都是error级别-->
<!--
additivity开启的话,由于这个logger也是满⾜root的,所以会被打印两遍。
不过root logger 的level是error,为什么Bar ⾥⾯的trace信息也被打印两遍呢
-
->
<logger name="cn.lsw.base.log4j2.Hello" level="trace" additivity="false">
<appender-ref ref="Console"/>
</logger>
<root level="error">
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
先简单介绍⼀下下⾯这个配置⽂件。
1)根节点configuration,然后有两个⼦节点:appenders和loggers(都是复数,意思就是可以定义很多
个appender和logger 了)(如果想详细的看⼀下这个xml的结构,可以去jar包下⾯去xsd⽂件和dtd⽂件)
2)appenders:这个下⾯定义的是各个appender,就是输出了,有好多类别,这⾥也不多说(容易造成理解和解释上的压⼒,⼀开始也未必能听懂,等于⽩讲),先看这个例⼦,只有⼀个Console,这些节点可不是随便命名的,Console就是输出控制台的意思。然后就针对这个输出设置⼀些属性,这⾥设置了PatternLayout就是输出格式了,基本上是前⾯时间,线程,级别,logger名称,log信息等,差不多,可以⾃⼰去查他们的语法规则。
3)loggers下⾯会定义许多个logger,这些logger通过name进⾏区分,来对不同的logger配置不同的输出,⽅法是通过引⽤上⾯定义的logger,注意,appender-ref引⽤的值是上⾯每个appender的name,⽽不是节点名称。
这个例⼦为了说明什么呢?我们要说说这个logger的name(名称)了(前⾯有提到)。
7. name的机制:
 我们这⾥看到了配置⽂件⾥⾯是name很重要,没错,这个name可不能随便起(其实可以随便起)。这个机制意思很简单。就是类似于java package⼀样,⽐如我们的⼀个包:cn.lsw.base.log4j2。⽽且,
可以发现我们前⾯⽣成Logger对象的时候,命名都是通过 Name(); 这样的⽅法,为什么要这样呢?很简单,因为有所谓的Logger 继承的问题。⽐如如果你给cn.lsw.base定义了⼀个logger,那么他也适⽤于cn.lsw.base.lgo4j2这个logger。名称的继承是通过点(.)分隔的。然后你可以猜测上⾯loggers⾥⾯有⼀个⼦节点不是logger⽽是root,⽽且这个root没有name属性。这个root相当于根节点。你所有的logger都适⽤与这个logger,所以,即使你在很多类⾥⾯通过类名.Name()  得到很多的logger,⽽且没有在配置⽂件的loggers下⾯做配置,他们也都能够输出,因为他们都继承了root的log配置。
我们上⾯的这个配置⽂件⾥⾯还定义了⼀个logger,他的名称是 cn.lsw.base.log4j2.Hello ,这个名称其实就是通过前⾯的Name(); 得到的,我们为了给他单独做配置,这⾥就⽣成对于这个类的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 = Logger(Name());
public static void main(String[] args) {
Hello hello= new Hello();
//        for (int i = 0; i < 10000;i++){
if (!hello.hello()) {
<("hello");
}
//        }
}
}
这⾥先把配置⽂件改⼀下⽅便对照,⼀个是刚才第⼀个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。
下⾯在看⼀个稍微复杂的例⼦:
复制代码代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="error">
<!--先定义所有的appender-->
<appenders>
<!--这个输出控制台的配置-->
<Console name="Console" target="SYSTEM_OUT">
<!--控制台只输出level及以上级别的信息(onMatch),其他的直接拒绝(onMismatch)-->
<ThresholdFilter level="trace" onMatch="ACCEPT" onMismatch="DENY"/>
<!--这个都知道是输出⽇志的格式-->
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</Console>
<!--⽂件会打印出所有信息,这个log每次运⾏程序会⾃动清空,由append属性决定,这个也挺有⽤的,适合临时测试⽤-->
<File name="log" fileName="log/test.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<!--这个会打印出所有的信息,每次⼤⼩超过size,则这size⼤⼩的⽇志会⾃动存⼊按年份-⽉份建⽴的⽂件夹下⾯并进⾏压缩,作为存档-->
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%">
<PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
<SizeBasedTriggeringPolicy size="50MB"/>
</RollingFile>
</appenders>
<!--然后定义logger,只有定义了logger并引⼊的appender,appender才会⽣效-->
<loggers>
<!--建⽴⼀个默认的root的logger-->
<root level="trace">
<appender-ref ref="RollingFile"/>
<appender-ref ref="Console"/>
</root>
</loggers>
</configuration>
说复杂,其实也不复杂,这⼀个例⼦主要是为了讲⼀下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级别⽇志⽂件的存在,否则你的程序基本上可以

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。