3.6 Java日志
之前在2.2节有关codec的介绍中曾经提到过,对Java日志,除了使用multiline做多行日志合并以外,还可以直接通过Log4J写入logstash里。本节就讲述如何在Java应用环境做到这点。
3.6.1 Log4J配置
首先,需要配置Java应用的Log4J设置,启动一个内置的SocketAppender。修改应用的log4j.xml配置文件,添加如下配置段:
<appender name=“LOGSTASH” class=“org.apache.log4j.net.SocketAppender”> <param name=“RemoteHost” value=“logstash_hostname” /> <param name=“ReconnectionDelay” value=“60000” /> <param name=“LocationInfo” value=“true” /> <param name=“Threshold” value=“DEBUG” /> </appender>
然后把这个新定义的appender对象加入root logger里,可以跟其他已有logger共存:
<root> <level value=“INFO”/> <appender-ref ref=“OTHERPLACE”/> <appender-ref ref=“LOGSTASH”/> </root>
如果是log4j.properties配置文件,则对应配置如下:
log4j.rootLogger=DEBUG, logstash ###SocketAppender### log4j.appender.logstash=org.apache.log4j.net.SocketAppender log4j.appender.logstash.Port=4560 log4j.appender.logstash.RemoteHost=logstash_hostname log4j.appender.logstash.ReconnectionDelay=60000 log4j.appender.logstash.LocationInfo=true
Log4J会持续尝试连接你配置的logstash_hostname这个地址,建立连接后,即开始发送日志数据。
3.6.2 Logstash配置
Java应用端的配置完成以后,开始设置Logstash的接收端。配置如下所示,其中4560端口是Log4J SocketAppender的默认对端端口:
input { log4j { type =>“log4j-json” port => 4560 } }
3.6.3 异常堆栈测试验证
运行Logstash后,编写一个简单的Log4J程序:
import org.apache.log4j.Logger; public class HelloExample{ final static Logger logger = Logger.getLogger(HelloExample.class); public static void main(String[] args) { HelloExample obj = new HelloExample(); try{ obj.divide(); }catch(ArithmeticException ex){ logger.error(“Sorry, something wrong!”, ex); } } private void divide(){ int i = 10 /0; } }
编译运行:
# javac -cp ./logstash-1.5.0.rc2/vendor/bundle/jruby/1.9/gems/logstash-input- log4j-0.1.3-java/lib/log4j/log4j/1.2.17/log4j-1.2.17.jar HelloExample.java # java -cp .:./logstash-1.5.0.rc2/vendor/bundle/jruby/1.9/gems/logstash-input- log4j-0.1.3-java/lib/log4j/log4j/1.2.17/log4j-1.2.17.jar HelloExample
这样即可在Logstash的终端输出看到如下事件记录:
{“message” =>“Sorry, something wrong!”,“@version” =>“1”,“@timestamp” =>“2015-07-02T13:24:45.727Z”,“type” =>“log4j-json”,“host” =>“127.0.0.1:52420”,“path” =>“HelloExample”,“priority” =>“ERROR”,“logger_name” =>“HelloExample”,“thread” =>“main”,“class” =>“HelloExample”,“file” =>“HelloExample.java:9”,“method” =>“main”,“stack_trace” =>“java.lang.ArithmeticException: / by zero\n\tat HelloExample. divide(HelloExample.java:13)\n\tat HelloExample.main(HelloExample.java:7)” }
可以看到,异常堆栈直接记录在单行内了。
3.6.4 JSON Event layout
如果无法采用SocketAppender,必须使用文件方式的,其实Log4J有一个layout特性,用来控制日志输出的格式。和Nginx日志自己拼接JSON输出类似,也可以通过layout功能记录成JSON格式。
Logstash官方提供了扩展包,可以通过mvnrepository.com搜索下载:
# wget http://central.maven.org/maven2/net/logstash/log4j/jsonevent-layout/1.7/ jsonevent-layout-1.7.jar
或者直接编辑自己项目的pom.xml添加依赖:
<dependency> <groupId>net.logstash.log4j</groupId> <artifactId>jsonevent-layout</artifactId> <version>1.7</version> </dependency>
然后修改项目的log4j.properties文件如下:
log4j.rootCategory=WARN, RollingLog log4j.appender.RollingLog=org.apache.log4j.DailyRollingFileAppender log4j.appender.RollingLog.Threshold=TRACE log4j.appender.RollingLog.File=api.log log4j.appender.RollingLog.DatePattern=.yyyy-MM-dd log4j.appender.RollingLog.layout=net.logstash.log4j.JSONEventLayoutV1
如果是log4j.xml,则修改如下:
<appender name=“Console” class=“org.apache.log4j.ConsoleAppender”> <param name=“Threshold” value=“TRACE” /> <layout class=“net.logstash.log4j.JSONEventLayoutV1” /> </appender>
生成的文件就是符合Logstash标准的JSON格式了,Logstash使用下面配置读取:
input { file { codec => json path => [“/path/to/log4j.log”] } }
生成的Logstash事件如下:
{ “mdc”:{}, “line_number”:“29”, “class”:“org.eclipse.jetty.examples.logging.EchoFormServlet”, “@version”:1, “source_host”:“jvstratusmbp.local”, “thread_name”:“qtp513694835-14”, “message”:“Got request from 0:0:0:0:0:0:0:1%0 using Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/32.0. 1700.77 Safari\/537.36”, “@timestamp”:“2014-01-27T19:52:35.738Z”, “level”:“INFO”, “file”:“EchoFormServlet.java”, “method”:“doPost”, “logger_name”:“org.eclipse.jetty.examples.logging.EchoFormServlet” }
可以看到,同样达到了效果。
如果你使用的不是Log4J而是logback项目来记录Java日志,Logstash官方也有类似的扩展包,在pom.xml中改成如下定义即可:
<dependency> <groupId>net.logstash.logback</groupId> <artifactId>logstash-logback-encoder</artifactId> <version>4.4</version> </dependency>