通过syslog发送log4j2堆栈跟踪 [英] Send log4j2 stack traces over syslog
问题描述
我正在尝试将堆栈跟踪记录到Logstash中.
I am trying to log stack traces into Logstash.
日志记录堆栈是ELK(ElasticSearch,Logstash,Kibana).
The logging stack is ELK (ElasticSearch, Logstash, Kibana).
产生日志的应用程序是一个Java应用程序,使用slf4j
作为日志记录接口,并使用log4j2
作为日志记录实现.
The application producing logs is a Java application, using slf4j
as a logging interface, and log4j2
as the logging implementation.
log4j2.xml
使用RFC5424
格式声明此syslog
Appender:
The log4j2.xml
declares this syslog
Appender, with the RFC5424
format:
<Appenders>
<Syslog name="RFC5424" format="RFC5424" host="localhost" port="8514"
protocol="TCP" appName="MyApp" includeMDC="true" mdcId="mdc"
facility="LOCAL0" enterpriseNumber="18060" newLine="true"
messageId="Audit" id="App">
<LoggerFields>
<KeyValuePair key="thread" value="%t"/>
<KeyValuePair key="priority" value="%p"/>
<KeyValuePair key="category" value="%c"/>
<KeyValuePair key="exception" value="%ex{full}"/>
</LoggerFields>
</Syslog>
</Appenders>
我从Java应用程序中记录一个Throwable,如下所示:
I log a Throwable from the Java application like so:
org.slf4j.LoggerFactory.getLogger("exception_test").error("Testing errors", new RuntimeException("Exception message"));
记录到异常后,Logstash会跟踪这样的内容以向我显示其持续存在的原因:
When an exception is logged, Logstash traces something like this to show me what it persists:
{
"@timestamp":"2016-11-08T11:08:10.387Z",
"port":60397,
"@version":"1",
"host":"127.0.0.1",
"message":"<131>1 2016-11-08T11:08:10.386Z MyComputer.local MyApp - Audit [mdc@18060 category=\"exception_test\" exception=\"java.lang.RuntimeException: Exception message",
"type":"syslog",
"tags":[
"_grokparsefailure"
]
}
我确认Kibana在其日志条目之一的_source
字段中显示了完全相同的JSON.
And I confirm that Kibana displays exactly the same JSON within the _source
field of one of its log entries.
这里有一个问题:没有保存堆栈跟踪.并且测试错误"消息丢失了.
There's a problem here: no stack trace is saved. And the message, "Testing errors", is lost.
不幸的是,"tags":["_grokparsefailure"]
却与此问题无关..
The "tags":["_grokparsefailure"]
is unfortunate but not related to this question.
我尝试添加<ExceptionPattern/>
来查看它是否会更改任何内容:
I tried adding <ExceptionPattern/>
to see if it would change anything:
<Syslog name="RFC5424" format="RFC5424" host="localhost" port="8514"
protocol="TCP" appName="MyApp" includeMDC="true" mdcId="mdc"
facility="LOCAL0" enterpriseNumber="18060" newLine="true"
messageId="Audit" id="App">
<LoggerFields>
<KeyValuePair key="thread" value="%t"/>
<KeyValuePair key="priority" value="%p"/>
<KeyValuePair key="category" value="%c"/>
<KeyValuePair key="exception" value="%ex{full}"/>
</LoggerFields>
<ExceptionPattern>%ex{full}</ExceptionPattern>
</Syslog>
<ExceptionPattern/>
替换日志消息,并且也(很遗憾)忽略了所有loggerFields
.但这确实给了我一个类名和行号:
<ExceptionPattern/>
replaces the log message, and also (sadly) omits all loggerFields
. But it does give me a class name and line number:
{
"@timestamp":"2016-11-08T11:54:03.835Z",
"port":60397,
"@version":"1",
"host":"127.0.0.1",
"message":"at com.stackoverflow.LogTest.throw(LogTest.java:149)",
"type":"syslog",
"tags":[
"_grokparsefailure"
]
}
再次:没有堆栈跟踪.再说一次:测试错误"消息丢失了.
Again: no stack trace. And again: the message, "Testing errors", is lost.
如何使用log4j2
将堆栈跟踪记录到Logstash中?我不一定必须使用syslog
附加程序.
How can I use log4j2
to log stack traces into Logstash? I don't necessarily have to use the syslog
appender.
基本上,约束是:
- 不锁定任何特定的日志记录基础结构(这就是为什么我使用syslog的原因)
- 多行堆栈跟踪需要理解为单个日志条目. 堆栈跟踪的每一行"都不是单独的日志消息"
- 堆栈跟踪必须能够经过过滤器.我的一个典型的例外可能是长达一整页的堆栈跟踪.我想过滤掉像Spring这样的框架.
- Not be locked in to any particular logging infrastructure (this is why I used syslog)
- Multi-line stack traces need to be understood as being a single log entry. It's undesirable for "each line of the stack trace" to be "a separate log message"
- Stack traces must be able to be subjected to filters. A typical exception of mine can have a page-long stack trace. I want to filter out frames like Spring.
推荐答案
Log4j 2.5的SyslogAppender只能通过UDP发送堆栈跟踪.
Log4j 2.5's SyslogAppender can only send stack traces over UDP.
<Syslog name="RFC5424" format="RFC5424" host="localhost" port="8514"
protocol="UDP" appName="MyApp" includeMDC="true" mdcId="mdc"
facility="LOCAL0" enterpriseNumber="18060" newLine="true"
messageId="LogTest" id="App">
<LoggerFields>
<KeyValuePair key="thread" value="%t"/>
<KeyValuePair key="priority" value="%p"/>
<KeyValuePair key="category" value="%c"/>
<KeyValuePair key="exception" value="%ex{full}"/>
</LoggerFields>
<ExceptionPattern>%ex{full}</ExceptionPattern>
</Syslog>
使用UDP:ExceptionPattern
和 LoggerFields.KeyValuePair["exception"]
都开始作为多行堆栈跟踪的解决方案.
With UDP: both ExceptionPattern
and LoggerFields.KeyValuePair["exception"]
start working as solutions for multiline stack traces.
当我通过syslog通过 UDP 发送异常时,这是logstash
打印的内容:
This is what logstash
prints when I sent an exception over UDP via syslog:
{
"@timestamp" => 2016-11-14T13:23:38.304Z,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "<131>1 2016-11-14T13:23:38.302Z BirchBox.local MyApp - LogTest [mdc@18060 category=\"com.stackoverflow.Deeply\" exception=\"java.lang.RuntimeException: Exception message\n\tat com.stackoverflow.Deeply.complain(Deeply.java:10)\n\tat com.stackoverflow.Nested.complain(Nested.java:8)\n\tat com.stackoverflow.Main.main(Main.java:20)\n\" priority=\"ERROR\" thread=\"main\"] Example error\njava.lang.RuntimeException: Exception message\n\tat com.stackoverflow.Deeply.complain(Deeply.java:10)\n\tat com.stackoverflow.Nested.complain(Nested.java:8)\n\tat com.stackoverflow.Main.main(Main.java:20)",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
在[mdc@18060 exception=\"…\"]
内部,我们获得了 LoggerFields.KeyValuePair["exception"]
堆栈跟踪.
Inside [mdc@18060 exception=\"…\"]
we get the LoggerFields.KeyValuePair["exception"]
stack trace.
此外,由于ExceptionPattern
,堆栈跟踪已插入到已记录的消息本身中.
In addition to this: the stack trace is inserted into the logged message itself, thanks to ExceptionPattern
.
供参考:当我通过syslog通过 TCP 发送异常时,这是logstash
打印的内容(即与上述相同的SyslogAppender,但使用protocol="TCP"
):
For reference: this is what logstash
prints when I send the exception over TCP via syslog (i.e. the same SyslogAppender as described above, but with protocol="TCP"
instead):
{
"@timestamp" => 2016-11-14T19:56:30.293Z,
"port" => 63179,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "<131>1 2016-11-14T19:56:30.277Z BirchBox.local MyApp - Audit [mdc@18060 category=\"com.stackoverflow.Deeply\" exception=\"java.lang.RuntimeException: Exception message",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
{
"@timestamp" => 2016-11-14T19:56:30.296Z,
"port" => 63179,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "at com.stackoverflow.Deeply.complain(Deeply.java:10)",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
{
"@timestamp" => 2016-11-14T19:56:30.296Z,
"port" => 63179,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "at com.stackoverflow.Nested.complain(Nested.java:8)",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
{
"@timestamp" => 2016-11-14T19:56:30.296Z,
"port" => 63179,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "at com.stackoverflow.Main.main(Main.java:20)",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
{
"@timestamp" => 2016-11-14T19:56:30.296Z,
"port" => 63179,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "\" priority=\"ERROR\" thread=\"main\"] Example error",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
{
"@timestamp" => 2016-11-14T19:56:30.296Z,
"port" => 63179,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "java.lang.RuntimeException: Exception message",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
{
"@timestamp" => 2016-11-14T19:56:30.297Z,
"port" => 63179,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "at com.stackoverflow.Deeply.complain(Deeply.java:10)",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
{
"@timestamp" => 2016-11-14T19:56:30.298Z,
"port" => 63179,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "at com.stackoverflow.Nested.complain(Nested.java:8)",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
{
"@timestamp" => 2016-11-14T19:56:30.298Z,
"port" => 63179,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "at com.stackoverflow.Main.main(Main.java:20)",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
{
"@timestamp" => 2016-11-14T19:56:30.299Z,
"port" => 63179,
"@version" => "1",
"host" => "127.0.0.1",
"message" => "",
"type" => "syslog",
"tags" => [
[0] "_grokparsefailure"
]
}
看起来TCP实际上确实在起作用",但是将单个日志消息拆分为许多个系统日志消息(例如,遇到\n
时).
It looks like TCP does actually "work", but splits the single log message into many syslog messages (for example when \n
is encountered).
这篇关于通过syslog发送log4j2堆栈跟踪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!