当前位置:首页 » JavaScript技术

如何使log4j生成json格式的log

2017-09-15 18:01 本站整理 浏览(4)

使用java开发项目时,log日志一般都是应用程序必不可少的一部分,大部分情况下我们的log文件都是普通的文本信息,通过level来标记不同级别的日志。
日志的目的,主要还是为了出现问题时有追踪的途径,方便从里面查出原因,在数据量小的时候通过linux上的各种shell命令如awk,grep就能快速查询或者做一些简单的统计,当数据量的时候,而且程序本身还是分布式的时候,这种方式就有点费劲。比如你有10台机器,你需要登录每台查询,是非常繁琐的,而且数据量大的时候linux命令可能效率非常低。所以这个时候我们就必要使用专门的日志分析工具来处理了,推荐使用ELK套件,对日志查询分析统计非常擅长,最重要是开源的。
ElasticSearch支持标准的json结构的数据,直接构建索引,但大多数时候我们的log文件都是普通文本,没办法直接插入es里面,除非中间使用logstash在转化一下,才能插入,但这样我们就需要维护多套logstash规则,也比较繁琐,理想的情况下,就是生成的log直接就是json格式的,这样通过logstash直接插入es即可,不需要关注具体的业务字段,这样就比较灵活。
在log4j中是没有直接对应的json的layout,这里解释一下layout,layout是日志组件里面渲染最终结果为字符串的一个类,如果我们需要自定义格式,那么就需要继承layout这个类,然后重写format方法,来完成最终的日志输出格式。
log4j直接是不支持json格式的,不过logstash官网已经提供了支持项目jsonevent-layout,虽然已经好几年没更新了,但简单的凑合还能用。功能就是将log4j的打印信息转成json格式,这样通过logstash就直接能插入es里面,如何使用?
github:https://github.com/logstash/log4j-jsonevent-layout
先在maven里面引入下面的pom依赖:

<!-- https://mvnrepository.com/artifact/net.logstash.log4j/jsonevent-layout -->
<dependency>
    <groupId>net.logstash.log4j</groupId>
    <artifactId>jsonevent-layout</artifactId>
    <version>1.7</version>
</dependency>


然后在log4j.properties简单配置即可:
#log4j.rootLogger=INFO,console,kafka
log4j.rootLogger=INFO,console

# appender console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.out
log4j.appender.console.layout=net.logstash.log4j.JSONEventLayout

最终打印的log格式如下:
{"@timestamp":"2017-09-15T09:08:50.805Z","source_host":"USER-20160722CY","file":"TestJson.java","method":"main","level":"INFO","line_number":"39","thread_name":"main","@version":1,"logger_name":"TestJson","message":"log信息","class":"net.logstash.log4j.TestJson","mdc":{}}

上面的log除了是标准的json格式外,还有ELK里面特需的时间戳字段@timestamp,注意这个字段必须得有而且格式必须是es支持的格式,只有这样才能直接经过logstash插入到es里面。
总结:
虽然使用logstash官网的jsonevent-layout能够直接将log4j的输出信息转换成json,但是缺点是不能够支持自定义的字段加入到json中,比如我在log.info()方法里面传入一个Map类里面的kv都需要在json里面生成,或者直接在info方法里面传入一个JSON对象,有时候我们的应用程序需要设置特定的字段加入到json,便于后续的针对性的统计分析,比如说我有一个方法耗时的字段,目前来看jsonevent-layout是不满足的,所以还需要我们自定义一个layout来实现这样的功能,这个在后面的文章会分享出来。