filebeat和logstash收集处理java多行日志
java的异常日志通常是多行的,使用logstash和filebeat收集的时候每行就会当成一条日志(事件),这样是不连贯的。所以,我们需要对这种日志进行合并.
比如一个java应用产生的异常日志是这样:
2017-11-15 08:04:23:889 ERROR com.weconex.pay.callback.gateway.service.mq.receive.MerchantCallbackReceiver 173 send - 商户回调网关-- 发送HTTP异常!参数:requestNo=101201711151000062271 java.io.FileNotFoundException: http://192.168..139:8000/mrchantDemo/callback.htm at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1624) ~[?:1.7.0_51] at com.weconex.pay.commons.callback.utils.HttpClient.response(HttpClient.java:198) ~[callback-gateway-commons-2.1.0-SNAPSHOT.jar:?] at com.weconex.pay.commons.callback.utils.HttpClient.send(HttpClient.java:109) ~[callback-gateway-commons-2.1.0-SNAPSHOT.jar:?] at com.weconex.pay.callback.gateway.service.mq.receive.MerchantCallbackReceiver.send(MerchantCallbackReceiver.java:165) [callback-gateway-service-2.1.0-SNAPSHOT.jar:?] at com.weconex.pay.callback.gateway.service.mq.receive.MerchantCallbackReceiver.onMessage(MerchantCallbackReceiver.java:79) [callback-gateway-service-2.1.0-SNAPSHOT.jar:?] at org.springframework.jms.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:214) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:721) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:681) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:651) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:317) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:255) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1166) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1158) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE] at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1055) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE] at java.lang.Thread.run(Thread.java:744) [?:1.7.0_51]
可以看到一个异常的日志是多行的,我们目的是要把有这样的日志合并成一条
logstash做法
增加一个匹配java日志的partten文件,目的是匹配以 “2017-11-15 08:04:23:889” 这种时间格式开头的日志
# vim /usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-4.1.2/patterns/catalina WORDS [a-zA-Z]{3} CATALINAOUT ^(\s*%{YEAR}|%{MONTHDAY})-(%{MONTHNUM}|%{WORDS})-(%{MONTHDAY}|%{YEAR}) %{HOUR}:?%{MINUTE}(?::?%{SECOND})
通过codec的mutiline插件将多行合并成一行
# vim /etc/logstash/conf.d/server.conf input { file { id => "input-file" type => "catalina.out" path => ["/data/logs/catalina.out"] codec => multiline { # 使用codec/multiline插件 pattern => "%{CATALINAOUT}" # 指定匹配的表达式 negate => true # 是否匹配到 what => "previous" # 可选previous或next, previous是合并到匹配的上一行末尾 max_lines => 1000 # 最大允许的行 max_bytes => "10MiB" # 允许的大小 auto_flush_interval => 30 # 如果在规定时候内没有新的日志事件就不等待后面的日志事件 } } } output { stdout { codec => "rubydebug" }
上面的意思是如果一个日志事件没有被 {CATALINAOUT} 这个pattern匹配到则合并到上一行的末尾,最后进行测试
[root@ops38 conf.d]# logstash -rf server.conf Sending Logstash's logs to /var/log/logstash which is now configured via log4j2.properties { "path" => "/data/logs/catalina.out", "@timestamp" => 2017-12-03T12:53:32.687Z, "@version" => "1", "host" => "ops38", "message" => "2017-11-15 08:04:23:889 ERROR com.weconex.pay.callback.gateway.service.mq.receive.MerchantCallbackReceiver 173 send - 商户回调网关--\n发送HTTP异常!参数:requestNo=101201711151000062271 java.io.FileNotFoundException: http://222.143.53.139:8000/MerchantDemo/callback.htm\n at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1624) ~[?:1.7.0_51]\n at com.weconex.pay.commons.callback.utils.HttpClient.response(HttpClient.java:198) ~[callback-gateway-commons-2.1.0-SNAPSHOT.jar:?]\n at com.weconex.pay.commons.callback.utils.HttpClient.send(HttpClient.java:109) ~[callback-gateway-commons-2.1.0-SNAPSHOT.jar:?]\n at com.weconex.pay.callback.gateway.service.mq.receive.MerchantCallbackReceiver.send(MerchantCallbackReceiver.java:165) [callback-gateway-service-2.1.0-SNAPSHOT.jar:?]\n at com.weconex.pay.callback.gateway.service.mq.receive.MerchantCallbackReceiver.onMessage(MerchantCallbackReceiver.java:79) [callback-gateway-service-2.1.0-SNAPSHOT.jar:?]\n at org.springframework.jms.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:214) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE]\n at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:721) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE]\n at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:681) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE]\n at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:651) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE]\n at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:317) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE]\n at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:255) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE]\n at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1166) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE]\n at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1158) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE]\n at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1055) [spring-jms-4.3.4.RELEASE.jar:4.3.4.RELEASE]\n at java.lang.Thread.run(Thread.java:744) [?:1.7.0_51]", "type" => "catalina.out", "tags" => [ [0] "multiline" ] }
解析时,最后一行不会输出。只有当再追加一条日志时,才会输出最后一条日志。 可以指定 auto_flush_interval值,如果在auto_flush_interval时间内没有新的日志事件就不等待后面的日志
filebeat做法
修改filebeat的配置文件 /etc/filebeat/filebeat.yml
filebeat.prospectors: - input_type: log enable: yes name: "catalina-out" paths: - /data/logs/catalina.out multiline: pattern: '^\s*(\d{4}|\d{2})\-(\d{2}|[a-zA-Z]{3})\-(\d{2}|\d{4})' # 指定匹配的表达式 negate: true # 是否匹配到 match: after # 合并到上一行的末尾 max_lines: 1000 # 最大的行数 timeout: 30s # 如果在规定的时候没有新的日志事件就不等待后面的日志 fields: # 添加type字段 type: "catalina-out" fields_under_root: true # 将type变为顶级字段
上面的效果和logstash一样, 如果没有被pattern匹配到则合并到上一行的末尾。
同样解析时最后一行不会输出。只有当再追加一条日志时,才会输出最后一条日志,可以指定timeout时间,与auto_flush_interval效果一样.