Log4J - JsonLayout и RollingFileAppender генерируют недопустимый JSON
Я пытаюсь сохранить свои журналы в файлах JSON, используя Log4J (2.6.2). Я использую JsonLayout
в RollingFileAppender
и работает нормально, пока я не пытаюсь добавить файл, который уже был написан ранее.
Вот мой код для настройки макета и приложения:
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
из этого файла.
Есть ли у вас какие-либо идеи о том, как решить эту проблему, не делая дрянной хак, удаляя лишние ]
и заменить его запятой?
Спасибо!
2 ответа
Поскольку никакое другое решение не удовлетворяло меня, я использовал регулярное выражение для замены недопустимых символов...
Это довольно безопасно, так как он проверяет, не находится ли он между двумя двойными кавычками, но это, очевидно, не идеальное решение:
String content = new String(Files.readAllBytes(Paths.get(pathToLogFile)));
content = content.replaceAll("(\\}\\R{2}\\]\\R\\{)(?=(?:(?:\\.|[^\"\\\\])*\"(?:\\.|[^\"\\\\])*\")*(?:\\.|[^\"\\\\])*)", "}\n, {");
Files.write(Paths.get(pathToLogFile), content.getBytes());
Причина, по которой JSONLayout делает это, заключается в создании "правильно сформированного" документа JSON. Вам нужно поместить каждый документ в отдельный файл (с начальными и конечными скобками), чтобы это было правдой, а здесь это не так.
У вас есть два варианта:
- Для JSONLayout установите complete=false (в вашем примере это значение истинно), которое будет распечатано без '[' и ']'. Затем вы можете сами добавить эти символы перед вызовом GSON (так как файл не будет иметь массив).
- Создайте свой собственный JSONLayout (вам нужно расширить AbstractStringLayout), используя что-то простое, например org.json:json или GSON, чтобы получить строку для файла.