Can nginx log time in ISO 8601 format, but include milliseconds?
Unfortunately, based on reading the source code to nginx, there doesn't seem to be a simple way to do this. You would need to post-process the logs (you could take the output of $msec and turn it into ISO8601 with ms yourself) or patch nginx to add this.
Interestingly a patch was proposed years ago that would have given enough flexibility to make it possible, but I don't think it went anywhere: http://nginx.2469901.n2.nabble.com/PATCH-time-custom-supports-a-custom-log-timestamp-td3505292.html#none
Here is a workaround that I found. Add the following line to the http {}
block:
map "$time_local:$msec" $time_local_ms { ~(^\S+)(\s+\S+):\d+\.(\d+)$ $1.$3$2; }
Then, in your log_format
line change [$time_local]
to [$time_local_ms]
, or create your own log format, e.g. the one that I use for 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"';
Example of access log:
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" "-"
Source: https://grangerx.wordpress.com/2019/08/28/nginx-improve-logs-by-adding-millisecond-msec-resolution-to-time_local/
The question requested ISO 8601 plus milliseconds - here is a one-liner for that specific use case, based on Oleksandr's answer but using ISO rather than local format:
map "$time_iso8601 # $msec" $time_iso8601_ms { "~(^[^+]+)(\+[0-9:]+) # \d+\.(\d+)$" $1.$3$2; }
The result is constructed from the regex match groups as follows:
-
$1
= just the date and time part of$time_iso8601
e.g.2021-05-21T10:26:19
-
$2
= just the timezone part of$time_iso8601
e.g.+00:00
-
$3
= just the millisecond part of$msec
e.g.123
extracted from1621594635.123
If the one-liner feels too opaque, see this post (as commented on another answer) which uses multiple map
statements.