>翻译,原文地址:https://blog.lanyonm.org/articles/2015/12/29/log-aggregation-log4j-spring-logstash.html
* 译者博客:http://www.zimug.com
* 参考:http://my.oschina.net/itblog/blog/547250?fromerr=0057pC5N
解析原始日志文件是Logstash摄取数据的好方法,有好几种方法可以将同样的信息转送到Logstash。选择这些方法需要做一下权衡,它们或多或少只适合特定的场景。之前我已经发布了关于多行的tomcat日志解析,这篇博文是尝试比较它和一些其他的方法:log4j-JSON格式,log4j-TCP 和 原始的log4j的多行编解码器。
这些例子是在一台机器上开发的,但设计目的是使您的ELK栈运行在不同的机器/实例/容器上。在多机环境Filebeat(原logstash-forwarder)将在使用文件输入的情况下使用。
下面是这次测试中,使用到的软件版本
* Java 7u67
* Spring 4.2.3
* Logstash 2.1.0
* Elasticsearch 2.1.1
* Kibana 4.3.1
我第一次开始创作这篇博文是在,2014年11月28日,所以请原谅有些选项可能不再好用。此外,你会发现,SLF4J被用作一个log4j的抽象在代码示例中使用。
## Log4j As JSON
这种方法用于JSON格式的log4j日志,然后用Logstash的文件输入一个JSON编解码器摄取数据。这将使用避免不必要的解析和线程不安全多行过滤器。Seeing json-formatted logs can be jarring for a Java dev (no pun intended), but reading individual log files should be a thing of the past once you’re up and running with log aggregation.如果您有足够的磁盘空间,你可以运行两个并联的追加程序。
比起使用复杂的PatternLayout,让我们一起来看看log4j-jsonevent-layou。一个完全基于配置的符合需求的解决方案。
在```pom.xml```中包含如下的依赖项:
```
<dependency>
<groupId>net.logstash.log4j</groupId>
<artifactId>jsonevent-layout</artifactId>
<version>1.7</version>
</dependency>
```
log4j.properties 看起来很熟悉
```
log4j.rootLogger=debug,json
log4j.appender.json=org.apache.log4j.DailyRollingFileAppender
log4j.appender.json.File=target/app.log
log4j.appender.json.DatePattern=.yyyy-MM-dd
log4j.appender.json.layout=net.logstash.log4j.JSONEventLayoutV1
log4j.appender.json.layout.UserFields=application:playground,environment:dev
```
Logstash的配置如你所想:
```
input {
file {
codec => json
type => "log4j-json"
path => "/path/to/target/app.log"
}
}
output {
stdout {}
}
```
The values set in the UserFields are important because they allow the additional log metadata (taxonomy) to be set in the application configuration. This is information about the application and environment that will allow the log aggregation system to categorize the data. Because we’re using the file input plugin we could also use add_field, but this would require separate file plugins statements for every application. Certainly possible, but even with configuration management more of a headache than the alternative. Also, the path parameter of the file plugin is an array so we can specify multiple files with ease.
如果所有的事情都做对, 在kibana中的log信息应该如下所示:
![](https://box.kancloud.cn/2016-05-25_57455fe9b57c3.png)
A log message from Playground using log4j-jsonevent-layout
As you can see, the UserFields are parsed into Logstash fields. If you prefer these values to be set via command line and environment variable, the library provides a way that will override anything set in the log4j.properties.
## Log4j over TCP
这种方法使用log4j的SocketAppender和Logstash的log4j input。日志事件被转换成可经由SocketAppender二进制格式并传输到log4j input。这里的好处是,新的Log4j追加可无需额外的依赖,而且我们能够避免处理额外的多行过滤器。在深入挖掘这种方法的缺点之前,让我们来看看它如何实现。
这里的log4j.properties的一个片段:
```
log4j.rootLogger=debug,tcp
log4j.appender.tcp=org.apache.log4j.net.SocketAppender
log4j.appender.tcp.Port=3456
log4j.appender.tcp.RemoteHost=localhost
log4j.appender.tcp.ReconnectionDelay=10000
log4j.appender.tcp.Application=playground
```
对应的 Logstash配置片段如:
```
input {
log4j {
mode => "server"
host => "0.0.0.0"
port => 3456
type => "log4j"
}
}
output {
stdout {}
}
```
采用上面的log4j的配置,你将无法看到日志的application字段。当此参数被设置,Logstash将它解析为一个event字段。这是非常方便的,但它无法满足你进行日志分类- 揭露这种方法的缺点之一:用application和环境识别信息对日志事件打标签。在Logstash配置时需要使用一个输入插件add_field。这种做法将意味着对于每一个Java应用程序,将发送日志到不同的输入 插件/端口 - 对于扩展应用来说,这真的不好玩!
### 映射诊断上下文(Mapped Diagnostic Context)
映射诊断上下文(MDC)提供了一种方法,通过设置一组你感兴趣的信息的map键值对,来丰富标准日志信息。值得庆幸的是log4j的插件将解析MDC到日志事件字段中。MDC在每个线程中单独管理,但是子线程自动继承父线程的MDC的副本。这意味着日志分类可以在应用程序的主线程设置为MDC,并影响其整个生命周期的每个日志声明。
下面是一个简单的例子:
```
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
public class LoggingTaxonomy {
private static final Logger log = LoggerFactory.getLogger(LoggingTaxonomy.class);
static public void main(String[] args) {
MDC.put("environment", System.getenv("APP_ENV"));
// run the app
log.debug("the app is running!");
}
}
```
一个样式如%d{ABSOLUTE} %5p %c{1}:%L - %X{environment} - %m%n的PatternLayout,并且设置APP_ENV为dev,你将看到如下输出:
```
15:23:03,698 DEBUG LoggingTaxonomy:34 - dev - the app is running!
```
在何时何地集成MDC很大程度上决定于你的应用使用的框架。但是我曾经用过的每一个框架都有一个地方可以设置这个信息。在Spring MVC中,可以放在应用初始化方法中。
如果所有的事情都做对, 在kibana中的log信息应该如下所示:
![A log message from Playground using Log4j over TCP and MDC for additional log event fields](https://box.kancloud.cn/2016-05-25_57455fec605e0.png)
使用这种方法需要注意几个事情:
* The logging level is stored in priority, not level as is with log4j-jsonevent-layout
* 没有 source_host 字段, 所以你需要通过MDC方式自行添加