Диагностика запросов Nginx по коду ответа, времени upstream и журналу ошибок
DevOps

Логи Nginx: диагностика 4xx, 5xx и медленных запросов

Настраиваем полезный access_log Nginx, читаем error_log, измеряем upstream timings и разбираем 404, 499, 502, 504 без записи секретов.

Содержание

Когда Nginx возвращает 502, код сообщает только о сбое при работе с приложением. Причину уточняют два журнала: access log связывает адрес, статус и длительность запроса, а error log записывает ошибку соединения, доступа к файлу или обработки конфигурации.

Начните с точного времени и одного воспроизводимого запроса. Затем найдите активные журналы, добавьте измерения работы upstream и сопоставьте запись Nginx с журналом приложения. Пароли, cookies, заголовок Authorization и тело запроса для этого не нужны и не должны попадать в лог.

Найдите активные журналы

Пути журналов могут переопределяться на уровнях http, server и location. Поэтому сначала найдите фактически подключённые директивы и последние сообщения службы:

sudo nginx -T 2>/dev/null | grep -E 'access_log|error_log|log_format'
systemctl status nginx --no-pager
sudo journalctl -u nginx --since "15 minutes ago"

nginx -T печатает всю собранную конфигурацию, поэтому выполняйте его в защищённой сессии: include могут содержать внутренние адреса. Не публикуйте вывод целиком.

В пакетной установке файлы часто находятся в /var/log/nginx, но полагайтесь на активную конфигурацию. При контейнерном запуске журналы могут направляться в stdout/stderr.

Добавьте формат с таймингами

Директива log_format задаётся в контексте http. Следующий формат добавляет время всего запроса, адрес upstream, его статус и три отдельных этапа ожидания:

log_format upstream_timing '$remote_addr [$time_iso8601] '
    '"$request" status=$status bytes=$body_bytes_sent '
    'rt=$request_time ua="$http_user_agent" '
    'upstream=$upstream_addr us=$upstream_status '
    'uct=$upstream_connect_time uht=$upstream_header_time '
    'urt=$upstream_response_time rid=$request_id';

access_log /var/log/nginx/access.log upstream_timing;

$request_time включает обработку запроса Nginx до отправки последних байтов клиенту. $upstream_connect_time отражает соединение, $upstream_header_time — ожидание заголовка, $upstream_response_time — получение ответа upstream. При повторных попытках значения могут содержать несколько элементов, поэтому парсер должен поддерживать этот формат.

User-Agent полезен для диагностики, но создаёт дополнительный объём и пользовательские данные. Если он не нужен, исключите. Строка $request включает query string; токены не должны передаваться в URL. Для чувствительных endpoint рассмотрите отдельный минимальный формат.

Свяжите запрос с приложением

Nginx создаёт $request_id — идентификатор одного запроса. Передайте его приложению и верните в ответе, чтобы связать записи двух систем без поиска по адресу и секунде:

proxy_set_header X-Request-ID $request_id;
add_header X-Request-ID $request_id always;

Приложение должно безопасно записывать этот ID в свой журнал. Если внешний proxy уже выдаёт идентификатор, решите, доверять ли ему и как валидировать формат; не позволяйте произвольной длинной строке раздувать журналы.

Ответный заголовок помогает поддержке, но не должен раскрывать внутренний адрес или stack trace. Request ID — корреляционный ключ, не средство авторизации.

Как читать основные ошибки

404 Not Found

Смотрите выбранный server, URI, document root и порядок location. Для статики проверьте существование файла и права каждого каталога пути. Для приложения сравните его route и Nginx fallback. Статья про root, alias и try_files помогает разобрать выбор файла.

499

Клиент закрыл соединение. Сравните $request_time, upstream timings и timeout внешнего proxy. Если upstream почти всегда отвечает позже клиентского предела, исправляйте приложение или переводите долгую работу в фон. Один 499 от ушедшего пользователя не равен аварии.

502 Bad Gateway

В error log ищите connect() failed, permission denied, отсутствие socket, premature close или invalid header. Затем проверьте слушающие порты, состояние службы и её сообщения за тот же интервал:

sudo ss -ltnp
systemctl status myapp.service --no-pager
sudo journalctl -u myapp.service --since "15 minutes ago"

Не перезапускайте всё до чтения сообщения: у каждой причины своё исправление.

504 Gateway Timeout

Сравните uct, uht и urt. Долгий connect указывает на сеть или очередь соединений, долгий header — на начало обработки приложения, долгий полный ответ — на вычисление или передачу тела. proxy_read_timeout измеряет паузу между чтениями, поэтому его увеличение не является оптимизацией.

413 и 408

413 связан с размером тела, 408 — с чтением клиентского запроса. Для них используйте руководство по лимитам и таймаутам, а не настройки upstream наугад.

Фильтрация в командной строке

Для короткого окна можно прочитать конец error log и отфильтровать несколько серверных кодов в access log. Пути замените значениями из действующей конфигурации:

sudo tail -n 200 /var/log/nginx/error.log
sudo grep ' 50[234] ' /var/log/nginx/access.log | tail -n 50

Формат может отличаться, поэтому текстовый grep не заменяет парсер. Не запускайте тяжёлый поиск по всем архивам на заполненном production-диске. Сначала ограничьте файл и время.

Проверьте, сколько места занимают журналы и как пакет собирается их ротировать. Ключ -d у logrotate показывает план без изменения файлов:

sudo du -h /var/log/nginx/*
sudo logrotate -d /etc/logrotate.d/nginx

Режим -d выполняет отладку без изменений. После ротации Nginx должен корректно переоткрыть файлы штатным механизмом пакета. Простое удаление активного журнала может не освободить место, пока процесс держит дескриптор.

Проверка и откат

После добавления формата проверьте конфигурацию, выполните reload, запросите известный URL и прочитайте новую строку access log:

sudo nginx -t
sudo systemctl reload nginx
curl -I https://example.com/health
sudo tail -n 5 /var/log/nginx/access.log

Убедитесь, что поля появляются, пути доступны Nginx, а объём одной строки приемлем. Затем воспроизведите известные safe-сценарии 200 и 404. Ошибку upstream тестируйте только в контролируемой среде.

Если формат мешает сборщику или растёт слишком быстро, верните предыдущий access_log, проверьте конфигурацию и reload. Полезность журнала измеряется тем, насколько быстро он приводит к причине без утечки данных.

Первоисточники

Рекламное местоВаша компания здесьРазместить рекламу

Самопроверка

Проверьте, что материал усвоен

Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.

01Какая переменная показывает полное время получения ответа от upstream?
02Что полезно сделать при 502?
03Зачем использовать request ID?

Разбираем коротко

Частые вопросы

Чем access_log отличается от error_log Nginx?

Access log записывает обработанные запросы, статусы, объёмы и выбранные переменные. Error log содержит сообщения о проблемах конфигурации, файлах, соединениях с upstream и работе процессов Nginx.

Что означает статус 499 в журнале Nginx?

Это код Nginx для ситуации, когда клиент закрыл соединение до завершения ответа. Причиной может быть уход пользователя, таймаут внешнего proxy или слишком медленный backend; нужен анализ времени и соседних журналов.

Можно ли записывать тело запроса и Authorization для удобной диагностики?

Обычно нельзя: в них могут находиться пароли, токены и персональные данные. Логируйте технические метаданные и безопасный request ID, а чувствительную отладку выполняйте ограниченно и с последующим удалением.