To clear Docker logs is to empty the file the daemon keeps for each container’s output, since Docker’s CLI reference lists no command that does it. Under the default json-file driver that file has no size cap. Emptying it buys time. The lasting fix is 2 settings, max-size and max-file, or the local driver, which rotates by default.
How to clear Docker logs, and why there is no clear command
Clearing Docker logs means emptying a container’s log file on the host, because Docker offers no command that does it for you. Recreating the container starts a fresh file. Truncating the file to zero bytes works without a restart. Deleting the file with rm frees no space while the daemon still has it open.
This page covers the container’s own log file on a host where you run the Docker daemon yourself; the wider picture is in logging and monitoring for an app in production.
docker logs only reads. The docker container logs reference lists six options (details, follow, since, tail, timestamps, until) and none of them empties anything, so there is no docker log clear or --clear flag to find. What you clear is a file. With the default driver there is one per container, and docker inspect --format='{{.LogPath}}' <container> prints its path.
There are three ways to clear Docker logs, and they cost different things:
| Method | What it does | When to use it | What it costs |
|---|---|---|---|
Recreate the container (docker rm, then run it again, or Compose’s --force-recreate) | A new container gets a new log file; the old file sat in the old container’s folder | A restart is acceptable | A restart, and the old lines are gone unless you copied them |
| Truncate the file to zero bytes | Empties the file in place while the container keeps running | The disk is full now and a restart is not wanted | Root on the host, and it sits outside Docker’s documented path |
| Cap and rotate through the logging driver | max-size and max-file, or the local driver, keep the file bounded | Always, as the lasting fix | Applies only to containers created after the change |
Truncating beats trying to delete Docker logs with rm because of how Linux treats open files: the unlink(2) manual page says that if any processes still have a deleted file open, “the file will remain in existence until the last file descriptor referring to it is closed.” The daemon is the process writing that file, so an rm hides the name and keeps the space in use.
Docker’s own docs warn against touching these files at all. The json-file driver page says these files “are designed to be exclusively accessed by the Docker daemon” and that “Interacting with these files with external tools may interfere with Docker’s logging system and result in unexpected behavior, and should be avoided.” So truncation is what it is: a common emergency step outside the documented path, used when the disk is full and a restart is worse.
The order that keeps the evidence during an incident is my working rule: check the size, copy the file off the disk (or at least its last few thousand lines), empty it, then set the cap. Clearing the log of a container that is failing throws away the record of why it is failing.
# 1. Check: find the file and its size (json-file driver)
LOG=$(docker inspect --format='{{.LogPath}}' app)
sudo ls -lh "$LOG"
# 2. Copy: to another disk or machine, not the full one
docker logs --tail 5000 app > /mnt/spare/app-before-clear.log 2>&1
# 3. Empty: in place, needs root (an emergency step)
sudo truncate -s 0 "$LOG"
# Or every json-file log on the host at once (this empties them all)
sudo sh -c 'truncate -s 0 /var/lib/docker/containers/*/*-json.log'
# 4. Cap: set max-size and max-file (next sections)
Docker Compose: clear logs for one service
Docker Compose has no clear-logs command either. Recreating a service with docker compose up -d --force-recreate starts it in a new container with a new log file, and named volumes keep their data. To avoid the restart, look up the container id with docker compose ps -q and truncate that container’s log file.
The docker compose logs reference lists follow, tail, since, until, timestamps and a few display options, and nothing that clears, so a docker-compose logs clear step does not exist there either. up recreates containers “preserving mounted volumes”, and --force-recreate does it “even if their configuration and image haven’t changed”. Running docker compose down and then up does the same for the whole project at the cost of a restart. docker compose down removes the containers and networks by default; it removes named volumes only when you pass -v or --volumes.
# Recreate one service: new container, new log file
docker compose up -d --force-recreate api
# Or empty its file without a restart (root; an emergency step)
sudo truncate -s 0 "$(docker inspect --format='{{.LogPath}}' "$(docker compose ps -q api)")"
Then add the logging: block from the drivers section below to the service, so the same file cannot grow back without limit.
Why it matters: a full disk takes the whole app down
A container log that nobody capped keeps growing, because json-file’s max-size defaults to “-1 (unlimited)” and Docker’s logging page says “By default, no log-rotation is performed.” Every line the app writes to stdout and stderr lands in that file. A debug level left on in production fills it sooner; which logs severity levels stay on in production is its own question.
When the disk fills, the kernel’s answer to a write is ENOSPC, printed as No space left on device. What you see depends on which process hits it first:
| Symptom | Likely cause | First check |
|---|---|---|
no space left on device on a deploy, an image pull or in the database container’s log | The host disk is full, and container logs are a prime suspect | df -h |
| The database container restarting in a loop | It cannot write its files or its own log | sudo sh -c 'du -sh /var/lib/docker/containers/*/*-json.log' | sort -h |
| Writes failing while reads still work | Reads need no new space, writes do | docker system df |
docker logs taking minutes to return | It reads the whole file unless told otherwise | docker logs --tail 100 <container> |
The first two checks change nothing, so they are safe to run on a live host. The du line matches json-file logs only; the local driver keeps its files under another name. It runs inside sudo sh -c because Docker creates the containers folder readable by root alone, so an ordinary shell cannot expand the * in that path. There is no dashboard step before them: on a plain VPS the terminal is the first place to look.
LangWatch recorded one of these in an issue on its own tracker in July 2026. On a dev box, a ClickHouse container hit a disk-full condition, and “Every failed write emitted a full stack trace to stderr”; Docker captured all of it “in a single unrotated json log, which grew to 28G on a 96G disk”, and the loop ran “until the box was unusable (SSH unresponsive, required reboot)”. Their compose files set no logging: limits; the fix the issue asks for is bounded logs, for example max-size plus max-file per service. The lesson I take from it: the log that filled the disk is also the only record of what went wrong, so it gets copied before it is emptied and capped before it can fill the disk again.
A filling disk is also a quiet failure unless something is watching it. “17 of the 21 third-party apps had no error tracking or alerting: when a user hits an error, nothing records it.” Those 21 are the third-party apps I audited in June and July 2026, a selected set of audited apps, not a random sample or a rate for AI-built apps in general. Alerting on error rates and other thresholds is a separate topic, how to alert on error rate spikes; in my reading, a disk-usage alert on the host is the same idea pointed at the disk.
How it works: where the logs live, how to read them, and the logging drivers
Five things matter when a disk is filling, in the order you will reach for them.
Where are Docker container logs stored
Docker container logs on a Linux host, with the default driver and data directory, are stored under /var/lib/docker/containers, in a file per container named after the container id and ending in -json.log. The exact path is the LogPath field of docker inspect. On Docker Desktop for Mac the files sit inside its disk image, not in that folder.
The full form is /var/lib/docker/containers/<container-id>/<container-id>-json.log: the daemon keeps its data in /var/lib/docker on Linux unless data-root moves it, and the json-file logger names the file after the container id inside that container’s folder. Docker’s json-file driver page describes each line as JSON that records its origin (stdout or stderr) and a timestamp, with one container per file. Asking docker inspect for LogPath is safer than guessing, and it comes back empty for a container on the local driver, which keeps its files in a local-logs folder instead.
The Linux paths in old forum answers do not exist on a Mac at all. Docker Desktop’s FAQ says Desktop “stores Linux containers and images in a single, large “disk image” file in the Mac filesystem”, unlike Docker on Linux, which usually keeps them in /var/lib/docker. Docker’s Windows FAQ does not say where they live.
With journald, syslog or a remote driver there is no json-file log for the container on the host: the lines went to that system instead. And only what the process writes to stdout and stderr is captured; an app that writes its own log file inside the container keeps it out of docker logs. In my reading, that file then grows inside the container’s writable layer, where none of the settings below apply.
Docker logs: reading, tailing and grep
Docker logs prints what a container wrote to stdout and stderr. The flag --tail 100 shows the last 100 lines, -f follows new ones, and --since 30m limits the window. To grep it, merge the streams first with 2>&1, or, unless the container runs with a TTY, lines it wrote to stderr slip past the filter.
| What you want | The command |
|---|---|
| The last 100 lines | docker logs --tail 100 <container> |
| New lines as they arrive | docker logs -f <container> |
| A time window | docker logs --since 30m <container> or --until 2026-09-28T10:00:00Z |
| Timestamps on each line | docker logs -t <container> |
| One Compose service, following | docker compose logs -f --tail 100 <service> |
| Only lines with ERROR, both streams | docker logs --since 1h <container> 2>&1 | grep ERROR |
To grep Docker logs reliably, know where each stream goes. For a container started without a TTY, the Docker CLI’s own source copies the container’s stdout to your terminal’s stdout and its stderr to your stderr, and a pipe only carries stdout. So docker logs app | grep ERROR misses every error the app printed on stderr, and docker logs app 2>&1 | grep ERROR catches them. That second form is the docker logs grep pattern to keep.
On a large file, put --since in front of the grep so the daemon does not stream the whole history into it. If the app writes one JSON object per line, as how to do logging in a web app recommends, pipe the output to jq and filter on a field instead of a word. A Python app whose lines only appear when it exits has a buffering problem, which logging in a Python web app covers.
Logging drivers: json-file, local, journald, syslog and the rest
Docker logging drivers decide where container output goes. The default, json-file, keeps a file per container with no size cap unless max-size is set, and max-file then sets how many files to keep. The local driver rotates by default. A changed daemon default applies only to containers created afterwards, so existing ones keep the old setting until recreated.
A Docker logging driver is the mechanism the daemon uses to send a container’s stdout and stderr somewhere, and Configure logging drivers lists the ones that ship with it. The last column below is the one to read before you switch Docker log drivers: whether docker logs still works afterwards.
| Driver | Where the lines go | Rotates by default | docker logs still reads it |
|---|---|---|---|
| json-file (default) | A JSON file per container on the host | No: max-size defaults to unlimited | Yes |
| local | Docker’s own file format on the host, rotated files compressed | Yes: 20 MB files, 5 kept | Yes |
| journald | The host’s systemd journal | Not stated in Docker’s docs | Yes |
| syslog | The host’s syslog daemon | Not stated in Docker’s docs | Through the dual logging cache |
| gelf, fluentd, awslogs, splunk, gcplogs | A log collector or remote log service | Not stated in Docker’s docs | Through the dual logging cache |
| none | Nowhere | Not applicable | No output at all |
For journald and syslog, my reading is that the host’s own log system decides how long lines stay, not Docker. Docker’s page on the choice is plain: “the local logging driver is recommended as it performs log-rotation by default”, while json-file stays the default “to remain backwards compatible with older versions of Docker”. The local logging driver keeps “100MB of log messages per container” by default and compresses rotated files.
The two settings that cap json-file are max-size, the size at which a file is rolled, and max-file, how many files may exist, which “Only effective when max-size is also set.” To size them, multiply: max-size times max-file times the number of containers is the most disk the logs can take. As my own worked example of that arithmetic, not a Docker recommendation, 10m times 3 across 6 containers is about 180 MB.
Set the logging driver Docker uses for every new container in /etc/docker/daemon.json with the log-driver and log-opts keys, then restart the daemon; values in log-opts must be strings, so "3" and not 3.
{
"log-driver": "json-file",
"log-opts": { "max-size": "10m", "max-file": "3" }
}
Or set it per service with the Compose logging element, where a driver and its options can be set, so Docker Compose logging drivers are chosen in the file that defines the app.
services:
api:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
Docker’s docs say a changed daemon default “only affects containers that are created after the configuration is changed” and that “Existing containers retain the logging driver options that were used when they were created.” Editing daemon.json and restarting Docker leaves every existing container on the options it was created with, so one that had no cap stays uncapped until you recreate it.
With a remote driver, docker logs reads only from a local cache that Docker Engine turns on automatically when a driver cannot be read back; Docker’s dual logging page documents it, and the first question below covers the error you get when it is off. What to keep, and for how long, once the lines leave the host is a separate decision: how long to keep application logs.
Dozzle: a browser view of container logs
Dozzle is an open-source web viewer that streams Docker container logs live and does not store them. It runs as a container with the Docker socket mounted. Its own docs call that socket access, unless restricted, equivalent to root on the host, so it belongs behind authentication whenever the internet can reach it.
Dozzle’s documentation gives the start command as a docker run with /var/run/docker.sock mounted, a /data volume for settings and port 8080 published, and it is MIT-licensed. If the question is how to view container logs in a browser rather than a terminal, running Dozzle on the Docker host is the short answer.
The socket is the part to take seriously. Docker Engine security says “only trusted users should be allowed to control your Docker daemon”. Dozzle’s docs add that a read-only :ro mount “does not limit the API”, and point to a socket proxy in front of the daemon when you need to restrict what Dozzle can do. Put it behind its simple login, OpenID Connect or a forward proxy; keep its shell and container actions off (both are disabled by default, and the docs say to keep them disabled unless you need them); and in forward-proxy mode publish only the proxy, never Dozzle’s own port.
Dozzle can match log patterns and send notifications, but it keeps no log history of its own, so search across last week and any retention still need a real log store.
Docker stats: checking container memory and CPU while you are there
Docker stats shows a live table for each running container: CPU percent, memory used against its limit, network and block I/O, and the number of processes. Adding --no-stream prints it once. With no limit set, a container can use as much memory as the host’s kernel scheduler allows, so that limit figure is not a cap you chose.
The docker stats command is the quickest way to check Docker memory usage per container while you are on the host for the disk. The docker container stats reference describes MEM USAGE / LIMIT as “the total memory the container is using, and the total amount of memory it is allowed to use” and MEM % as the percentage of the host’s memory it is using, and --no-stream pulls one result, which is what you want in a script or an incident note.
When a container runs out of memory, by default the kernel kills processes in it, which can show up as restarts, a separate topic: Docker Compose health checks and restart policies. For the disk side, docker system df summarizes the space Docker uses by images, containers and local volumes.
How to check your own app
Docker log rotation is checked with 5 tests: every container was created after the cap was set or carries its own, no log file exceeds the cap times the file count, a staging container rotates when pushed past the cap, the disk alert fires, and a recreated container’s old lines still exist off the host.
Each check below can fail, and each names the evidence to keep. Run them on the Docker host; the third one belongs in staging.
- 01 List each container's creation time with docker inspect --format '{{.Name}} {{.Created}}' and compare it with the date the log cap went into daemon.json or the Compose file. A container created before that date keeps its old logging options and needs recreating. Keep the list and the change date.
- 02 Run sudo du -sh on each container's log files. No container's total may exceed max-size times max-file. Keep the sizes.
- 03 In a staging container with a small cap, such as max-size=1m and max-file=2, write lines past the cap and list the log folder before and after. A rotated file should appear and the oldest should go (json-file on Linux; the local driver compresses rotated files). Keep both listings.
- 04 If the host has a disk-usage alert, lower its threshold below current usage for one test, wait at least one check interval, confirm the alert arrives naming the host, then put the threshold back. No alert configured is the finding. Keep the alert and the times.
- 05 Recreate one container, then search for its lines from the day before wherever logs are kept off the host. If none exist, the container's file was the only copy. Keep the search and its result.
A container’s HostConfig.LogConfig shows the driver and options it was created with, and Docker Engine’s source merges the daemon’s defaults into it at creation, so a json-file container with no max-size there has no cap.
In the Production Hardening Sprint, deliverable 8.5, log retention, is verified this way: “Inspect the configured windows and verify retention behavior in supported systems.”
Where the sprint fits
The sprint’s deliverable 8.5, log retention, is to set and document log retention across the application’s services. The fee covers our engineering work; hosting, paid tools and API usage remain in your accounts, and we explain any required third-party costs before enabling them. Your app’s current framework and hosting setup are our starting point. Every deliverable and how we verify it is in the published scope.
Common questions about Docker container logs
What does the error “Configured logging driver does not support reading” mean and how can I fix it?
The container uses a driver that sends its lines somewhere else, and the local cache that lets docker logs read them back is switched off. Docker prints “Error response from daemon: configured logging driver does not support reading” in that case. The fix is to turn the dual logging cache back on, by removing cache-disabled or setting it to "false", and recreate the container, or to read the lines where the driver sends them.
The cache keeps at most 5 files of 20 MB each per container by default, before compression, and its size is set with cache-max-size and cache-max-file.
How can I store docker logs in a file?
With json-file or local they are already in a file on the host, one per container. For a copy you can move or attach to a ticket, run docker logs app > app.log 2>&1, which keeps stderr lines too. For a store that survives the container, ship the logs off the host with a remote driver or a collector.
How do I clear my docker cache?
That is a different cleanup from container logs. docker builder prune removes build cache only. docker system prune removes stopped containers, unused networks, dangling images and unused build cache, and adding --volumes also prunes anonymous volumes, so read its warning before you confirm. None of it touches the log of a running container.
docker system prune asks for confirmation unless you pass -f, and it leaves volumes alone by default “to prevent important data from being deleted”.
Can you safely delete log files?
Not while a running process still holds one open: on Linux the space is not freed until the last open descriptor closes, so the disk stays full. Empty the file instead, and copy it somewhere else first if something is going wrong.
What are the best practices for logging in docker containers?
My working rules: write one JSON object per line to stdout, cap every container’s log with max-size and max-file or the local driver, ship the lines off the host so a recreate does not delete the only copy, and put a disk-usage alert on the host.
What the app itself should log, how to strip secrets and personal data before an event leaves the process, and how to wire an error tracker are in error logging best practices for a solo app.
If you have a working app built with these tools and need it ready for real customers, this is what we do.
Built it with AI. Now it has to hold up for real customers.
The Production Hardening Sprint takes the app you already have and builds the production foundation underneath it. Authentication and access rules, payments that stay consistent, error handling, monitoring, backups, automated tests and a documented handover. Our engineers work inside your existing codebase for ten working days. All 123 deliverables are included, and you get the evidence for each one.
See the Production Hardening Sprint →
$2,500 fixed price · 10 working days · One codebase