Тема: Bash/Perl: logmerge - программа слияния лог-файлов
Казалось бы простая задача - слить несколько лог-файлов в один и отсортировать. Однако задача несколько усложняется тем, что одна запись лог-файла не равна одной строке, то есть запись может занимать несколько строк. Это хорошо известно тем, кто работал с java приложениями. Там стектрейсы могу занимать по два десятка строк, а это одна запись.
В интернете попадались аналоги, но либо они были несвободными, либо ориентированы на специфический формат записей лог-файлов (например только веб-серверов), либо возможность работать с многострочными записями была не очевидна. Подгонка под наши нужды возможно заняла бы больше времени чем разработка с нуля.
Объединение и хронологическая сортировка файлов требуется для анализа событий двух и более взаимодействующих процессов. При простой сортировке двух файлов соседние строки одной записи могут потеряться.
Другая проблема заключается в том, что время двух записей может совпадать (например две записи от нескольких нитей, threads, или две последовательных записи одной нити). В данном случае важно сохранить последовательность записей в пределах одного файла.
Скрипт был написан. Для его работы требуются Bash+Perl. Требуется gzip для чтения сжатых файлов. То есть, скрипт, в первую очередь ориентирован для работы в Unix. Также он может работать и в Windows при наличии установленного Cygwin. Никаких специфических требований к библиотекам Perl нет. Разрабатывалось и тестировалось в следующих конфигурациях:
Windows Vista+Cygwin
Bash 3.2.49
Perl 5.10.0Red Hat Linux
Bash 2.05
Perl 5.8.9
Хотя скрипт писался для собственных нужд, я обнаружил, что его можно расширить для большинства текстовых лог-файлов. В качестве бонуса я добавил пару опций, которые позволяют работать с логами Apache (access.log и error.log). Далее несколько примеров.
1.
./logmerge --apache-error ./error.log* > all.logОбъединить все error.log* файлы, включая упакованные командой gzip и сохранить в один результирующий файл. Опция --apache-error рассматривает, что строки содержат временную метку в следующем фоормате
[Fri Apr 23 22:14:21 2010] <...>
2.
find /export/home/ -name 'access.log' | xargs ./logmerge -f -n --apache-access > all.logнайти все последние access.log файлы и объединить их в один отсортировав записи хронологически. В начале каждой строки добавляется имя исходного файла и номер строки (!) в нем. Временная метка определяется так:
<...> [15/Feb/2008:14:18:49 +0300] <...>
3.
./logmerge -f -n log/*.log | gzip -c > all.gzПоследний пример - образец того ради чего все это затевалось. Скрипт аналогично предыдущему примеру "сливает" несколько файлов в один добавляя в начало строки имя файла и номер строки. Далее результат передается команде gzip, которая создает сжатый файл. Лог-файл может содержать строки подобные этой:
05/21/2012 21:54:41.070 <the rest of the entry>
java.lang.Throwable
at boo.hoo.StackTrace.bar(StackTrace.java:223)
at boo.hoo.StackTrace.foo(StackTrace.java:218)
at boo.hoo.StackTrace.main(StackTrace.java:54)
...
Здесь описана лишь часть опций скрипта. Архив скрипта доступен на странице http://code.google.com/p/logmerge/. Критика и пожелания приветствуются.

