For the complete documentation index, see llms.txt. Markdown versions are available by appending .md to documentation URLs.

NGINX Logs - Collect and Parse with OpenTelemetry

SigNoz Cloud - This page applies to SigNoz Cloud editions.
Self-Host - This page applies to self-hosted SigNoz editions.

This guide shows you how to send NGINX access and error logs to SigNoz with the OpenTelemetry Collector. The Collector tails the log files and parses each line into fields such as status, request_path, and severity, so you can filter and aggregate them in SigNoz.

Prerequisites

  • NGINX writing access and error logs to files, such as /var/log/nginx/access.log and /var/log/nginx/error.log
  • The OpenTelemetry Collector on the same host, sending data to SigNoz (VM install guide)
  • An instance of SigNoz (either Cloud or Self-Hosted)

Send logs to SigNoz

Step 1. Let the Collector read the log files

The nginx.org packages create the log files with mode 640, owned by the nginx user and the adm group. The Collector service runs as the otelcol-contrib user, so add that user to the adm group:

sudo usermod -aG adm otelcol-contrib

If you run the Collector binary manually, add the user that runs it to the adm group instead. Without this step, the Collector logs permission denied for each file.

Step 2. Add the log receivers

Add these two receivers to /etc/otelcol-contrib/config.yaml, under the existing receivers section. They read the access and error logs and parse each line:

/etc/otelcol-contrib/config.yaml
receivers:
  # On Collector v0.149.0 and newer, use "file_log" to avoid a deprecation warning.
  filelog/nginx-access-logs:
    include: [/var/log/nginx/access.log]
    operators:
      # Parses the "combined" log format, and the nginx.org "main" format that appends "$http_x_forwarded_for":
      # $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"
      - type: regex_parser
        if: body matches '^(?P<remote_addr>[0-9a-fA-F\\.:]+) - (?P<remote_user>[^\\s]+) \\[(?P<ts>.+)\\] "(?P<request_method>\\w+?) (?P<request_path>.+?) (?P<protocol>HTTP/[0-9.]+)" (?P<status>[0-9]+) (?P<body_bytes_sent>[0-9]+) "(?P<http_referrer>[^"]*)" "(?P<http_user_agent>[^"]*)"( "(?P<http_x_forwarded_for>[^"]*)")?$'
        parse_from: body
        parse_to: attributes
        regex: '^(?P<remote_addr>[0-9a-fA-F\.:]+) - (?P<remote_user>[^\s]+) \[(?P<ts>.+)\] "(?P<request_method>\w+?) (?P<request_path>.+?) (?P<protocol>HTTP/[0-9.]+)" (?P<status>[0-9]+) (?P<body_bytes_sent>[0-9]+) "(?P<http_referrer>[^"]*)" "(?P<http_user_agent>[^"]*)"( "(?P<http_x_forwarded_for>[^"]*)")?$'
        timestamp:
          parse_from: attributes.ts
          layout: "02/Jan/2006:15:04:05 -0700"
          layout_type: gotime
        severity:
          parse_from: attributes.status
          overwrite_text: true
          mapping:
            debug: "1xx"
            info: ["2xx", "3xx"]
            warn: "4xx"
            error: "5xx"
      - type: remove
        if: attributes.ts != nil
        field: attributes.ts
      - type: add
        field: attributes.source
        value: nginx
 
  # On Collector v0.149.0 and newer, use "file_log" to avoid a deprecation warning.
  filelog/nginx-error-logs:
    include: [/var/log/nginx/error.log]
    operators:
      # Parses the default error log format:
      # YYYY/MM/DD HH:MM:SS [LEVEL] PID#TID: *CID MESSAGE
      - type: regex_parser
        if: body matches '^(?P<ts>.+?) \\[(?P<log_level>\\w+)\\] (?P<pid>\\d+)#(?P<tid>\\d+). \\*(?P<cid>\\d+) (?P<message>.+)$'
        parse_from: body
        parse_to: attributes
        regex: '^(?P<ts>.+?) \[(?P<log_level>\w+)\] (?P<pid>\d+)#(?P<tid>\d+). \*(?P<cid>\d+) (?P<message>.+)$'
        timestamp:
          parse_from: attributes.ts
          layout: "2006/01/02 15:04:05"
          layout_type: gotime
        severity:
          parse_from: attributes.log_level
          overwrite_text: true
          mapping:
            debug: "debug"
            info: ["info", "notice"]
            warn: "warn"
            error: ["error", "crit", "alert"]
            fatal: "emerg"
      - type: remove
        if: attributes.ts != nil
        field: attributes.ts
      - type: move
        if: attributes.message != nil
        from: attributes.message
        to: body
      - type: add
        field: attributes.source
        value: nginx

