在 Tomcat 前面,我们有一个 Nginx 作为反向代理。它们都使用 ISO 8601 时间戳来记录访问,但 tomcat 添加了毫秒(这是标准的一部分)。因此,如果 Nginx 收到请求并将其传递给 Tomcat,则 Nginx 日志的时间戳可能是“2015-10-29T00:37:02+00:00”,而 Tomcat 针对同一访问的时间戳将是“2015-10-29T00:37:02,106+0000”。我并不关心格式上的细微差别,但没有毫秒(Tomcat 日志中的“,106”部分)是一个问题,因为它会阻止我们正确关联日志。
有什么方法可以让 Nginx 在其日志中包含毫秒数?
答案1
不幸的是,根据对 nginx 源代码的阅读,似乎没有简单的方法可以做到这一点。您需要对日志进行后处理(您可以获取 $msec 的输出并使用 ms 自己将其转换为 ISO8601)或修补 nginx 以添加此功能。
有趣的是,几年前就提出了一个补丁,它提供了足够的灵活性来实现这一点,但我认为它没有任何进展: http://nginx.2469901.n2.nabble.com/PATCH-time-custom-supports-a-custom-log-timestamp-td3505292.html#none
答案2
问题要求 ISO 8601 加毫秒 - 这里是针对该特定用例的一行代码,基于 Oleksandr 的答案,但使用 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
语句。
答案3
这是我找到的一个解决方法。将以下行添加到http {}
块中:
map "$time_local:$msec" $time_local_ms { ~(^\S+)(\s+\S+):\d+\.(\d+)$ $1.$3$2; }
然后,在您的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 - - [23/Apr/2021:13:06:02.802 +0000] "GET /static/image.jpg HTTP/1.1" 304 0 0.000 "http://localhost/" "Mozilla" "-"