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. Вам нужно поместить каждый документ в отдельный файл (с начальными и конечными скобками), чтобы это было правдой, а здесь это не так.

У вас есть два варианта:

  1. Для JSONLayout установите complete=false (в вашем примере это значение истинно), которое будет распечатано без '[' и ']'. Затем вы можете сами добавить эти символы перед вызовом GSON (так как файл не будет иметь массив).
  2. Создайте свой собственный JSONLayout (вам нужно расширить AbstractStringLayout), используя что-то простое, например org.json:json или GSON, чтобы получить строку для файла.
Другие вопросы по тегам