Everything a container writes to stdout and stderr goes to a logging driver. The default driver keeps logs as JSON files without any size limit, which is a classic way for a long-running Docker host to fill its disk. Choosing the right driver and setting rotation takes five minutes, and prevents that.
Reading logs: docker logs.
Check what you use
docker info --format '{{.LoggingDriver}}'
docker inspect -f '{{.HostConfig.LogConfig}}' <container>
sudo du -sh /var/lib/docker/containers/*/*-json.log | sort -h | tail
The main drivers
| Driver | Stored | docker logs works |
Notes |
|---|---|---|---|
| json-file (default) | /var/lib/docker/containers/<id>/<id>-json.log |
Yes | No rotation unless configured |
| local | Compressed, efficient files | Yes | Rotates by default (100 MB per container); recommended |
| journald | systemd journal | Yes | Query with journalctl CONTAINER_NAME=…; journal limits apply |
| syslog | Local or remote syslog | No (without dual logging) | Central logging |
| fluentd, gelf, awslogs, loki (plugin) | External systems | Depends | Centralised logging stacks |
Since Docker 20.10, dual logging keeps a local cache, so docker logs works even with remote drivers.
Set defaults for all containers (daemon.json)
{
"log-driver": "local",
"log-opts": {
"max-size": "20m",
"max-file": "5"
}
}
Or keep json-file with rotation:
{
"log-driver": "json-file",
"log-opts": { "max-size": "20m", "max-file": "5", "compress": "true" }
}
sudo nano /etc/docker/daemon.json
sudo systemctl restart docker
Defaults apply only to containers created afterwards. Recreate existing ones (docker compose up -d --force-recreate) to pick them up.
Per-service settings in Compose
services:
app:
image: myapp:1.8.3
logging:
driver: json-file
options:
max-size: "10m"
max-file: "5"
See Docker Compose in production.
journald driver
{ "log-driver": "journald" }
journalctl CONTAINER_NAME=web -f
journalctl -u docker --since "1 hour ago"
Logs then follow the journal’s size limits (SystemMaxUse= in journald.conf), and appear alongside system logs. See journalctl.
Emergency: a container log filled the disk
sudo du -sh /var/lib/docker/containers/* | sort -h | tail -5
sudo truncate -s 0 /var/lib/docker/containers/<id>/<id>-json.log # frees space immediately
Then set rotation, and recreate the container, so it doesn’t happen again. Don’t delete the file while the container is running (the space isn’t freed until it stops). See disk full troubleshooting and Docker disk cleanup.
Central logging
For several servers or many containers, ship logs to one place:
- Grafana Loki + Promtail/Alloy (or the Loki Docker driver): lightweight, label-based.
- ELK / OpenSearch with Fluent Bit or Filebeat: powerful search.
- Hosted services (via fluentd/gelf or agents).
Prefer structured JSON logs from your applications. They’re much easier to filter. See jq.
Good practices
- Apps should log to stdout/stderr, not files inside the container.
- Avoid very chatty debug logging in production. It costs disk and CPU.
- Don’t log secrets (tokens, passwords) — logs are often less protected than databases.
Quick reference
| Task | Command / setting |
|---|---|
| Current driver | docker info --format '{{.LoggingDriver}}' |
| Global rotation | daemon.json → log-opts max-size, max-file |
| Recommended driver | local |
| Per service | Compose logging: |
| Free space now | truncate -s 0 <id>-json.log |
| journald | journalctl CONTAINER_NAME=x |
Related: Docker secrets and Linux log files explained.