Docker Logging Driver
The mechanism Docker uses to capture and route container stdout and stderr output. The default json-file driver writes to the host filesystem — production systems typically use awslogs, fluentd, or splunk drivers to ship logs to centralised aggregation systems.
What a logging driver does
Every container writes its output to stdout and stderr. The logging driver decides where that output goes: a local file, a cloud service such as CloudWatch, a log aggregator, or nowhere at all.
The default driver, json-file, stores logs under /var/lib/docker/containers/ on the host. It does not rotate logs by default, so a busy container can slowly fill the disk.
stdout and stderr"] --> B["Logging driver"] B --> C["Host disk
json-file, local"] B --> D["Remote system
awslogs, fluentd, splunk"] B --> E["Discarded
none"] class A,C,D,E base class B key classDef base fill:#f8fafc,stroke:#94a3b8,stroke-width:1.5px,color:#0f172a classDef key fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#0f172a
Common drivers
| Driver | Description | Typical use |
|---|---|---|
| json-file | Default. JSON files on the host | Always configure rotation |
| local | Compact, rotated-by-default binary format | Better performance than json-file |
| awslogs | AWS CloudWatch Logs | AWS-based infrastructure |
| fluentd | Forwards to a Fluentd collector | EFK and similar stacks |
| journald | systemd journal | Linux hosts using systemd |
| splunk | Splunk HTTP Event Collector | Enterprise Splunk setups |
| none | Discards all logs | Batch jobs that need no logs |
Configuring log rotation
Set rotation in /etc/docker/daemon.json so it applies to every new container. This caps each container at 3 files of 100MB, or 300MB in total:
{ "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "3" }}Restart the daemon to apply it. Existing containers keep their old settings until they are recreated.
sudo systemctl restart docker # Per-container overridedocker run -d \ --log-driver json-file \ --log-opt max-size=200m \ --log-opt max-file=5 \ payment-api:latestShipping logs to CloudWatch
docker run -d \ --log-driver awslogs \ --log-opt awslogs-region=ap-south-1 \ --log-opt awslogs-group=/production/payment-api \ --log-opt mode=non-blocking \ registry.example.com/payment-api:v3.1.0mode=non-blocking prevents the application from stalling if the log endpoint is slow or unreachable, at the cost of possibly dropping messages when the buffer fills.
Using docker logs
docker logs always works with json-file and local. Since Docker 20.10, remote drivers such as awslogs and fluentd also keep a small local cache, so docker logs generally works with them too. The cache is for convenience only; the remote system remains the source of truth.
RememberConfigure rotation before running production workloads. Without it,
json-filelogs grow without limit. Withmax-size: 100mandmax-file: 3, each container is capped at 300MB.
Frequently Asked Questions
Why does the default json-file logging driver become a problem in production?
json-file writes every line of container stdout/stderr to a file on the host disk with no rotation configured out of the box, so a chatty service can silently fill the disk over weeks, eventually taking down every container on that host, not just the noisy one. It also means logs live and die with the host. If you replace the instance, the logs go with it, which defeats centralized debugging across an autoscaled fleet.
How should logging drivers actually be configured for production containers?
Two common approaches: set `max-size` and `max-file` on json-file to bound disk usage while still writing locally (good when a separate agent like Filebeat tails the files), or switch the driver itself to something like `awslogs`, `gelf`, or `fluentd` to ship logs directly off-host. A frequent mistake is using a driver such as `awslogs` in blocking mode without also setting `mode=non-blocking`, which can stall container writes if the logging endpoint is slow or unreachable.