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 文档。您需要将每个文档放在自己的文件中(带有开始和结束括号)才能实现这一点,但此处并非如此。
您有两个选择:
- 对于 JSONLayout,设置 complete=false(您在示例中将其设置为 true),这将在没有“[”和“]”的情况下打印出来。然后你可以在调用 GSON 之前自己添加这些字符(因为文件不会真正有一个数组)。
- 创建您自己的 JSON布局(您需要扩展 AbstractStringLayout),使用 org.json:json 或 GSON 等简单的东西来获取文件的字符串。
由于没有其他解决方案令人满意,我最终使用正则表达式来替换无效字符...
它非常安全,因为它会检查它是否不在两个双引号之间,但这显然不是理想的解决方案:
String content = new String(Files.readAllBytes(Paths.get(pathToLogFile)));
content = content.replaceAll("(\}\R{2}\]\R\{)(?=(?:(?:\.|[^\"\\])*\"(?:\.|[^\"\\])*\")*(?:\.|[^\"\\])*)", "}\n, {");
Files.write(Paths.get(pathToLogFile), content.getBytes());
我正在尝试使用 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 文档。您需要将每个文档放在自己的文件中(带有开始和结束括号)才能实现这一点,但此处并非如此。
您有两个选择:
- 对于 JSONLayout,设置 complete=false(您在示例中将其设置为 true),这将在没有“[”和“]”的情况下打印出来。然后你可以在调用 GSON 之前自己添加这些字符(因为文件不会真正有一个数组)。
- 创建您自己的 JSON布局(您需要扩展 AbstractStringLayout),使用 org.json:json 或 GSON 等简单的东西来获取文件的字符串。
由于没有其他解决方案令人满意,我最终使用正则表达式来替换无效字符...
它非常安全,因为它会检查它是否不在两个双引号之间,但这显然不是理想的解决方案:
String content = new String(Files.readAllBytes(Paths.get(pathToLogFile)));
content = content.replaceAll("(\}\R{2}\]\R\{)(?=(?:(?:\.|[^\"\\])*\"(?:\.|[^\"\\])*\")*(?:\.|[^\"\\])*)", "}\n, {");
Files.write(Paths.get(pathToLogFile), content.getBytes());