Access and error logs

NGINX · Practical · 10 min

Logs are the first place to look for every 4xx, 5xx or slow request, and custom formats make them far more useful.

NGINX writes two logs.

The error log (error_log path level;) records problems: missing files, upstream failures, configuration warnings. Levels go from debug through info, notice, warn, error up to emerg; the default is error. Upstream errors show the exact cause, such as connect() failed (111: Connection refused) while connecting to upstream.

The access log records every request using a log_format. The predefined combined format contains client address, time, request line, status, body size, referer and user agent. Define your own with variables:

  • $request_time: total time NGINX spent on the request.
  • $upstream_response_time, $upstream_addr, $upstream_status: what the backend did, essential for latency debugging.
  • $request_id: a unique ID you can also forward to the backend as a header for tracing.

log_format name escape=json '{...}' produces JSON lines that log shippers parse without regexes.

access_log off; disables logging for noisy locations like health checks; access_log ... buffer=32k flush=5s; reduces disk writes on busy servers; a conditional if=$loggable parameter logs only some requests. In containers, the official image links these logs to stdout and stderr.

Example

http {
    log_format json escape=json '{'
        '"time":"$time_iso8601","ip":"$remote_addr",'
        '"req":"$request","status":$status,"bytes":$body_bytes_sent,'
        '"rt":$request_time,"urt":"$upstream_response_time",'
        '"upstream":"$upstream_addr","id":"$request_id"}';

    access_log /var/log/nginx/access.json json buffer=32k flush=5s;
    error_log  /var/log/nginx/error.log warn;

    server {
        listen 80;
        location = /healthz { access_log off; return 200 "ok\n"; }
        location / {
            proxy_set_header X-Request-ID $request_id;
            proxy_pass http://127.0.0.1:8000;
        }
    }
}

Remember

  • error_log for problems, access_log for every request
  • Log $request_time and $upstream_response_time to find slowness
  • escape=json gives machine-readable logs

Watch out for

  • Debugging 502s from the access log alone; the error log says why the upstream failed.

Check yourself

  1. A request took 3 s according to $request_time but $upstream_response_time is 2.9 s. Where is the time spent?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: nginx.org/en/docs/http/ngx_http_log_module.html