If your log files live elsewhere, update the include paths.

Step 3. Add a logs pipeline

Add a logs/nginx pipeline under the existing service.pipelines section. It reuses the processors and exporter from the VM install guide config:

/etc/otelcol-contrib/config.yaml
service:
  pipelines:
    logs/nginx:
      receivers: [filelog/nginx-access-logs, filelog/nginx-error-logs]
      processors: [batch, resourcedetection]
      exporters: [otlphttp]

Step 4. Restart the Collector

Restart the Collector so it picks up the new group membership and configuration:

sudo systemctl restart otelcol-contrib

The Collector reads only lines written after it starts, so send a few requests to NGINX to produce new log lines.

Validate

  1. Send a few requests to NGINX, for example curl http://localhost/.
  2. Open SigNoz and navigate to Logs > Explorer.
  3. Filter by source = nginx.
  4. Click a log line to see its parsed attributes, such as status, request_method, and request_path.
SigNoz Logs Explorer filtered by source nginx, with an access log line expanded to show its parsed attributes
NGINX access and error logs in the Logs Explorer, with parsed attributes

Severity follows the response status for access logs: 2xx and 3xx are INFO, 4xx is WARN, and 5xx is ERROR. Error log lines keep the NGINX level.

Connect the NGINX integration (Optional)

The Integrations page in SigNoz tracks whether NGINX logs are arriving.

  1. Open Integrations and search for nginx.
SigNoz Integrations page filtered by nginx, listing the Nginx integration as Not Installed
The Nginx integration on the Integrations page
  1. Open Nginx, click Connect Nginx, and then click I have already configured.
Connect Nginx dialog with Show Configuration Steps and I have already configured buttons
Connect the integration after you configure the Collector
  1. Send a few requests to NGINX. Once logs arrive, the page shows This integration is working properly.
Nginx integration page showing This integration is working properly
The integration confirms that NGINX logs are arriving

To stop tracking, click Remove from SigNoz. This does not change your Collector configuration.

Data collected

The Data Collected tab of the integration lists the parsed log attributes.

Data Collected tab of the Nginx integration listing log attributes
Log attributes of the Nginx integration

The configuration in this guide also adds protocol and http_x_forwarded_for, which the tab does not list yet.

NamePathType
Timestamptimestamptimestamp
Severity Textseverity_textstring
Severity Numberseverity_numbernumber
Body Bytes Sentattributes.body_bytes_sentstring
Referrerattributes.http_referrerstring
User Agentattributes.http_user_agentstring
Request Methodattributes.request_methodstring
Request Pathattributes.request_pathstring
Protocolattributes.protocolstring
Response Status Codeattributes.statusstring
Remote Addressattributes.remote_addrstring
Forwarded Forattributes.http_x_forwarded_forstring

Troubleshooting

Check the Collector logs first:

sudo journalctl -u otelcol-contrib -f

Why do the logs show open /var/log/nginx/access.log: permission denied?

The otelcol-contrib user cannot read the NGINX log files. Add it to the adm group as shown in Step 1, then restart the Collector. Group changes apply only after the restart.

Why do NGINX logs arrive without parsed attributes?

Your log_format does not match the access log regex. Compare a line from access.log with the format in the receiver comment, then adjust the regex and if lines.

Why are older log lines missing?

The filelog receiver starts at the end of each file by default. To also send existing lines once, add start_at: beginning to both receivers.

For more help with missing data, see Debug missing traces, logs, and metrics in SigNoz.

Next steps

Get Help

If you need help with the steps in this topic, please reach out to us on SigNoz Community Slack. If you are a SigNoz Cloud user, please use in product chat support located at the bottom right corner of your SigNoz instance or contact us at cloud-support@signoz.io.

Is this page helpful

Last updated—October 06, 2026

Edit on GitHub