Skip to content

Repository files navigation

nginx-log-analyzer

Сервис разбора access-логов nginx: читает файл в потоке, раскладывает строки в PostgreSQL и отдаёт аналитику через REST API и дашборд.

Задача

Access-лог nginx — это плоский текст, по которому нельзя задать вопрос. Чтобы узнать, какие URL отдают 5xx чаще остальных или какой адрес выбирает больше всего трафика, приходится каждый раз собирать конвейер из grep, awk и sort, а на файле в несколько гигабайт это занимает минуты.

Сервис делает разбор один раз: строка лога превращается в запись со схемой, и дальше вопросы задаются запросами к базе.

Как работает

access.log ──► парсер (tail -f) ──► PostgreSQL ──► REST API ──► дашборд
                                                            └─► CLI

Парсер (apps/services/nginx_log_parser.py) открывает файл, встаёт в конец и опрашивает размер раз в секунду. Появились новые байты — читает и разбирает их регулярным выражением под combined-формат. Если файл стал короче, чем был, значит его провернул logrotate: позиция сбрасывается в ноль, чтение продолжается с начала нового файла.

Разобранная строка становится записью с полями: время с таймзоной, адрес клиента, метод, URI, версия протокола, код ответа, размер ответа, реферер, user-agent и идентификатор сервера. Записи разных серверов лежат в одной таблице и разделяются внешним ключом, поэтому один инстанс собирает логи с нескольких машин.

Архитектура

apps/
  api/v1/
    handlers/     роутеры: серверы, записи лога, аналитика
    cruds/        доступ к данным поверх SQLAlchemy
    models/       ORM-модели
    schemas/      схемы запроса и ответа
  auth/           JWT: выдача токенов, проверка, зависимости
  db/             движок, сессии, аннотированные поля
  services/       парсер access-лога
  utils/          healthcheck, перечисления
  settings.py     конфигурация на pydantic-settings
  main.py         сборка приложения
migrations/       Alembic
tests/

Обработчики не ходят в базу напрямую — между ними и SQLAlchemy лежит слой CRUD с общим базовым классом. Таблицы вынесены в отдельную схему Postgres nginx_parser_schema, а не в public: так сервис можно поселить в общую базу, не смешивая его таблицы с чужими.

API

Все ручки, кроме /health и /login, требуют токен — в заголовке Authorization или в куке.

метод путь назначение
POST /login получить пару токенов
DELETE /logout удалить токены из кук
GET /check_user текущий пользователь
GET /api/servers список серверов
GET /api/servers/{server_id} сервер вместе с его записями
GET /api/log-entries записи лога
GET /api/analytics/status-codes распределение по кодам ответа
GET /api/analytics/top-ips адреса по числу запросов и среднему размеру ответа
GET /api/analytics/top-urls самые запрашиваемые URI
GET /api/analytics/errors коды 4xx и 5xx
GET /api/analytics/traffic запросы, уникальные адреса, объём
GET /api/analytics/time-series ряд по корзинам заданной ширины
GET /health проверка живости

Аналитические ручки принимают hours — окно в часах от текущего момента. У time-series есть interval_minutes: ширина корзины, по которой группируется ряд.

Схема OpenAPI доступна на /docs.

Запуск

Нужны Python 3.11+, PostgreSQL 14+ и uv.

uv venv && source .venv/bin/activate
uv pip install ".[dev]"

cp env.example .env
createdb nginx_log_analyzer

alembic upgrade head
make run

API поднимется на http://localhost:8000, дашборд — на http://localhost:8000/static/index.html.

В контейнерах:

docker compose up -d --build

Образ собирается в два этапа, приложение работает не от root.

CLI

python cli.py monitor /var/log/nginx/access.log --server-id 1
python cli.py check /var/log/nginx/access.log

monitor запускает непрерывное чтение и запись в базу, check показывает размер файла и первые строки — удобно, чтобы убедиться, что формат распознаётся, до запуска мониторинга.

Проверки

make test                                    pytest с покрытием
ruff check apps tests migrations cli.py      линтер
ruff format --check apps tests               формат

67 тестов: разбор строк лога и краевые случаи формата, CRUD, аналитические запросы к живому Postgres, аутентификация, CLI, миграции и сквозной сценарий от файла до ответа API. Тестовые данные генерируются кодом, поэтому набор запускается на чистом клоне без подготовки файлов.

CI прогоняет линтер, формат, миграции и тесты на каждый push.

Ограничения

  • парсер рассчитан на combined-формат nginx; свой log_format потребует правки регулярного выражения
  • опрос файла по таймеру раз в секунду, без inotify: задержка до секунды и лишние системные вызовы на простое
  • пользователь один и задаётся конфигурацией, ролей и разграничения доступа нет
  • аналитика считается запросами по всей таблице без предагрегации: на десятках миллионов строк потребуются материализованные представления или сворачивание старых данных
  • ретеншн не реализован — таблица растёт, пока её не почистить руками
  • парсер запускается отдельным процессом через CLI и не управляется из API

About

Сервис разбора access-логов nginx: потоковый парсер, PostgreSQL, REST API с аналитикой

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages