Skip to content
Field Notes
Go back

Docker Logging: Drivers, Rotation, and Not Filling Your Disk

A container runs for three months. It logs every request, every error, every debug statement to stdout. The default Docker log driver stores all of it to a JSON file on disk — with no size limit. One morning the server is down. Disk full. Not from database growth or uploaded files, but from container logs. This is one of the most common operational failures in Docker deployments, and it is entirely preventable.


TL;DR

Docker’s default log driver (json-file) has no size limit. Set max-size and max-file globally in /etc/docker/daemon.json or per-container. For production, configure log rotation before you deploy anything. docker logs works with json-file and journald but not most other drivers. For centralized logging, ship logs to Loki, Elasticsearch, or a similar system via Fluentd or a log driver.


Context

Docker captures everything a container writes to stdout and stderr. Where those logs go — and how much space they consume — depends on the log driver. The default behavior is convenient for development (everything goes to a local file, docker logs works) but dangerous for production (unlimited growth). This article covers the drivers, the rotation settings, and the path to centralized logging.


Analysis / Key Findings

The Default Problem

Out of the box, Docker uses the json-file driver with no rotation. Every line written to stdout/stderr is appended to a JSON file at:

/var/lib/docker/containers/<container-id>/<container-id>-json.log

A container that logs 10MB per hour generates 7GB in a month. A verbose application under heavy load can fill a disk in days.

Log Drivers

Driverdocker logs worksPersistentUse case
json-fileYesLocal fileDefault, development, small deployments
journaldYessystemd journalLinux servers using systemd
syslogNosyslog daemonTraditional Unix logging
fluentdNoFluentd serviceCentralized logging pipelines
gelfNoGraylog/GELF endpointGraylog setups
awslogsNoAWS CloudWatchAWS deployments
noneNoNothingWhen you truly don’t need logs

The key tradeoff: json-file and journald support docker logs. All other drivers do not — the logs go directly to the external system, and docker logs returns nothing. This matters for debugging.

Configuring json-file Rotation

Per-container:

docker run \
  --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  my-app

This limits each container to 3 log files of 10MB each — 30MB maximum. When the current file reaches 10MB, Docker rotates it. When there are 3 files, the oldest is deleted.

Globally (recommended for production):

Edit /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "5"
  }
}

Restart Docker:

sudo systemctl restart docker

This applies to all new containers. Existing containers keep their original settings — they need to be recreated to pick up the global config.

In Compose:

services:
  api:
    build: .
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "5"

Using journald

On Linux servers running systemd, the journald driver integrates Docker logs with the system journal:

{
  "log-driver": "journald"
}

Advantages:

# View logs for a specific container
journalctl CONTAINER_NAME=my-app

# Follow logs
journalctl CONTAINER_NAME=my-app -f

# Filter by time
journalctl CONTAINER_NAME=my-app --since "1 hour ago"

Configure journald’s own retention in /etc/systemd/journald.conf:

[Journal]
SystemMaxUse=2G
MaxRetentionSec=30day

docker logs Command

# All logs
docker logs my-container

# Follow in real-time
docker logs -f my-container

# Last N lines
docker logs --tail 100 my-container

# Since a specific time
docker logs --since 2h my-container
docker logs --since "2026-05-05T10:00:00" my-container

# Show timestamps
docker logs -t my-container

Remember: docker logs only works with json-file and journald drivers. If you switch to fluentd, syslog, or other drivers, docker logs returns nothing — you must query the external system directly.

Structured Logging

Applications that output structured JSON get better results from log aggregation tools:

{"level":"info","timestamp":"2026-05-05T10:00:00Z","message":"Request handled","method":"GET","path":"/api/users","duration_ms":45}

When combined with the json-file driver, you get JSON-in-JSON (Docker wraps the line in its own JSON structure). Log aggregation tools can parse both layers. When using fluentd or similar, the inner JSON can be parsed and indexed for structured queries.

Centralized Logging

For anything beyond a single server, ship logs to a central system:

Loki + Grafana — Lightweight, label-based log aggregation. Loki does not index log content (only labels), making it cheaper to run than Elasticsearch. Use the Loki Docker log driver or Promtail to ship logs.

# Install the Loki log driver plugin
docker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions

# Use it per-container
docker run --log-driver loki \
  --log-opt loki-url="http://loki:3100/loki/api/v1/push" \
  my-app

Fluentd — A log aggregation daemon that runs as a container and collects logs from other containers:

services:
  fluentd:
    image: fluent/fluentd:v1.16
    volumes:
      - ./fluentd/conf:/fluentd/etc
    ports:
      - "24224:24224"

  api:
    build: .
    logging:
      driver: fluentd
      options:
        fluentd-address: localhost:24224
        tag: api

ELK (Elasticsearch + Logstash + Kibana) — Full-featured but resource-intensive. Appropriate for larger deployments that need full-text search across logs.

Finding What Is Eating Disk

# Overall Docker disk usage
docker system df

# Verbose breakdown
docker system df -v

# Find the largest log files
sudo du -sh /var/lib/docker/containers/*/
sudo find /var/lib/docker/containers -name "*-json.log" -size +100M

If disk is already full, truncating a log file is faster than waiting for a container recreate:

sudo truncate -s 0 /var/lib/docker/containers/<id>/<id>-json.log

This is a band-aid — configure rotation to prevent recurrence.


Conclusion

Set log rotation before you deploy. The one-time cost of adding max-size and max-file to /etc/docker/daemon.json prevents the most common Docker disk space failure. Use json-file with rotation for small deployments, journald for systemd-based servers, and a centralized system (Loki, Fluentd, ELK) for anything multi-server. Remember that docker logs stops working with most external drivers — plan your debugging workflow accordingly.


References


Share this post on:

Previous Post
Docker Networking in Production
Next Post
Resource Limits: CPU, Memory, and Why Defaults Are Dangerous