log4j使用教程详解(怎么使用log4j2)
1. 去官方下载log4j 2,导入jar包,基本上你只需要导入下面两个jar包就可以了(xx是乱七八糟的版本号):
log4j-core-xx.jar
log4j-api-xx.jar
2. 导入到你的项目中:这个就不说了。
3. 开始使用:
我们知道,要在某个类中使用log4j记录日志,只需要申明下面的成员变量(其实不一定要是成员变量,只是为了方便调用而已)
private static logger logger = logmanager.getlogger(myapp.class.getname());
里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 = logmanager.getlogger(hello.class.getname());
public boolean hello() {
logger.entry(); //trace级别的信息,单独列出来是希望你在某个方法或者程序逻辑开始的时候调用,和logger.trace("entry")基本一个意思
logger.error("did it again!"); //error级别的信息,参数就是你输出的信息
logger.info("我是info信息"); //info级别的信息
logger.debug("我是debug信息");
logger.warn("我是warn信息");
logger.fatal("我是fatal信息");
logger.log(level.debug, "我是debug信息"); //这个就是制定level类型的调用:谁闲着没事调用这个,也不一定哦!
logger.exit(); //和entry()对应的结束方法,和logger.trace("exit");一个意思
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">
<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对象的时候,命名都是通过 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。
下面在看一个稍微复杂的例子:
<?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}-%i.log.gz">
<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级别日志文件的存在,否则你的程序基本上可以重写了。
这里可以添加一个appender,内容如下:
<file name="error" filename="logs/error.log">
<thresholdfilter level="error" onmatch="accept" onmismatch="deny"/>
<patternlayout pattern="%d{yyyy.mm.dd 'at' hh:mm:ss z} %-5level %class{36} %l %m - %msg%xex%n"/>
</file>
并在loggers中的某个logger(如root)中引用(root节点加入这一行作为子节点)。
<appender-ref ref="error" />
>然后,增加一个rollingfile的appender,设置基本上同上面的那个配置文件。
>最后,在logger中进行相应的配置。不过如果你的logger中也有日志级别的配置,如果级别都在error以上,你的appender里面也就不会输出error一下的信息了。
还记得上面的test类里面有一个被注释掉的for循环么?这个是为了做配置文件中rollingfile那个appender的配置的,取消注释,运行商一次或几次,看你的输出配置文件的地方,他是怎么“rollingfile”的,这里给个我测试的截图:(这里你可以把 <sizebasedtriggeringpolicy size="50mb"/>这里的size改成2mb,要生成50mb的日志还是比较慢的。为了方便观察么!然后把console的thresholdfilter的level设置成error这样的较高级别,不然控制台输出东西太多了)
第一部分(图中标识为1),是我加入的jar包;
第二部分是file这个appender生成的日志文件,你会发现你运行很多次,这个文件中的日志是被覆盖的。
第三部分是rollingfile 这个appender生成的配置文件,可以发现,默认建立的是app.log这个日志,每次超过2mb的时候,就会生成对应年-月的文件夹,和制定命名格式的log文件,而且是压缩成gz格式文件,打开资源管理器发现这个文件只有11kb,解压后就是2mb。
最后,希望这个教程能够帮到大家!
下一篇: 脚本编程,脚本实测
推荐阅读
-
log4j使用教程详解(怎么使用log4j2)
-
PHP没有数据库连接池怎么破?PHP环境下使用Nginx ngx_http_limit_req_module模块的高负载解决方案_PHP教程
-
php中使用parse_url()对网址进行解析的实现代码(parse_url详解)_PHP教程
-
Log4j详细使用教程_动力节点Java学院整理
-
thinkphp教程之RBAC详解2之RBAC类内容和使用流程讲解
-
SpringBoot整合Swagger和Actuator的使用教程详解
-
鲁大师wifi共享怎么用?鲁大师免费iwifi共享功能使用教程
-
AJAX使用教程图文详解(附视频)
-
影音先锋怎么看片?影音先锋点播视频教程(PC端、手机端、平板电脑端使用方法大全)
-
PHP的可变变量名使用方法详解_PHP教程