18

We have Nginx as a reverse proxy in front of Tomcat. Both of them log access with ISO 8601 timestamps, but tomcat adds in milliseconds (which is part of the standard). So if Nginx gets a request and passes it onto Tomcat, the Nginx log might have a timestamp of "2015-10-29T00:37:02+00:00" and Tomcat will have a timestamp of "2015-10-29T00:37:02,106+0000" for the same access. I'm not concerned about the minor differences in formatting, but not having milliseconds (the ",106" part in the Tomcat log) is a problem because it prevents us from correlating the logs correctly.

Is there any way to make Nginx include milliseconds in it's logs?

2
  • Did you check the docs? Commented Oct 29, 2015 at 1:48
  • 1
    Yes I did. From that I can't see any way to log ISO 8601 timestamps with millisecond resolution, but that seems like a ridiculous oversight to me, especially given that it can log msec timestamps with millisecond resolution. So I was wondering/hoping that someone might know of a way to make Nginx log the way I want Commented Oct 29, 2015 at 2:44

4 Answers 4

4

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

1
10

Here is a workaround that I found.

Add the following line to the http {} block of your nginx.conf:

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

where:

  • $1 - date and time part of $time_local
  • $2 - timezone part of $time_local e.g. +0000
  • $3 - millisecond part of $msec e.g. 234 extracted from 1681650855.234
  • $msec - time in seconds with a milliseconds resolution at the time of the log write

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 - - [16/Apr/2023:13:14:15.234 +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/

9

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 from 1621594635.123

If the one-liner feels too opaque, see this post (as commented on another answer) which uses multiple map statements.

4

Gosh lots of attempts at solving the millisecond question - but this is a proxy for the REAL problem:

is a problem because it prevents us from correlating the logs correctly.

Nginx has a mechanism for that - request_id, e.g.

proxy_set_header X-Request-Id $request_id;

And add the header to your Tomcat log.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.