【问题标题】:Send log4j2 stack traces over syslog通过 syslog 发送 log4j2 堆栈跟踪
【发布时间】:2016-11-08 12:18:51
【问题描述】:

我正在尝试将堆栈跟踪记录到 Logstash。

日志堆栈是 ELK(ElasticSearch、Logstash、Kibana)。

产生日志的应用是一个Java应用,使用slf4j作为日志接口,log4j2作为日志实现。

log4j2.xmlRFC5424 格式声明此syslog Appender:

<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,如下所示:

org.slf4j.LoggerFactory.getLogger("exception_test").error("Testing errors", new RuntimeException("Exception message"));

当记录异常时,Logstash 会跟踪类似这样的内容,以向我展示它持续存在的内容:

{
   "@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。

这里有一个问题:没有保存堆栈跟踪。并且“测试错误”消息丢失了。

"tags":["_grokparsefailure"] 很不幸,但 与这个问题无关


我尝试添加&lt;ExceptionPattern/&gt; 看看它是否会改变任何东西:

<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>

&lt;ExceptionPattern/&gt; 替换了日志消息,(遗憾地)省略了所有 loggerFields。但它确实给了我一个类名和行号:

{
   "@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"
   ]
}

再次:没有堆栈跟踪。再说一遍:“测试错误”消息丢失了。


如何使用log4j2 将堆栈跟踪记录到 Logstash?我不一定非得使用syslog appender。

基本上限制是:

  • 不被锁定到任何特定的日志记录基础设施(这就是我使用 syslog 的原因)
  • 多行堆栈跟踪需要被理解为单个日志条目。 “堆栈跟踪的每一行”都是“单独的日志消息”是不可取的
  • 堆栈跟踪必须能够接受过滤器。我的一个典型例外可能有一个页面长的堆栈跟踪。我想过滤掉像 Spring 这样的框架。

【问题讨论】:

    标签: java logging logstash log4j2 syslog


    【解决方案1】:

    Log4j 2.5 的 SyslogAppender 只能通过 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"] 都开始作为多行堆栈跟踪的解决方案。

    这是logstash 在我通过 syslog 通过 UDP 发送异常时打印的内容:

    {
        "@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"] 堆栈跟踪。

    除此之外:感谢ExceptionPattern,堆栈跟踪被插入到记录的消息本身中


    供参考:这是logstash 通过 syslog 通过 TCP 发送异常时打印的内容(即与上述相同的 SyslogAppender,但使用 protocol="TCP" 代替):

    {
        "@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 确实“工作”了,但将单个日志消息拆分为 许多 syslog 消息(例如当遇到 \n 时)。

    【讨论】:

    • 我在 Syslog appender 中使用 PatternLayout,并且“%throwable{separator(|)}”允许我通过 TCP 获取整个异常堆栈。
    猜你喜欢
    • 2018-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-01
    • 2016-06-17
    • 1970-01-01
    • 2011-05-19
    • 1970-01-01
    相关资源
    最近更新 更多