Утилита Access Log Tabulator
Работа с логами в формате Apache Combined Log создаёт для меня проблемы уже не первый год. Как показывает практика, чаще всего мне нужно работать с логами либо AS-IS, в текстовом формате, либо нужно их загрузить и обрабатывать уже в БД.
Данные в таком случае нужно подготовить. Проблема: у Combined Log нет единого разделителя. Поля request line, referrer и user-agent будут в двойных кавычках, ведь они могут содержать пробелы. Поле time будет в квадратных скобках.
Сортировать данные в поле time как простой текст не получится. Вот наглядный пример формата этого поля (в стандартных конфигурациях веб-серверов):
$ LC_ALL=C date +'%d/%b/%Y:%H:%M:%S %z'
03/Sep/2024:09:57:04 +0300
Как видно, день, месяц и год идут именно в таком порядке. Месяц не в численном, а буквенном виде. Именно из-за этого сортировка с помощью sort невозможна без дополнительных преобразований. А вот формат ISO 8601 лишён всех этих недостатков и позволяет сортировать даты как простой текст:
$ date -Is
2024-09-03T09:57:04+03:00
Две эти проблемы, а именно отсутствие универсального разделителя полей и неудобный формат времени, решаются либо с точки зрения конфигурации, либо дополнительной обработкой.
Иногда просто невозможно изменить формат журнала доступа у HTTP-сервера. Тогда необходимо писать пост-обработчики. Можно обработать данные с помощью sed, ripgrep и комбинации других инструментов.
Но, задача эта универсальна, хочется иметь один простой и быстрый инструмент, который разделит поля с помощью TAB, и преобразует даты в формат ISO 8601.
Для решения этой задачи я написал на C простую программу [Access Log Tabulator]. Это примитивный конвертер, который перегонит данные в формат Tab-Separated Values, не забывая о конвертации поля time в формат, подобный ISO 8601.
Компилировать утилиту предельно просто (флаги gcc можно добавить по вкусу):
$ gcc -o access_log_tabulator{,.c}
$ du -h access_log_tabulator
20K access_log_tabulator
$ ldd access_log_tabulator
linux-vdso.so.1 (0x00007f3478f57000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3478d55000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3478f59000)
Никаких внешних зависимостей нет, да и странно их иметь для такого “топорного” инструмента посимвольного обхода строки. Использование также предельно просто:
$ ./access_log_tabulator < access.log
Если Вам необходимо объединить множество логов в один, то это тоже возможно:
$ zcat -f *.access.log* \
| ./access_log_tabulator \
| (sed -u 1q; sort) \
> sorted.tsv
В данном случае zcat позволяет совместить все логи. И в формате GZIP и без сжатия. С помощью sed и sort можно отсортировать все строки, за исключением первой, содержащей заголовки колонок.
Если нужно работать в реальном времени, табулятор это также позволит:
$ tail -f access.log \
| ./access_log_tabulator \
> unsorted.tsv
Надеюсь, эта утилита кому-нибудь пригодится. Данные о лицензии, моих флагах компиляции, вариантах использования и граничных условиях можно найти в репозитории на GitHub.
Журнал изменений
1 января 2026 г.: перенёс исходники на GitHub.