Объединение нескольких файлов журналов по дате, включая многострочные

У меня есть несколько журналов, содержащих строки, начинающиеся с метки времени, так что следующее работает, как и ожидалось, для их объединения:

cat myLog1.txt myLog2.txt | sort -n > combined.txt

Проблема в том, что myLog2.txt также может содержать строки без метки времени (например, трассировки стека Java). Есть ли простой способ без каких-либо пользовательских сценариев объединить их и сохранить многострочный контент?

Пример myLog1.txt

11:48:18.825 [main] INFO  org.hibernate.cfg.Environment - HHH000206: hibernate.properties not found
11:48:55.784 [main] INFO  o.h.tool.hbm2ddl.SchemaUpdate - HHH000396: Updating schema

Пример myLog2.txt

11:48:35.377 [qtp1484319352-19] ERROR c.w.b.c.ControllerErrorHandler -
org.springframework.beans.TypeMismatchException: Failed to convert value of type   'java.lang.String' to required type 'org.joda.time.LocalDate'; nested exception is    org.springframework.core.convert.ConversionFailedException: Failed to convert from type     java.lang.String to type @org.springframework.web.bind.annotation.RequestParam   @org.springframework.format.annotation.DateTimeFormat org.joda.time.LocalDate for value    '[2013-03-26]'; nested exception is java.lang.IllegalArgumentException: Invalid format: "    [2013-03-26]"
    at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:68) ~[spring-beans-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:45) ~[spring-beans-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:595) ~[spring-context-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:98) ~[spring-web-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77) ~[spring-web-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162) ~[spring-web-3.2.1.RELEAS

Ожидаемый результат

11:48:18.825 [main] INFO  org.hibernate.cfg.Environment - HHH000206: hibernate.properties not found
11:48:35.377 [qtp1484319352-19] ERROR c.w.b.c.ControllerErrorHandler -
org.springframework.beans.TypeMismatchException: Failed to convert value of type   'java.lang.String' to required type 'org.joda.time.LocalDate'; nested exception is    org.springframework.core.convert.ConversionFailedException: Failed to convert from type     java.lang.String to type @org.springframework.web.bind.annotation.RequestParam   @org.springframework.format.annotation.DateTimeFormat org.joda.time.LocalDate for value    '[2013-03-26]'; nested exception is java.lang.IllegalArgumentException: Invalid format: "    [2013-03-26]"
    at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:68) ~[spring-beans-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:45) ~[spring-beans-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:595) ~[spring-context-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:98) ~[spring-web-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77) ~[spring-web-3.2.1.RELEASE.jar:3.2.1.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162) ~[spring-web-3.2.1.RELEAS
11:48:55.784 [main] INFO  o.h.tool.hbm2ddl.SchemaUpdate - HHH000396: Updating schema

Спасибо, Марко.


person Marco Behler    schedule 07.04.2013    source источник
comment
Спасибо за пример @marco. Помогли мне решить такую ​​же проблему для себя.   -  person yegeniy    schedule 08.01.2014


Ответы (5)


Я боролся с той же проблемой, и, наконец, я думаю, что понял. Попробуйте сделать это так:

sort -nbms -k1.1,1.2 -k1.4,1.5 -k1.7,1.8 -k1.10,1.12 myLog1.txt myLog2.txt > combined.txt

Это все еще не совсем понятно для меня самого, но я попытаюсь дать некоторые пояснения. Согласно справочным страницам используемые переключатели означают:

-n, --numeric-sort - сравнивать по числовому значению строки.

-b, --ignore-leading-blanks — игнорировать начальные пробелы.

-s, --stable — стабилизировать сортировку, отключив сравнение последней инстанции

-m, --merge — объединить уже отсортированные файлы; не сортировать

-k, --key=POS1[,POS2] — начать ключ с POS1 (исходная точка 1), закончить его с POS2 (конец строки по умолчанию)

  • файлы журналов уже упорядочены, поэтому нам не нужно их снова сортировать, а только определить, какая строка куда идет при слиянии. Вот почему -m. Крайне важно предотвратить скремблирование трассировки стека.
  • -b в этом случае не нужен, так как каким-то образом комбинация -n и -m предотвращает кластеризацию строк трассировки стека. Я оставил это на всякий случай, так как большинство строк трассировки стека начинаются с пробелов.
  • -n, по-видимому, перестает сравнивать ключ всякий раз, когда в ключе есть нечисловой символ. Это второй важный момент для сохранения трассировки стека. Важно то, что если бы это было -n -k1,1, файлы журнала сортировались бы только по часам, поскольку двоеточие не является числом. Кроме того, -n ускоряет числовое сравнение, поэтому мы все равно хотели бы его иметь.
  • проблема, упомянутая в предыдущем пункте, решается указанием на определенные позиции символов в каждом ключе, поэтому -k1.1,1.2 (первая и вторая цифры часа) -k1.4,1.5 (первая и вторая цифры минут) и так далее. Первая цифра перед точкой всегда равна «1», поскольку она указывает на первый столбец строки файла (в нашем случае это время). Вкратце это -kA,B, где A и B — позиции столбцов в заданной строке (по умолчанию строки разделяются пробелами). Используемый формат A и B: .. Имейте в виду, что всякий раз, когда между A и B есть нечисловой символ, все после него будет игнорироваться при сравнении, если используется -n.
  • -s отключает поведение по умолчанию, а именно: всякий раз, когда ключи, по которым выполняется сравнение, являются одними и теми же, выполняется полное сравнение строк. Мы не хотим, чтобы это сохраняло исходный порядок записей в журнале. Однако не уверен, что это необходимо с -m.
person topr    schedule 26.11.2014
comment
Молодец @topr! Если ваш формат журнала не является простой числовой сортировкой, вам придется бороться с флагом -k. Я обнаружил, что проще изменить временную метку в удобном для сортировки формате даты и времени (например, ггггММддЧЧммссССС), но его труднее читать. - person yegeniy; 26.11.2014

Нет, это невозможно сделать с помощью простой команды ИМХО.

Но - вот скрипт для этого (это был вызов...)

@ECHO OFF
SETLOCAL
:: First log to tempfile
COPY /y mylog.txt "%temp%\combinedlogs.tmp" >NUL
(
FOR /f "delims=" %%i IN (mylog2.txt) DO (
 SET line=%%i
 ECHO %%i|FINDSTR /b /r "[012][0-9]:[0-5][0-9]:[0-5][0-9]\.[0-9][0-9][0-9]" >NUL
 IF ERRORLEVEL 1 (
  SETLOCAL ENABLEDELAYEDEXPANSION
 ECHO(!stamp:~0,12!!count!!line!
  ENDLOCAL
  SET /a count+=1
 ) ELSE (
 SET /a count=100
 ECHO %%i
 SET stamp=%%i
 )
)
)>>"%temp%\combinedlogs.tmp"
(
FOR /f "delims=" %%i IN ('SORT "%temp%\combinedlogs.tmp"') DO (
 SET line=%%i
 SETLOCAL enabledelayedexpansion
 IF "!line:~12,1!"==" " (ECHO(%%i) ELSE (ECHO(!line:~15!)
 ENDLOCAL
)
)>combinedlogs.txt
DEL "%temp%\combinedlogs.tmp" /F /Q

Скопируйте первый журнал с записями с отметками времени во временный файл
. Обработайте второй файл,

  • прямой вывод любой строки с меткой времени, сохранение строки метки и установка 3-значного счетчика
  • Вывод части штампа+счетчика+исходного текста для других строк и сброс счетчика

Таким образом, временный файл

Timestamp1 line1 from file1
..
Timestampn linen from file1
timestampA line1 from file2 with timestamp
timestampA100 UNtimestamped line2from file2
timestampA101 UNtimestamped line3from file2
timestampB line4 from file2 with timestamp
timestampB100 UNtimestamped line5from file2
timestampB101 UNtimestamped line6from file2
...

Сортировка результата и повторная обработка
Строка без пробела в 13-м символе является строкой без метки времени из второго файла, поэтому

  • вывести все, кроме первых 15 символов (временная метка 12 символов + 3 для счетчика)
  • в противном случае строка с отметкой времени, поэтому выведите все.

Сделанный!

person Magoo    schedule 08.04.2013

Вот один из способов сделать это в оболочке bash с помощью простого слияния файлов (вместо дорогостоящего повторения — поскольку файлы журналов уже отсортированы). Это важно для огромных файлов размером в сотни мегабайт и более, как это часто бывает с реальными файлами журналов.

Это решение предполагает, что в ваших журналах нет байтов NUL, что верно для каждого файла журнала, с которым я сталкивался, с различными наборами символов.

Основная мысль:

  1. Объединить все многострочные в отдельные строки, заменив эти новые строки на NUL в каждом входном файле.
  2. Сделайте sort -m для замененных файлов, чтобы объединить их
  3. Замените NUL обратно на новые строки в объединенном результате

Поскольку первый шаг выполняется несколько раз, я дал ему псевдоним:

alias a="awk '{ if (match(\$0, /^[0-9]{2}:[0-9]{2}:[0-9]{2}\\./, _))\
{ if (NR == 1) printf \"%s\", \$0; else printf \"\\n%s\", \$0 }\
else printf \"\\0%s\", \$0 } END { print \"\" }'"

Вот команда, которая выполняет все 3 шага:

sort -m <(a myLog1.txt) <(a myLog2.txt) | tr '\0' '\n'

Подробнее см. https://superuser.com/a/838446/125379.

person Evgeniy Berezovsky    schedule 12.11.2014

Вы должны использовать merge, stable, ignore-leading-blanks, numeric-sort и легко сортируемый формат даты и времени (например, yyyyMMddHHmmssSSS) в файлах журнала.

Итак, я изменил формат вашего журнала, чтобы его было легче сортировать, в результате чего sort -bsnm log1 log2:

 $ cat -n log1 log2 && sort -m -b -n -s log1 log2
      1 114818825 [main] INFO  org.hibernate.cfg.Environment - HHH000206 hibernate.properties not found
      2 114855784 [main] INFO  o.h.tool.hbm2ddl.SchemaUpdate - HHH000396 Updating schema
      1 114835377 [qtp1484319352-19] ERROR c.w.b.c.ControllerErrorHandler -
      2 org.springframework.beans.TypeMismatchException Failed to convert value of type   'java.lang.String' to required type 'org.joda.time.LocalDate'; nested exception is    org.springframework.core.convert.ConversionFailedException Failed to convert from type     java.lang.String to type @org.springframework.web.bind.annotation.RequestParam   @org.springframework.format.annotation.DateTimeFormat org.joda.time.LocalDate for value    '[2013-03-26]'; nested exception is java.lang.IllegalArgumentException Invalid format "    [2013-03-26]"
      3     at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java68) ~[spring-beans-3.2.1.RELEASE.jar3.2.1.RELEASE]
      4 at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java45) ~[spring-beans-3.2.1.RELEASE.jar3.2.1.RELEASE]
      5 at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java595) ~[spring-context-3.2.1.RELEASE.jar3.2.1.RELEASE]
      6 at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java98) ~[spring-web-3.2.1.RELEASE.jar3.2.1.RELEASE]
      7 at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java77) ~[spring-web-3.2.1.RELEASE.jar3.2.1.RELEASE]
      8 at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java162) ~[spring-web-3.2.1.RELEAS
      9 
 114818825 [main] INFO  org.hibernate.cfg.Environment - HHH000206 hibernate.properties not found
 114835377 [qtp1484319352-19] ERROR c.w.b.c.ControllerErrorHandler -
 org.springframework.beans.TypeMismatchException Failed to convert value of type   'java.lang.String' to required type 'org.joda.time.LocalDate'; nested exception is    org.springframework.core.convert.ConversionFailedException Failed to convert from type     java.lang.String to type @org.springframework.web.bind.annotation.RequestParam   @org.springframework.format.annotation.DateTimeFormat org.joda.time.LocalDate for value    '[2013-03-26]'; nested exception is java.lang.IllegalArgumentException Invalid format "    [2013-03-26]"
     at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java68) ~[spring-beans-3.2.1.RELEASE.jar3.2.1.RELEASE]
 at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java45) ~[spring-beans-3.2.1.RELEASE.jar3.2.1.RELEASE]
 at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java595) ~[spring-context-3.2.1.RELEASE.jar3.2.1.RELEASE]
 at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java98) ~[spring-web-3.2.1.RELEASE.jar3.2.1.RELEASE]
 at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java77) ~[spring-web-3.2.1.RELEASE.jar3.2.1.RELEASE]
 at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java162) ~[spring-web-3.2.1.RELEAS

 114855784 [main] INFO  o.h.tool.hbm2ddl.SchemaUpdate - HHH000396 Updating schema

Как сказано в @Magoo answer, способ форматирования даты и времени ваших журналов в настоящее время трудно отсортировать.

person yegeniy    schedule 08.01.2014
comment
Это испортит многострочные записи журнала, «сортируя» трассировки стека, не так ли? - person topr; 24.11.2014
comment
Привет @topr, прошло некоторое время, но, насколько я помню, многострочные трассировки стека сохраняются с помощью sort -bsnm log1 log2.... Я бы не удивился, если бы были крайние случаи, но для примера, предоставленного @marco, и моего собственного использования это сработало на удивление хорошо. Существует множество инструментов для просмотра журналов, если вам нужно что-то более сложное. - person yegeniy; 25.11.2014
comment
Спасибо за Ваш ответ. Трассировки стека сохраняются, но с этими переключателями все равно сохраняются все строки. Никакой сортировки нет, только слияние. Я использую инструмент просмотра журнала, но мне нужно слияние с сортировкой, поскольку у меня есть несколько файлов журнала, и гораздо удобнее использовать инструмент с одним файлом. - person topr; 25.11.2014
comment
Привет @topr, рассмотрите возможность написания собственного вопроса о стеке с примером того, что вы ищете. По крайней мере, для примера в этом вопросе это должно работать. Имейте в виду, что каждая строка должна начинаться с сортируемого числового представления времени. Имейте в виду, что журналы должны начинаться с легко сортируемого формата даты и времени (например, ггггММддЧЧммссССС). То есть строки строк журнала 1 начинаются с 114818825 и 114855784, а строки журнала 2 начинаются с 114835377. Отсортированная версия выходит 114818825, 114835377, 114855784, начиная с 18825‹35377‹55784. - person yegeniy; 26.11.2014
comment
Не уверен, что новый вопрос не будет дубликатом, поскольку он будет таким же, как в этом случае. Строки моего файла журнала начинаются с даты и времени, например: 2014-11-25 06:43:20,991 INFO... Это сортируемый формат, не так ли? Однако есть также строки для записей журнала с трассировкой стека точно так же, как в примере выше. Не уверен, что -m должен делать, но он вообще отключает сортировку (ничем не отличается от использования cat). Без -m он сортирует, но группирует все строки для всех трассировок вверху, что делает такую ​​сортировку бесполезной. Я не понимаю вашего ответа, так как не похоже, что sort может сортировать файл журнала с многострочными записями. - person topr; 26.11.2014

Инструмент с открытым исходным кодом (Java GitHub) позволяет вам объединить файлы журналов с различными форматами, включая многострочные, в объединенный файл.

Инструмент позволяет сдвигать время записи в лог-файле. Это может быть полезно, когда файлы приходят из разных часовых поясов.

Это также позволяет генерировать дополнительную информацию в объединенный файл, например, имена приложений или метки времени в едином формате, см. пример.

Инструмент можно использовать как инструмент командной строки или Библиотека Java. Примечание: я автор.

person Kyrylo Semenko    schedule 26.01.2020