使用 Json 模板布局 log4j2 在 json 日志中写入序列号时处理异常堆栈跟踪

Handling exception stack trace while writing serial no in json logs using Json template layout log4j2

我正在使用 json template layout 通过 kinesis firehose 和 firelens 将我的 ecs 服务的 json 日志写入到 s3。

以下是我使用的json模板布局的配置-

{
   "context_map": {
       "$resolver": "mdc"
   },
   "serial_no": {
     "$resolver": "pattern",
     "pattern": "%sn"
   },
   "timestamp": {
     "$resolver": "timestamp",
     "pattern": {
       "format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
       "timeZone": "UTC"
     }
   },
   "level": {
     "$resolver": "level",
     "field": "name"
   },
   "logger_name": {
     "$resolver": "logger",
     "field": "name"
   },
   "message": {
     "$resolver": "message",
     "stringified": true
   },
   "thread": {
     "$resolver": "thread",
     "field": "name"
   },
   "exception": {
     "exception_class": {
       "$resolver": "exception",
       "field": "className"
     },
     "exception_message": {
       "$resolver": "exception",
       "field": "message",
       "stringified": true
     },
     "stacktrace": {
       "$resolver": "exception",
       "field": "stackTrace",
       "stringified": true
     }
   },
   "class": {
     "$resolver": "source",
     "field": "className"
   }
 }

以下是日志配置的快照-

     Console:
       - Name: Console
         Target: SYSTEM_OUT
         JsonTemplateLayout:
           eventTemplateUri: "file:/opt/amazon/log-configuration/JsonLayoutTemplate.json"
           prettyPrintEnabled: true
           stackTraceEnabled: true


以下是异常情况下生成的样例日志-

{
    "container_id": "1f1319d278264d3dwewdeddewdewdewdew-849099158",
    "container_name": "test-container",
    "context_map": {
        "RequestId": "28289758-ab3b-4f8c-b3f1-freferfc"
    },
    "exception": {
        "exception_class ": "com.xyz.exception”,
        "exception_message": "Problem processing the SQS message with body helllo world, exception: Error while deserializing the message from test - message - queue.",
        "stacktrace": "com.xyz.exception: Problem processing the SQS message with body helllo world, exception: Error while deserializing the message from test - message - queue.\n\ .... stackTrace”
    },
    "level": "ERROR”,
    "logger_name": "com.xyz.handler",
    "message": "Seems to be impossible to process message: helllo world",
    "serial_no": "52 com.xyz.handler: Problem processing the SQS message with body helllo world, exception: Error while deserializing the message from test - message - queue.\n\ .... stackTrace",
    "source": "stdout",
    "thread": "test-thread",
    "timestamp": "2021-04-06 T14:30:02.122 Z"
}

根据文档 Pattern Resolver delegates to PatternLayout 和模式布局提供 %sn 用于获取序列号。

我们确实需要序列号,因为我们可以同时获取很多日志,所以为了区分日志,我们将在查询日志时依赖那些 json 日志中的序列号、requestId 参数在 AWS Athena 中。

此外,我看到很少有序列号为空的日志实例(不是异常日志)

如何防止 serial_no 在其中包含异常堆栈跟踪? 并确保我总是在日志中得到 serial_no 字段 ?

当您通过 pattern 解析器从 JsonTemplateLayout 委托给 PatternLayout 时,LogEvent 将按原样传递。一旦 PatternLayout 发现 LogEvent 附加了异常,它会将堆栈跟踪附加到发出的输出,因为创建的 PatternLayout 实例继承了 stackTraceEnabled=true 标志您设置为 JsonTemplateLayout。因此,您需要禁用 PatternLayout 的堆栈跟踪,如下所示:

{
  "$resolver": "pattern",
  "pattern": "%sn",
  "stackTraceEnabled": false
}

请注意,这仍将生成 string 类型的序列号。如果要生成 number 类型的序列号,可以按以下方式使用 timestamp 解析器:

{
  "$resolver": "timestamp",
  "epoch": {
    "unit": "nanos",
    "rounded": true
  }
}

与此同时,我创建了 LOG4J2-3067 以将序列号解析器添加到 JsonTemplateLayout