Log4J - JsonLayout 和 RollingFileAppender 生成无效 JSON

Log4J - JsonLayout and RollingFileAppender generating invalid JSON

我正在尝试使用 Log4J (2.6.2) 将我的日志存储在 JSON 文件中。我在 RollingFileAppender 中使用 JsonLayout,只要我不尝试附加到之前已经写入的文件,它就可以正常工作。

这是我设置 Layout 和 Appender 的代码:

Layout<?> layout = JsonLayout.createLayout(config, false, false, false, true, false, true, "[", "]", Charset.defaultCharset());

String appenderFileName = "mylogfile-latest.log.json";
String appenderFilePattern = "mylogfile-%i.log.json";
String appenderName = "MyAppender";
Appender appender = RollingFileAppender.createAppender(appenderFileName, appenderFilePattern, "true", appenderName, "true", "256", "true",
        SizeBasedTriggeringPolicy.createPolicy(this.configuration.getLogMaxSize().toString()),
        null, layout, null, "false", "false", null, config);

正如我所说,我第一次在我的日志文件中写入时它工作正常:

[
  {
    "timeMillis" : 1469620840442,
    "thread" : "SimpleAsyncTaskExecutor-43",
    "level" : "ERROR",
    "loggerName" : "MyLogger",
    "message" : "my log message",
    "endOfBatch" : false,
    "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
    "threadId" : 243,
    "threadPriority" : 5
  }
  , {
    "timeMillis" : 1469620840442,
    "thread" : "SimpleAsyncTaskExecutor-43",
    "level" : "DEBUG",
    "loggerName" : "MyLogger",
    "message" : "my log message",
    "endOfBatch" : false,
    "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
    "threadId" : 243,
    "threadPriority" : 5
  }
]

然后我关闭我的 appender 等...并重新启动我的应用程序,当我向这个现有文件写入新日志时,我得到的是:

[
{
  "timeMillis" : 1469620840442,
  "thread" : "SimpleAsyncTaskExecutor-43",
  "level" : "ERROR",
  "loggerName" : "MyLogger",
  "message" : "my log message",
  "endOfBatch" : false,
  "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
  "threadId" : 243,
  "threadPriority" : 5
}
, {
  "timeMillis" : 1469620840442,
  "thread" : "SimpleAsyncTaskExecutor-43",
  "level" : "DEBUG",
  "loggerName" : "MyLogger",
  "message" : "my log message",
  "endOfBatch" : false,
  "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
  "threadId" : 243,
  "threadPriority" : 5
}

]
{
    "timeMillis" : 1469620840490,
    "thread" : "SimpleAsyncTaskExecutor-43",
    "level" : "ERROR",
    "loggerName" : "MyLogger",
    "message" : "my log message",
    "endOfBatch" : false,
    "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
    "threadId" : 245,
    "threadPriority" : 5
  }
  , {
    "timeMillis" : 1469620840492,
    "thread" : "SimpleAsyncTaskExecutor-43",
    "level" : "DEBUG",
    "loggerName" : "MyLogger",
    "message" : "my log message",
    "endOfBatch" : false,
    "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
    "threadId" : 245,
    "threadPriority" : 5
  }

]

这个问题导致无法解析日志,因为 Gson 无法从该文件创建 List

您是否知道如何解决此问题而不用糟糕的技巧删除多余的 ] 并将其替换为逗号?

谢谢!

JSONLayout 之所以这样做是为了创建一个"well-formed" JSON 文档。您需要将每个文档放在自己的文件中(带有开始和结束括号)才能实现这一点,但此处并非如此。

您有两个选择:

  1. 对于 JSONLayout,设置 complete=false(您在示例中将其设置为 true),这将在没有“[”和“]”的情况下打印出来。然后你可以在调用 GSON 之前自己添加这些字符(因为文件不会真正有一个数组)。
  2. 创建您自己的 JSON布局(您需要扩展 AbstractStringLayout),使用 org.json:json 或 GS​​ON 等简单的东西来获取文件的字符串。

由于没有其他解决方案令人满意,我最终使用正则表达式来替换无效字符...

它非常安全,因为它会检查它是否不在两个双引号之间,但这显然不是理想的解决方案:

String content = new String(Files.readAllBytes(Paths.get(pathToLogFile)));
content = content.replaceAll("(\}\R{2}\]\R\{)(?=(?:(?:\.|[^\"\\])*\"(?:\.|[^\"\\])*\")*(?:\.|[^\"\\])*)", "}\n, {");
Files.write(Paths.get(pathToLogFile), content.getBytes());