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
| Driver | docker logs works | Persistent | Use case |
|---|---|---|---|
json-file | Yes | Local file | Default, development, small deployments |
journald | Yes | systemd journal | Linux servers using systemd |
syslog | No | syslog daemon | Traditional Unix logging |
fluentd | No | Fluentd service | Centralized logging pipelines |
gelf | No | Graylog/GELF endpoint | Graylog setups |
awslogs | No | AWS CloudWatch | AWS deployments |
none | No | Nothing | When 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:
docker logsstill works- Logs are managed by journald’s own rotation and retention settings
- Unified view of system and container logs via
journalctl - Structured metadata (container name, image, labels) is preserved
# 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.