Может ли nginx журналировать время в формате ISO 8601, но с миллисекундами?

Вопрос или проблема

У нас есть Nginx в качестве обратного прокси перед Tomcat. Оба ведут логирование доступа c метками времени в формате ISO 8601, но Tomcat добавляет миллисекунды (что является частью стандарта). Так что, если Nginx получает запрос и передает его на Tomcat, в логе Nginx может быть метка времени “2015-10-29T00:37:02+00:00”, а у Tomcat – “2015-10-29T00:37:02,106+0000” для того же доступа. Я не беспокоюсь о небольших различиях в формате, но отсутствие миллисекунд (часть “,106” в логе Tomcat) является проблемой, потому что это мешает правильно сопоставлять логи.

Есть ли способ сделать так, чтобы Nginx включал миллисекунды в свои логи?

К сожалению, исходя из прочтения исходного кода nginx, не существует простого способа сделать это. Вам потребуется обработать логи после их создания (можно взять вывод $msec и самостоятельно преобразовать его в ISO8601 с миллисекундами) или пропатчить nginx для добавления этой функции.

Интересно, что несколько лет назад было предложено патч, который бы обеспечивал достаточную гибкость для этой возможности, но, насколько я знаю, он никуда не попал:
http://nginx.2469901.n2.nabble.com/PATCH-time-custom-supports-a-custom-log-timestamp-td3505292.html#none

Запрос был на ISO 8601 плюс миллисекунды – вот однострочник для этого конкретного случая, основанный на ответе Александра, но с использованием формата ISO вместо локального формата:

map "$time_iso8601 # $msec" $time_iso8601_ms { "~(^[^+]+)(\+[0-9:]+) # \d+\.(\d+)$" $1.$3$2; }

Результат строится из групп сопоставления регулярных выражений следующим образом:

  • $1 = только часть с датой и временем из $time_iso8601, например, 2021-05-21T10:26:19
  • $2 = только часть с часовым поясом из $time_iso8601, например, +00:00
  • $3 = только миллисекундная часть из $msec, например, 123 извлеченная из 1621594635.123

Если однострочник кажется слишком неинформативным, посмотрите этот пост (как прокомментировано в другом ответе), который использует несколько операторов map.

Вот временное решение, которое я нашел.

Добавьте следующую строку в блок http {} вашего nginx.conf:

map "$time_local:$msec" $time_local_ms { ~(^\S+)(\s+\S+):\d+.(\d+)$ $1.$3$2; }

где:

  • $1 – часть с датой и временем из $time_local
  • $2 – часть с часовым поясом из $time_local, например, +0000
  • $3 – миллисекундная часть из $msec, например, 234 извлеченная из 1681650855.234
  • $msec – время в секундах с разрешением в миллисекунды на момент записи лога

Затем, в своей строке log_format измените [$time_local] на [$time_local_ms], или создайте свой собственный формат лога, например, тот, который я использую для Datadog:

log_format  common  '$remote_addr - $remote_user [$time_local_ms] "$request" '
                    '$status $body_bytes_sent $request_time "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

Пример журнала доступа:

172.17.0.1 - - [16/Apr/2023:13:14:15.234 +0000] "GET /static/image.jpg HTTP/1.1" 304 0 0.000 "http://localhost/" "Mozilla" "-"

Источник: https://grangerx.wordpress.com/2019/08/28/nginx-improve-logs-by-adding-millisecond-msec-resolution-to-time_local/

Ответ или решение

Может ли Nginx логировать время в формате ISO 8601 с миллисекундами?

Вопрос довольно актуален, учитывая необходимость корреляции логов между различными сервисами, такими как Nginx и Tomcat. Как мы знаем, Tomcat логирует запросы с временными метками в формате ISO 8601, включая миллисекунды. Если Nginx не будет включать миллисекунды в свои логи, это усложнит объединение данных логов от разных сервисов в одну временную цепочку. Давайте разберемся, возможно ли настроить Nginx так, чтобы он также включал миллисекунды в лог-файлы.

Обходные решения и реализация

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

  1. Использование переменных $time_iso8601 и $msec:
    Одним из решений является объединение встроенных переменных Nginx. Переменная $time_iso8601 отвечает за вывод времени в формате ISO 8601 без миллисекунд, а $msec хранит время в секундах с миллисекундной точностью. Это позволяет создать настраиваемую временную метку с миллисекундами.

    В конфигурационном файле nginx.conf в блоке http {} можно определить следующее:

    map "$time_iso8601 # $msec" $time_iso8601_ms { "~(^[^+]+)(\+[0-9:]+) # \d+\.(\d+)$" $1.$3$2; }

    Здесь создается переменная $time_iso8601_ms, которая компилирует и форматирует время с миллисекундами.

  2. Лог формат:
    В лог формате, используемом Nginx, замените старую временную переменную [$time_local] на новую [$time_local_ms]:

    log_format main '$remote_addr - $remote_user [$time_local_ms] "$request" '
                   '$status $body_bytes_sent "$http_referer" '
                   '"$http_user_agent" "$http_x_forwarded_for"';
  3. Альтернативы и расширения:
    Возможно, вы захотите использовать сторонние патчи или расширения для Nginx, однако это может повлечь необходимость пересборки пакета Nginx и анализ возможных рисков.

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

Источники и дополнения: Дополнительная информация об этой теме доступна на grangerx.wordpress.com.

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

Оцените материал
Добавить комментарий

Капча загружается...