Статьи

Разбор 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-хосте.