How to Inspect Docker Logs and Rotate Them the Safe Way
Read Docker container logs with docker logs, filter by time, set up json-file rotation with max-size and max-file, and choose another driver for production.

A container that logs a few lines per second fills a disk in weeks if nothing rotates the file. The default configuration is unbounded, and the first sign is a full disk. Logging is simple to inspect and simple to bound, and the fix takes four lines. It relates to disk cleanup, and the examples assume Docker 27.
Read the logs
docker logs app
docker logs -f --tail 50 app
docker logs --since 10m -t app
docker logs --since 2026-11-03T09:00:00 --until 2026-11-03T09:30:00 app 2>&1 | grep -i error
docker compose logs -f --tail 20 web db2026-11-03T09:14:01.114Z GET /health 200
2026-11-03T09:14:06.115Z GET /health 200
docker logs writes the container's stdout to its stdout and its stderr to your stderr, so redirect 2>&1 before piping to grep. -t adds Docker's own timestamp. For Compose, name services to follow several at once. This is the same discipline as following logs with tail.
Find the file and its size
docker inspect -f '{{.LogPath}}' app
sudo ls -lh $(docker inspect -f '{{.LogPath}}' app)
docker inspect -f '{{.HostConfig.LogConfig.Type}}' app/var/lib/docker/containers/3f9a.../3f9a...-json.log
-rw-r----- 1 root root 2.4G Nov 3 09:20 .../3f9a...-json.log
A 2.4 GB log file for one container is the usual surprise. Truncating it in an emergency works with sudo truncate -s 0 FILE, while the container keeps running, but the fix is rotation.
Turn on rotation
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}Save that as /etc/docker/daemon.json and restart the daemon with sudo systemctl restart docker. The setting applies to containers created afterwards, so existing ones must be recreated. This caps each container at about 50 MB. Per container, use docker run --log-opt max-size=10m --log-opt max-file=5, and in Compose put logging: {driver: json-file, options: {max-size: "10m", max-file: "5"}} under the service. Add compress: "true" to compress rotated files.
Send logs elsewhere
docker run -d --log-driver=syslog --log-opt syslog-address=udp://logs.example.test:514 myappDrivers like syslog, journald, fluentd and gelf ship logs off the host. A caveat: with some drivers, docker logs no longer works unless dual logging is available, which Docker Engine provides for remote drivers since 20.10. A central system also survives container deletion, which local json files do not.
Why unrotated logs fill disks
By default Docker's json-file driver writes every line a container prints to stdout and stderr into a file under /var/lib/docker/containers/<id>/, and it never truncates it. A service that logs a few lines per request can produce gigabytes in weeks. The usual symptom is a host that runs out of disk space, followed by a database that cannot write and containers that fail in confusing ways. The fix takes one setting, and it is worth applying before the first deploy, since the limit applies only to containers created after the change.
That detail causes most of the confusion. Changing the daemon configuration does not affect running containers, because the logging driver and its options are fixed when the container is created. After editing /etc/docker/daemon.json and restarting the daemon, existing containers must be recreated, with docker compose up -d --force-recreate or an equivalent, for the limit to take effect.
Choosing sizes and the local driver
A typical limit is max-size of 10m with max-file of 3, which keeps about thirty megabytes per container. Choose it from the volume of logs you need to debug a failure: enough to cover the period between an incident and someone looking. If the answer is "several days of detail", the right place for them is outside the host, since a rotating local file only keeps the most recent output.
The local driver is a newer alternative that stores logs in a compact binary format, compresses rotated files and applies a default limit of 100 MB per container. It saves space, but the files are not plain JSON, so reading them with ordinary tools works only through docker logs. If other software reads the JSON files directly, such as a log shipper that tails them, stay with json-file.
Per-service settings in Compose
Compose lets you set a logging block for each service, which overrides the daemon default. Chatty services such as a reverse proxy can have larger files, while quiet ones can keep small limits. Putting the block in an extension field and reusing it with a YAML anchor keeps the file short and avoids a service silently missing the setting. Apply the same limits to one-off containers started with docker run by passing --log-opt, because forgotten containers started by hand are a common source of surprise growth.
To find the offenders on an existing host, list the log files by size with sudo du -h /var/lib/docker/containers/*/*-json.log | sort -h, then map the directory name to a container with docker ps --no-trunc. Truncating a live log with truncate -s 0 frees space immediately without restarting the container, which is the emergency measure while the real fix is applied.
Shipping logs and structured output
Rotation limits retention but does not give search or history. For that, ship logs to a collector: a driver such as fluentd or gelf, or an agent that tails the files and forwards them. Be aware that with some remote drivers, docker logs stops working because the daemon no longer keeps a local copy, unless dual logging is available in your Docker version. Test failure behaviour as well: a blocking driver can stall the application when the collector is down, so set the mode to non-blocking with a buffer, accepting that lines may be dropped under pressure.
Make the application's output easy to ship. One JSON object per line, with a timestamp, level and message, lets a collector parse fields without regular expressions. Log to stdout and stderr only, not to files inside the container, so the engine sees everything. And keep secrets out of logs, since they are copied to several places and are harder to remove than to avoid.
Check the result after every change. Inspect a recreated container with docker inspect --format '{{.HostConfig.LogConfig}}' NAME to confirm that the driver and options are the ones intended, and watch disk use over a day to verify that the files stay within the limit. A limit that is configured in the wrong place, or applied to the old containers only, is a very common reason for a disk that fills again a month later.
Add a disk-space alert at 80 percent on the Docker data directory, so a log or image problem surfaces while there is still time to act. Pair it with regular pruning of unused images, since logs are rarely the only thing that grows.
Where this does not apply
Programs that write to log files inside the container bypass all of this and grow the container's writable layer. Link the file to stdout in the image (ln -sf /dev/stdout /var/log/app.log, as the official nginx image does) or configure the application to log to the console. Rotation drops old lines, so keep a copy where retention matters. Debugging tips for logs in scripts are in reading logs to find the error. See the Docker logging configuration guide and the json-file driver reference.


