Access log filters are not honouring configuration

Hi!

I'm trying to configure the access log in order to get all the requests/responses resulting in 400 to 499 status code.

I'm using a docker compose file and CLI arguments to configure it:

- "--accesslog=true"
- "--accesslog.filepath=/var/log/access.log"
- "--accesslog.filters.statuscodes=400"
- "--accesslog.filters.retryattempts"
- "--accesslog.filters.minduration=10ms"

I tried with just status code 400 for simplifying even more the example.

I'm able to see in the service logs that the configuration is apparently parsed correctly:

Static configuration loaded [json] staticConfiguration={"accessLog":{"fields":{"defaultMode":"keep","headers":{"defaultMode":"drop"}},"filePath":"/var/log/access.log","filters":{"minDuration":"10ms","retryAttempts":true,"statusCodes":["400"]},"format":"common"},
....

After that, I try to access any of my configured services and they work as usual, but in the access log I see all the requests/responses for all status codes.

Am I doing something wrong?

Share your full Traefik static and dynamic config, and docker-compose.yml if used.

compose file

services:
  traefik:
    container_name: traefik
    image: traefik:latest
    command:
      - "--api.insecure=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--providers.docker"
      - "--providers.docker.exposedbydefault=false"
      - "--providers.file.directory=/etc/traefik"
      - "--log.level=DEBUG"
      - "--certificatesResolvers.letsencrypt.acme.email=XXXXXXXX@YYYYYYY.com"
      - "--certificatesResolvers.letsencrypt.acme.storage=/etc/traefik/acme.json"
      - "--certificatesResolvers.letsencrypt.acme.dnsChallenge.provider=duckdns"
      - "--certificatesResolvers.letsencrypt.acme.dnsChallenge.delayBeforeCheck=0"
      - "--accesslog=true"
      - "--accesslog.filepath=/var/log/access.log"
      - "--accesslog.filters.statuscodes=400"
      - "--accesslog.filters.retryattempts"
      - "--accesslog.filters.minduration=10ms"
      - "--entrypoints.websecure.http.tls.certResolver=letsencrypt"
      - "--entrypoints.websecure.http.tls.domains[0].main=XXXXXX.duckdns.org"
      - "--entrypoints.websecure.http.tls.domains[0].sans=*.XXXXXX.duckdns.org"
      - "--experimental.plugins.rewriteHeaders.modulename=github.com/bitrvmpd/traefik-plugin-rewrite-headers"
      - "--experimental.plugins.rewriteHeaders.version=v0.0.1"
    environment:
      - DUCKDNS_TOKEN=${DUCKDNS_TOKEN}
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
      - /media/hdd/etc/traefik:/etc/traefik

I don't use any static file, and tbh I don't know what are you referring with dynamic config. Is there a way to dump the dynamic configuration from the dashboard?

Please check the following: Traefik Configuration Documentation - Traefik

Meanwhile, I have a similar case, where Traefik logs requests with "OriginStatus":200 with the following static configuration stated in the file traefik.conf:

# ...
accessLog:
  filePath: '/var/log/traefik/access.log'
  addInternals: false
  format: json

  filters:
    minDuration: '10ms'

    statusCodes:
      - '500-599'
# ...

An example of a log record:

{
  "ClientAddr": "192.168.176.1:33724",
  "ClientHost": "192.168.176.1",
  "ClientPort": "33724",
  "Duration": 15520190,
  "OriginContentSize": 15086,
  "OriginDuration": 15437943,
  "OriginStatus": 200,
  "RequestAddr": "pic.example.com",
  "RequestContentSize": 0,
  "RequestCount": 2002,
  "RequestHost": "pic.example.com",
  "RequestMethod": "GET",
  "RequestPath": "/favicon.ico",
  "RequestPort": "-",
  "RequestProtocol": "HTTP/2.0",
  "RequestScheme": "https",
  "RetryAttempts": 0,
  "RouterName": "https-nginx@docker",
  "ServiceAddr": "192.168.176.3:2283",
  "ServiceName": "nginx@docker",
  "StartLocal": "2025-07-27T13:37:48.596490602Z",
  "StartUTC": "2025-07-27T13:37:48.596490602Z",
  "TLSCipher": "TLS_AES_128_GCM_SHA256",
  "TLSVersion": "1.3",
  "downstream_Content-Length": "15086",
  "downstream_Content-Type": "",
  "downstream_Date": "Sun, 27 Jul 2025 13:37:48 GMT",
  "downstream_Etag": "W/\"15086-1753367216000\"",
  "downstream_Last-Modified": "Thu, 24 Jul 2025 14:26:56 GMT",
  "downstream_Vary": "Accept-Encoding",
  "downstream_X-Powered-By": "nginx",
  "entryPointName": "https",
  "level": "info",
  "msg": "",
  "origin_Content-Length": "15086",
  "origin_Content-Type": "",
  "origin_Date": "Sun, 27 Jul 2025 13:37:48 GMT",
  "origin_Etag": "W/\"15086-1753367216000\"",
  "origin_Last-Modified": "Thu, 24 Jul 2025 14:26:56 GMT",
  "origin_Vary": "Accept-Encoding",
  "origin_X-Powered-By": "nginx",
  "request_Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
  "request_Accept-Encoding": "gzip, deflate, br, zstd",
  "request_Accept-Language": "en-US,en;q=0.9",
  "request_Priority": "u=0, i",
  "request_Sec-Ch-Ua": "\"Not)A;Brand\";v=\"8\", \"Chromium\";v=\"138\", \"Google Chrome\";v=\"138\"",
  "request_Sec-Ch-Ua-Mobile": "?0",
  "request_Sec-Ch-Ua-Platform": "\"Windows\"",
  "request_Sec-Fetch-Dest": "document",
  "request_Sec-Fetch-Mode": "navigate",
  "request_Sec-Fetch-Site": "none",
  "request_Sec-Fetch-User": "?1",
  "request_Upgrade-Insecure-Requests": "1",
  "request_User-Agent": "Mozilla/5.0 (Linux; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36",
  "request_X-Forwarded-Host": "pic.example.com",
  "request_X-Forwarded-Port": "443",
  "request_X-Forwarded-Proto": "https",
  "request_X-Forwarded-Server": "reverse-proxy",
  "request_X-Real-Ip": "192.168.176.1",
  "time": "2025-07-27T13:37:48Z"
}

It seems the filters are combined with OR:

1 Like

Thank you! I commented out the minDuration and indeed the logs now don't get populated with requests with HTTP Status 200.