Collect Traefik Access Logs with OpenTelemetry and SigNoz

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

Overview

This guide ships Traefik access logs to SigNoz with the OpenTelemetry Collector, parsed into structured fields you can query by router, service, and status code.

Prerequisites

Ensure you have:

How it works

Traefik writes two log streams, each with its own block in the static configuration:

  • Access logs (the accessLog block): one record per HTTP request, with the router, backend service, status code, and timings. This guide collects these.
  • Application logs (the log block): Traefik's own diagnostics, such as startup and configuration reloads. Traefik writes them to stdout at ERROR level by default, and your accessLog settings do not change them. This guide skips them.

Set the access log format to json and let the OpenTelemetry Collector file log receiver tail it. A json_parser operator turns each line into structured fields you can query and aggregate in SigNoz.

Collect Traefik access logs

Switch Traefik's access log to json, write a Collector config that tails and parses that file, then deploy the Collector.

Step 1: Enable JSON access logs

Traefik ships with access logs off, and its common default format needs regex parsing. Turn access logs on and switch the format to json.

--accesslog=true
--accesslog.format=json
--accesslog.filepath=/var/log/traefik/access.log

Traefik writes to stdout when you omit the file path. Restart Traefik to apply the change.

Step 2: Create the Collector config file

Create a file named traefik-logs-collection-config.yaml with the following content:

traefik-logs-collection-config.yaml
receivers:
  # On Collector v0.149.0 and newer, use "file_log" to avoid a deprecation warning.
  filelog/traefik-access:
    include: ["${env:TRAEFIK_ACCESS_LOG_FILE}"]
    operators:
      # Traefik's json access log format. Each line is one request record with
      # fields such as RouterName, ServiceName, RequestMethod, RequestPath,
      # DownstreamStatus, and Duration.
      # See https://doc.traefik.io/traefik/reference/install-configuration/observability/logs-and-accesslogs/
      - type: json_parser
        parse_from: body
        timestamp:
          parse_from: attributes.StartUTC
          layout_type: gotime
          layout: "2006-01-02T15:04:05.999999999Z07:00"
        severity:
          parse_from: attributes.DownstreamStatus
          overwrite_text: true
          mapping:
            info:
              - "2xx"
              - "3xx"
            warn: "4xx"
            error: "5xx"
        # Traefik also writes non-access lines to stdout on startup. Let anything
        # that is not valid JSON through instead of dropping it.
        on_error: send
      # Traefik wraps each access record in its logger's envelope: "level" is always
      # "info", "msg" is always empty, and "time" duplicates the parsed timestamp.
      # Drop them so they do not clutter the attributes.
      - type: remove
        if: attributes.level != nil
        field: attributes.level
      - type: remove
        if: attributes.msg != nil
        field: attributes.msg
      - type: remove
        if: attributes.time != nil
        field: attributes.time
      - type: add
        field: attributes.source
        value: traefik

processors:
  # sets service.name so Traefik logs are easy to filter in SigNoz
  resource/traefik:
    attributes:
      - key: service.name
        value: traefik
        action: upsert
  batch:
    send_batch_size: 10000
    send_batch_max_size: 11000
    timeout: 10s

exporters:
  # On Collector v0.144.0 and newer, use "otlp_http" to avoid a deprecation warning.
  otlphttp/traefik:
    endpoint: "${env:OTLP_DESTINATION_ENDPOINT}"
    headers:
      "signoz-ingestion-key": "${env:SIGNOZ_INGESTION_KEY}"

service:
  pipelines:
    logs/traefik:
      receivers: [filelog/traefik-access]
      processors: [resource/traefik, batch]
      exporters: [otlphttp/traefik]

Duration, OriginDuration, and Overhead arrive in nanoseconds. Divide by 1,000,000 when you chart them as milliseconds.

Step 3: Deploy the Collector

Set the environment variables the config reads:

# path of the Traefik access log, must be readable by the otel collector
export TRAEFIK_ACCESS_LOG_FILE="/var/log/traefik/access.log"

