Вопрос или проблема
У нас есть 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" "-"
Ответ или решение
Может ли Nginx логировать время в формате ISO 8601 с миллисекундами?
Вопрос довольно актуален, учитывая необходимость корреляции логов между различными сервисами, такими как Nginx и Tomcat. Как мы знаем, Tomcat логирует запросы с временными метками в формате ISO 8601, включая миллисекунды. Если Nginx не будет включать миллисекунды в свои логи, это усложнит объединение данных логов от разных сервисов в одну временную цепочку. Давайте разберемся, возможно ли настроить Nginx так, чтобы он также включал миллисекунды в лог-файлы.
Обходные решения и реализация
К сожалению, стандартные возможности Nginx по логированию не позволяют сделать это напрямую. Однако существуют обходные решения, которые позволяют достичь желаемого результата.
-
Использование переменных
$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
, которая компилирует и форматирует время с миллисекундами. -
Лог формат:
В лог формате, используемом 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"';
-
Альтернативы и расширения:
Возможно, вы захотите использовать сторонние патчи или расширения для Nginx, однако это может повлечь необходимость пересборки пакета Nginx и анализ возможных рисков.
Таким образом, хотя изменения требуют небольшого объема ручных настроек и корректировок конфигурационного файла, они позволяют интегрировать логи с миллисекундной точностью, что в свою очередь значительно упрощает анализ и синхронизацию данных между разными компонентами сервера.
Источники и дополнения: Дополнительная информация об этой теме доступна на grangerx.wordpress.com.
Эти меры позволят вам создавать более детализированные отчеты и улучшить качество сбора аналитических данных. Надеемся, что каждое действие, описанное выше, приведет к более точным и надежным результатам вашей работы с логами Nginx.