Разбор HTTP лога на Lua
Обновлено 14.10.2026
Счётчики запросов, ошибок и объёма ответов; отчёт на учебном логе.
Напишем отчёт по журналу запросов: общее число обращений, ошибки 4xx и 5xx, объём ответов и пять самых частых адресов. Для примера достаточно Lua - дополнительные библиотеки не нужны.
Урок продолжает подключение по SSH. Понадобятся Linux-хост с файлом ssh-synapse.conf и работающая VM. В конце настроим cron, чтобы отчёт обновлялся сам.
Подготовьте файлы
На Linux-хосте скачайте скрипт и учебный лог в папку с ssh-synapse.conf:
curl -fLo log-summary.lua https://synapseos.ru/static/tutorials/log-summary.lua
curl -fLo tutorial-access.log https://synapseos.ru/static/tutorials/tutorial-access.log
В гостевой консоли создайте каталоги:
mkdir -p /root/bin /var/log
lua -v
На хосте откройте SFTP:
sftp -F ./ssh-synapse.conf synapse-tutorial
Внутри SFTP выполните:
put log-summary.lua /root/bin/log-summary.lua
put tutorial-access.log /var/log/tutorial-access.log
bye
Формат входных данных
Строка учебного лога:
10.0.2.2 - - [12/Oct/2026:12:00:00 +0000] "GET / HTTP/1.1" 200 120
После адреса клиента, двух служебных полей и даты идут запрос в кавычках, код HTTP и размер ответа. Скрипт допускает дополнительные поля после размера, например Referer и User-Agent. Значение - вместо размера учитывается как ноль байтов; фактический объём такого ответа неизвестен.
В файле пять запросов и одна строка другого формата. Её парсер пропустит и учтёт в счётчике Skipped. Пустые строки в этот счётчик не входят.
Как устроен скрипт
io.open открывает входной файл, а source:lines() читает его построчно. Из каждой строки извлекаются запрос, статус и размер:
local request, code, size = line:match('^%S+%s+%S+%s+%S+%s+%b[]%s+"([^"]*)"%s+(%d%d%d)%s+(%S+)')
local method, path = (request or ''):match('^([A-Z]+)%s+(%S+)%s+HTTP/%d+%.%d+$')
Это шаблоны Lua: %S обозначает непробельный символ, %s - пробел, %d - цифру, %b[] - фрагмент в квадратных скобках. Парсер ожидает запрос с методом, адресом и версией HTTP вида 1.1. Произвольные журналы ядра или приложения под этот формат не подходят.
Для корректной строки увеличиваются счётчики статусов и адресов. Пути сортируются по числу запросов, а при равенстве - по алфавиту. Строка запроса используется как данные и не выполняется как команда.
Готовый отчёт сначала записывается в файл с суффиксом .tmp, затем заменяет прежний через os.rename. Если входной лог не найден, скрипт завершается с ошибкой до записи отчёта. Полный код доступен в файле Lua.
Выполните парсер
В гостевой консоли:
lua /root/bin/log-summary.lua /var/log/tutorial-access.log /var/log/access-summary.txt
cat /var/log/access-summary.txt
Или с Linux-хоста:
ssh -F ./ssh-synapse.conf -n synapse-tutorial '/bin/lua /root/bin/log-summary.lua /var/log/tutorial-access.log /var/log/access-summary.txt'
ssh -F ./ssh-synapse.conf -n synapse-tutorial 'cat /var/log/access-summary.txt'
Для учебного файла получите:
Requests: 5
Skipped: 1
Response bytes: 400
4xx: 1
5xx: 1
Statuses:
200: 3
404: 1
500: 1
Top paths:
2 /
1 /api
1 /missing
1 /style.css
В начале отчёта также указаны имя источника и время формирования в UTC. Скрипт каждый раз пересчитывает весь файл; он не дополняет прежние суммы и не читает архивы ротации. Адреса с разными параметрами запроса считаются отдельными путями.
Подключите свой журнал
Если используете darkhttpd из инструкции сайта, попробуйте /var/log/web-access.log вместо учебного файла. Сначала сравните формат его строк с примером. При большом Skipped проверьте шаблон: это число пропущенных строк, а не HTTP-ошибок.
Храните отчёт вне каталога публичного сайта: реальные URL могут содержать личные данные или токены. Скрипт и входной лог остаются также на Linux-хосте.