Перейти к содержанию

Журналы и проверка здоровья сайта

После публикации важно не только знать выбранный каталог, но и понимать, что происходит с запросами. Журнал помогает восстановить ход ошибки, а небольшой индикатор здоровья — быстро получить ограниченное наблюдение. В этом уроке соединим оба средства на статическом release-lab и разберём границы их выводов.

Предположим, что посетитель сообщает: старая статья иногда открывается без стиля. У нас есть время сообщения, адрес и идентификатор текущего выпуска. Этого ещё недостаточно для причины, однако достаточно, чтобы искать конкретные запросы. Мы не будем начинать с общих слов «сервер тормозит»: сначала установим, какой ответ получил HTML и какой — ресурс страницы.

Два журнала отвечают на разные вопросы

Access log описывает обработанные запросы: путь, статус, объём и время. Error log содержит дополнительные сообщения о сбоях обслуживания. Запись 404 в первом журнале может сопровождаться сообщением об отсутствующем файле во втором, но не обязана выглядеть как авария процесса. Существование любого 404 также не доказывает неисправность сайта: посетители и роботы способны запрашивать адреса, которых никогда не было.

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

# log_format задаётся в контексте http, не внутри server.
log_format release_lab escape=json
  '{"time":"$time_iso8601","id":"$request_id",'
  '"method":"$request_method","target":"$request_uri",'
  '"status":$status,"bytes":$body_bytes_sent,'
  '"seconds":$request_time}';

# В серверном блоке учебного сайта:
access_log /var/log/nginx/release-lab.access.log release_lab;
add_header X-Request-ID $request_id always;

В таком формате исходный request_uri включает параметры. Для нашего учебного статического стенда это приемлемый пример, но настоящая форма или API могут передавать в них чувствительные сведения. Тогда формат уменьшают или очищают параметры до записи. Журнал хранится вне публичного корня и доступен ограниченным ролям. Не следует включать тело запроса, пароль и все заголовки просто ради возможной будущей диагностики.

Идентификатор соединяет наблюдения

X-Request-ID позволяет связать конкретный внешний ответ с записью. Идентификатор запроса отличается от идентификатора выпуска: первый обозначает одно обращение, второй — набор обслуживаемых файлов. В журнале публикации есть время смены current, поэтому событие можно сопоставить с запросами вокруг него. При нескольких узлах дополнительно потребуется знать, какой узел обработал запрос, иначе одинаковое время не установит выбранный каталог.

Условные записи для объяснения, не реальные журналы:
10:05:01 GET /my/legacy/first.php   200  id=req-a
10:05:01 GET /assets/site.r2.css   404  id=req-b
Выбранный выпуск по журналу публикации: r2

Здесь HTML найден, а стиль отсутствует. Из этого ещё не следует, что генератор ошибся: причиной может быть неверный путь в HTML, неполный артефакт или доставка не в тот каталог. Проверяем последовательно содержание ссылки, наличие файла в принятом артефакте и выбранный серверный корень. Разные запросы имеют разные идентификаторы, поскольку браузер загружает страницу несколькими обращениями. Один успешный ответ статьи не распространяется автоматически на её ресурсы.

Индикатор здоровья имеет узкое назначение

Наш health.json содержит только номер выпуска. Если GET к основному HTTPS-имени возвращает корректный JSON, мы знаем, что прошли определённый маршрут: разрешение имени, соединение, выбранный сервер и чтение небольшого файла. Это полезно для сравнения после публикации. Но статический файл может открываться и тогда, когда каталог статей неполон. Поэтому индикатор дополняет проверку содержания, а не заменяет её.

В шестом уроке для него задано Cache-Control: no-store. Это уменьшает риск наблюдать сохранённую копию в поддерживающем заголовок кеше. При CDN дополнительно проверяют настройки внешнего слоя: он может иметь собственную политику. Номер из файла нельзя выдавать за идентификатор каждого ответа, если HTML и ресурсы проходят другие кеши. Иногда разумно добавить в публичный ответ заголовок версии через согласованную конфигурацию, но тогда его обновление также становится частью выпуска.

curl --dump-header health.headers --output health.json \
  https://example.com/health.json

Команда предназначена читателю и не запускалась. Ожидаемый ответ содержит текущий номер, но сам факт скачивания файла ещё не проверяет JSON и его смысл. Если сервер отдаёт страницу ошибки с кодом 200, текстовый файл появится, однако проверка здоровья должна отклонить его. Для будущего монитора опишем ожидаемый статус и признак содержимого отдельно.

Время ответа и источник задержки

request_time отражает обработку со стороны Nginx, а не всё время, которое пользователь провёл перед экраном. Разрешение DNS, сетевой путь и выполнение JavaScript в браузере имеют другие границы. Для статической страницы долгий ответ может быть связан с передачей большого файла или проблемой сети, а не со сложным запросом базы, которой в нашем стенде нет. Поэтому цифру сопровождают названием измерения и единицей.

Во второй части курса появится upstream-приложение. Тогда журнал полезно дополнить временем соединения и ожидания ответа от него. Это позволит отличать задержку приложения от передачи клиенту. Пока не добавляем поля, которые в статическом ответе не имеют полезного значения. Хороший журнал содержит достаточно сведений для конкретных вопросов и остаётся читаемым, а не копирует весь доступный список переменных.

Хранение и практический разбор

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

При сообщении об ошибке сохраняют нужный небольшой фрагмент до ротации, добавляют внешний ответ и паспорт выпуска. Сам фрагмент не публикуют вместе с уроком или в открытом каталоге. В учебном разборе допустимо заменить адрес клиента и убрать параметры, сохранив причинную связь. Если данных не хватает, это отмечают честно: «источник неизвестен» полезнее уверенного объяснения по одному статусу.

Теперь у нас есть связь между запросом, выбранным выпуском и наблюдаемым симптомом. Следующий урок превратит отдельные наблюдения в регулярный мониторинг, чтобы получить сигнал об изменении поведения без постоянного ручного открытия страниц.