# region specific SigNoz cloud ingestion endpoint
export OTLP_DESTINATION_ENDPOINT="https://ingest.<region>.signoz.cloud:443"

# your SigNoz ingestion key
export SIGNOZ_INGESTION_KEY="<your-ingestion-key>"

Start the Collector with the config file:

otelcol-contrib --config traefik-logs-collection-config.yaml

Verify these values:

Sending logs over OTLP without a Collector

Traefik can push logs straight to SigNoz over OTLP, which removes the Collector from the logs path. The feature sits behind an experimental flag, so treat it as optional and keep the file log path above as your default.

Requires Traefik 3.3 or newer. Traefik added OTLP access log export in 3.3. On 3.0 through 3.2 these flags do not exist and Traefik fails to start.

--experimental.otlpLogs=true
--accesslog=true
--accesslog.format=json
--accesslog.otlp=true
--accesslog.otlp.http=true
--accesslog.otlp.http.endpoint=https://ingest.<region>.signoz.cloud:443/v1/logs
--accesslog.otlp.http.headers.signoz-ingestion-key=<your-ingestion-key>
--accesslog.dualOutput=true

Verify these values:

  • <region>: Your SigNoz Cloud region

  • <your-ingestion-key>: Your SigNoz ingestion key

  • Enabling OTLP access logs disables stdio output unless you also set --accesslog.dualOutput=true.

  • Traefik marks this experimental and has open bugs against it, so validate on a non-production router first.

  • To use gRPC instead, swap the three http flags for --accesslog.otlp.grpc=true, --accesslog.otlp.grpc.endpoint=ingest.<region>.signoz.cloud:443, and --accesslog.otlp.grpc.headers.signoz-ingestion-key=<your-ingestion-key>. The gRPC endpoint takes no /v1/logs path.

The same --log.otlp.* flags exist for Traefik's application logs.

Validate

After you start the Collector, generate traffic through Traefik so it writes access log records.

  1. Open the Logs explorer and add filter service.name = traefik.
  2. Expand a record to see the parsed fields, such as RequestMethod, RequestPath, DownstreamStatus, Duration, and ClientHost. Severity follows the status code, so a 404 shows as WARN and a 200 as INFO.
  3. Requests that a router matched also carry RouterName, ServiceName, ServiceURL, and ServiceAddr. Traefik omits those fields when no router matches, which is what an unrouted 404 looks like.
Traefik access logs in the SigNoz Logs explorer, filtered by service.name = traefik
Traefik access logs in SigNoz, filtered by service.name = traefik

Troubleshooting

No logs arrive

  • Confirm Traefik writes the file: tail -f /var/log/traefik/access.log should show one JSON object per request. Traefik disables access logs unless you set --accesslog=true.
  • Confirm the Collector can read the file. In Docker or Kubernetes, check that both containers mount the same volume.
  • Generate traffic through a router. Traefik logs one record per request, so an idle proxy writes nothing.
  • The file log receiver reads only lines written after it starts, so records that predate the Collector never appear.

Fields are not parsed

  • Confirm the format is json. Traefik defaults to common, which the json_parser operator cannot read.
  • If you set filters.statusCodes, Traefik logs only matching responses. Widen or remove the filter.
  • A dropped StartUTC field breaks timestamp parsing. Keep it, or point the timestamp parser at StartLocal instead.

No data at all

  • Recheck the OTLP_DESTINATION_ENDPOINT region against your SigNoz region. A wrong region drops data with no error.
  • Copy the signoz-ingestion-key value fresh from SigNoz settings.

Limitations

  • Access logs are off by default. Traefik writes none until you set --accesslog=true.
  • The parser expects the json format. The default common format needs a regex parser instead.
  • Durations are nanoseconds. Duration, OriginDuration, and Overhead need scaling for millisecond charts.
  • Log severity comes from DownstreamStatus. 2xx and 3xx map to info, 4xx to warn, and 5xx to error.
  • Native OTLP log export is experimental. The Collector path stays the supported default.

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.

Last updated: July 25, 2026

Edit on GitHub

Was this page helpful?

Your response helps us improve this page.