How to View, Filter and Manage Docker Logs Without Losing Them or Filling the Disk
Why does a container fail, restart and leave behind almost nothing useful when you go looking for the cause? Docker logs are the first place most engineers check during an incident, and they work well right up until the output goes missing. Sometimes it is buried under thousands of lines, and sometimes it is deleted along with the container.
The docker logs command itself is simple. The difficulty comes from the settings around it, starting with the logging driver and where its files live on disk. If nothing stops those files from growing, a five-minute check can turn into a long investigation, or a full host disk can take healthy services down with it.
This guide treats container output as one signal in log monitoring and wider observability, alongside metrics and traces. It starts with the commands you run on a single host and ends with what production environments need. In this blog, you will see:
How to check docker logs: The core commands for one container, a stopped container or a Compose stack
How to tail docker logs: Live streaming, the last 100 lines, and filtering by time and text
Where Docker stores log files: Paths for Linux, Windows and Docker Desktop, and how to find any container's file
How to rotate and clear logs: Settings that cap disk use, and safe ways to recover space on a filling disk
How to fix empty output: Five common causes of missing logs and the fix for each
How to collect logs at scale: What changes once containers run across many hosts, and what it means for outage time and audits
What are Docker Logs?
Docker logs are whatever a container's main process prints to standard output (stdout) and standard error (stderr). The Docker Engine collects those two streams and stores them through a logging driver. The docker logs command reads that captured output back for one container at a time.
Anything the application prints to the console is captured. Anything it writes to a file inside the container's filesystem is missed, which is the most common reason a docker log looks empty.
Captured: Console output from the main process the container starts, including errors written to stderr
Missed: Log files written inside the container, such as an application log under /var/log, and output from commands run separately with docker exec
Kept per container: Each container has its own log stream, stored until the container is removed
That last point is easy to overlook. With containerization, replacing a container is routine, and its log history goes with it.
What is the Difference Between Container Logs and Docker Daemon Logs?
Container logs hold what your applications print. Docker daemon logs are different: they track the Engine itself, from container starts to driver errors. If a container never starts, look in the daemon log first.
Container output: docker logs api
Docker daemon on systemd Linux: journalctl -u docker.service
On most Linux servers, the daemon logs to the systemd journal. If you need to dig into it, our journalctl guide covers filtering by boot or by priority. First, though, here's why any of this should matter to someone who never opens a terminal.
Why do Docker Logs Matter to the Business?
Docker logs matter to the business because they're usually the only evidence of why a containerized service went down. When nobody can find the right lines, the outage runs longer and the support queue grows with it.
When container logging is left at its defaults, the cost shows up in places a manager tracks:
Longer outages: Time spent hunting for the right log line adds directly to resolution time, and to the hours customers feel the problem
Lost evidence: Logs deleted along with a replaced container leave incident reviews and root cause work without facts
Avoidable failures: An unrotated log that fills a disk can stop services that had nothing to do with the original fault
Engineering hours: Logging in to host after host to read output pulls senior engineers away from planned work
Audit exposure: Regulated organizations must keep logs for set periods under a log retention policy, and container lifecycles do not do that on their own
All five come down to a few settings that this guide walks through. They're cheap to get right at the start, and the place to begin is how Docker captures output at all.
How does Docker Capture Container Logs?
Docker captures container logs from the stdout and stderr of each container's main process, line by line. It doesn't store those lines itself. Every line goes to a logging driver, which picks the destination.
By default the driver is json-file, writing each line to a JSON file on the host, tagged with its stream and a timestamp. Other drivers handle log forwarding instead and send the same output elsewhere. Typical destinations are journald or syslog on Linux, while bigger environments lean on Fluentd or a cloud logging service.
Which Docker Logging Driver Should You Use?
The right docker logging driver comes down to one question: do logs stay on the host, or travel to a central system? The drivers most deployments choose between compare as follows:
Driver | Where output goes | Readable with docker logs | Best fit |
json-file | JSON file on the host | Yes | Default choice, and works with agents that read files on the host |
local | Compressed file on the host, rotated by default | Yes | Single hosts where only Docker reads the logs |
journald | The systemd journal | Yes | Linux hosts already standardized on journald |
syslog | A local or remote syslog server | Yes, through a local cache | Sending output to a central syslog collector |
fluentd or gelf | A Fluentd or GELF-compatible collector | Yes, through a local cache | Pipelines already built on those collectors |
awslogs or gcplogs | A cloud provider's logging service | Yes, through a local cache | Workloads running on that cloud |
none | Discarded | No | Containers whose output is never needed |
Docker's documentation steers most single-host setups to the local driver. Rotation is on by default and the files are compact, yet Docker expects to be the only thing reading them. When a log agent needs those files, json-file with rotation configured is the safer pick.
Two commands confirm what a host and a container are using:
Daemon default: docker info --format '{{.LoggingDriver}}'
One container: docker inspect --format '{{.HostConfig.LogConfig.Type}}' api
With the driver confirmed, reading the output itself takes a single command.
How do You Check Docker Logs?
Checking docker logs takes one command: docker logs plus the container's name or ID, for example docker logs api, which prints all the stdout and stderr output since the container started. There's also docker container logs, which is just the newer way of writing the same command.
These commands cover everyday checks, and the table doubles as a short docker logs command reference drawn from the official docker logs command documentation:
Command | What it tells you |
docker ps | Names and IDs of running containers |
docker ps -a | All containers, including stopped ones |
docker logs api | Full log output for the container named api |
docker container logs api | Same output through the newer command form |
docker logs -t api | Adds a timestamp to the start of every line |
docker logs --details api | Adds extra attributes set through logging options |
That is also the quickest answer to how to see docker logs after a crash, because a stopped container keeps its logs until someone removes it. Run docker ps -a first whenever a service has restarted and the cause is unclear. On Docker Desktop, a container's Logs tab shows the same output.
Consider a checkout service with a restart policy that restarted twice after a deployment. Docker restarts the same container in place, so its log still holds the output from each earlier run, and the exception that ended the last one usually appears just above the new startup messages. This kind of check is where container monitoring begins, though a live incident usually calls for watching new lines arrive.
How do You Tail Docker Logs in Real Time?
Tailing docker logs works with the -f (follow) flag. After printing the existing history, Docker keeps the session open and shows each new line as it's written, similar to tail -f.
On a busy container, follow mode on its own prints the entire history before it reaches anything new. So pairing it with --tail limits that history to a set number of lines, which is the usual way to run docker logs tail during an incident. The combinations below answer most docker tail logs questions, including how to show only the last 100 lines:
Command | What it tells you |
docker logs -f api | Streams new output live until you stop it |
docker logs --tail 100 api | Prints only the last 100 lines, then exits |
docker logs -n 100 api | Short form of the same last 100 lines view |
docker logs -f --tail 50 api | Last 50 lines, then keeps following new output |
docker logs -f --since 10m api | Last ten minutes, then keeps following new output |
Press Ctrl+C to stop following, and the container keeps running. This docker logs follow pattern is the command-line version of live tail, which log platforms offer across many sources at once. A container that's been up for a week can easily have tens of thousands of lines, and nobody wants to scroll through that during an outage.
How do You Filter Docker Logs by Time and Text?
Docker logs can be filtered by time with the --since and --until flags, which take values like 30m, 2h or 2026-10-15. There's no search option for text, so that part goes through grep.
How do You Filter Docker Logs by Time?
To filter docker logs by time, add the docker logs since and until flags with a duration such as 30m, or with a date when the window is further back:
Command | What it tells you |
docker logs --since 30m api | Output from the last 30 minutes |
docker logs --since 2h --until 1h api | The hour that ended one hour ago |
docker logs --since 2026-10-15 api | Everything from that date onward |
docker logs --since 2026-10-15 --until 2026-10-16 api | Output from that single day |
Time zones cause more confusion here than people expect. Docker reads a date with no zone in the local time of the machine running the command. That's why the same query from a laptop in Pune and a server in Frankfurt can return different hours, and why a full timestamp ending in Z, which Docker treats as UTC, is the safer habit.
How do You Search Docker Logs for Specific Text?
Searching docker logs for specific text means piping the output to grep, after first folding stderr into stdout. Error messages usually go to stderr, and without that step they skip grep entirely and print straight to your screen. The 2>&1 redirect fixes this:
Find errors in any case: docker logs api 2>&1 | grep -i error
Show five lines of context: docker logs api 2>&1 | grep -i -C 5 timeout
Count matches in the last hour: docker logs --since 1h api 2>&1 | grep -c "connection refused"
Our grep command guide covers regular expressions and multi-pattern searches in more depth. When the same search has to run across a fleet of hosts, centralized log search returns the matching lines from all of them without anyone needing to log in to each machine.
How do You Save Docker Logs to a File?
To save docker logs to a file, redirect the command's output into a file, which is useful when a log has to be attached to a ticket or sent to an application vendor for review:
Write everything to a file: docker logs api > api.log 2>&1
Watch and save at the same time: docker logs -f api 2>&1 | tee api.log
Each of these commands handles one container. Once you've got a web front end, an API and a database to compare, running three separate commands and matching up the output yourself gets slow.
How do You View Docker Compose Logs and Multiple Containers?
Docker compose logs collects the output of every service in a Compose project into a single stream. Lines are prefixed with the service name, web or db for example, so interleaved output is still easy to follow.
Run them in the folder where the Compose file lives:
Command | What it tells you |
docker compose logs | Output from every service in the project |
docker compose logs web | Output from the web service only |
docker compose logs -f --tail 20 web db | Live output from two services together |
docker compose logs --no-log-prefix web | The same lines without the service name prefix |
docker compose logs --index 2 web | Output from one replica of a scaled service |
Running them from somewhere else works too, as long as you give Compose the path with -f placed before logs, for example docker compose -f path/compose.yaml logs.
How do You View Docker Logs for Multiple Containers Outside Compose?
Without Compose, docker logs reads from one container per run, and there is no flag to pass it several at once. A short shell loop is the usual docker logs multiple containers workaround:
Last 20 lines from every running container: for c in $(docker ps -q); do echo "== $c"; docker logs --tail 20 $c; done
A Swarm service across all its replicas: docker service logs -f web
For three or four containers on one machine, either option does the job. Twenty or thirty containers is a different story, because scanning mixed terminal output during an incident is slow and easy to get wrong, and that's when central log aggregation pays for itself. In both cases, though, the logs are files on the host first, so knowing where Docker keeps them is useful.
Where are Docker Logs Stored?
Docker logs are stored in /var/lib/docker/containers/ on the host when a container runs with the default json-file driver, and each container has a folder there named after its full ID. Other drivers, Windows Server and Docker Desktop all put logs in different places.
The docker logs location changes with platform and driver:
Platform and driver | Where the files live | How to read them |
Linux, json-file | /var/lib/docker/containers/CONTAINER_ID/CONTAINER_ID-json.log | docker logs, or the file itself with sudo |
Linux, local | A subfolder of the same container directory, in a format only Docker reads | docker logs only |
Linux, journald | The systemd journal | journalctl CONTAINER_NAME=api |
Windows Server, Docker Engine | C:\ProgramData\docker\containers\CONTAINER_ID\ | docker logs, or the file itself as an administrator |
Docker Desktop on macOS or Windows | Inside the Linux virtual machine Docker Desktop runs | docker logs, since the files stay inside the virtual machine |
Docker can print the exact path, which saves guessing:
Find any container's log file: docker inspect --format '{{.LogPath}}' api
You can open a json-file log with any text tool. Don't do the same with the local driver's files, which are only meant for the Docker daemon. And when nothing caps their size, these are the files that fill a disk.
How do You Set Up Docker Log Rotation?
Docker log rotation puts a ceiling on how much disk each container's log can use. Docker writes output to files of a fixed size and deletes the oldest one once you hit the file count you've set. If you've set up log rotation for Linux system logs before, it's the same idea, just applied container by container.
Left at its defaults, json-file never rotates, and a single noisy container can keep adding to its log until the disk is full. A reporting service left on debug logging after a release is a common way this happens, since it can write several gigabytes a day until the disk fills and the database container on the same host stops being able to write. The fix goes in /etc/docker/daemon.json, the Docker daemon configuration file on Linux, using these keys:
Setting | Example value | What it does |
log-driver | "local" or "json-file" | Sets the default driver for new containers |
max-size | "10m" | File size at which Docker starts a new file |
max-file | "3" | Number of files kept for each container |
compress | "true" | Compresses rotated files to save space |
Note the quotes around every value, including the numbers. Docker reads them as strings, and a bare number will keep the daemon from starting. After that, four steps take the change live:
Edit the file: Add the log-driver setting and a log-opts block holding the other keys to /etc/docker/daemon.json, or open Settings and then Docker Engine on Docker Desktop
Restart Docker: Run sudo systemctl restart docker on systemd Linux, or restart Docker Desktop
Recreate containers: Existing containers keep their original settings, so recreate them, for example with docker compose up -d --force-recreate
Verify: Run docker inspect --format '{{.HostConfig.LogConfig}}' api and confirm the new options appear
Most failed rotation changes come down to step 3. Existing containers keep whatever settings they were created with, no matter how many times Docker restarts, so docker log rotation can seem broken when it was never applied to them. If only one container needs it, the options can go on the run command:
One container: docker run -d --log-opt max-size=10m --log-opt max-file=3 nginx
A Compose service: Add a logging section to the service, with driver set to local or json-file and options holding max-size and max-file
Rotation turns log growth into a number you can plan disk space around. The side-by-side arithmetic below spells out that ceiling for one container and a busy host, next to the same host with no rotation at all.
How do You Clear Docker Logs Safely?
To clear docker logs for a running container, truncate the log file down to zero bytes with truncate -s 0 and the file's path. Space comes back immediately and the container keeps running. Using rm on the file is tempting but does not help, as Docker keeps the file open, the space is never released and docker logs may start throwing errors.
Which option fits depends on the time pressure and on whether anyone still needs the history, and the table below sets out how to clear docker logs for each case:
Method | Command | When to use it |
Truncate one log | sudo truncate -s 0 $(docker inspect --format '{{.LogPath}}' api) | Emergency space recovery on a json-file container |
Recreate the container | docker compose up -d --force-recreate api | Clears history and applies new rotation settings |
Remove stopped containers | docker container prune | Deletes stopped containers along with their logs |
Wider cleanup | docker system prune | Also removes stopped containers and their logs, plus unused images and networks |
Set rotation | max-size and max-file in daemon.json | Permanent fix that stops the problem returning |
Truncating needs root access and only makes sense for json-file logs, so on the local driver, recreate the container instead. Pruning and removal are permanent, so export anything an incident review will need before you clear docker logs.
Why are Docker Logs Empty or Missing?
Docker logs are usually empty or missing for one of five reasons, and once you've worked out which one you're facing, the fix tends to be small.
1. The Application Writes to a File Inside the Container
Only stdout and stderr reach Docker. An application that writes its log to /var/log/app/app.log inside the container is therefore invisible to docker logs, which comes back empty. Changing the application to log to the console solves it, and where that is not possible, the Dockerfile can link the log files to the output streams:
Send the main log to stdout: RUN ln -sf /dev/stdout /var/log/app/app.log
Send the error log to stderr: RUN ln -sf /dev/stderr /var/log/app/error.log
Several official images, including nginx, use this approach so their access and error logs appear in docker logs.
2. The Logging Driver Cannot Be Read Locally
Switch to a remote driver such as syslog or awslogs, turn off local caching, and docker logs answers with "configured logging driver does not support reading". Docker Engine normally heads this off with dual logging, a small local copy of recent output that lets engineers read logs on the host while the remote system gets them too. If you still see the message, check daemon.json and the container's logging options for cache-disabled set to true, and take it out.
3. The Container Was Removed or Recreated
Removing a container also removes its log files, straight away. Because docker compose up recreates containers whenever an image or configuration changes, each deployment drops the old container's output unless a driver or agent has already shipped it elsewhere.
4. The Application Buffers Its Output
Buffered output is another common cause, where the runtime keeps console lines in memory and writes them out in chunks. A Python worker in that situation might show nothing for ten minutes, then crash and lose everything still in the buffer. PYTHONUNBUFFERED=1 or python -u turns buffering off for Python, and other runtimes have comparable switches.
5. Log Lines Were Dropped Under Load
With non-blocking delivery mode, Docker gives each container a 1 MB buffer by default and drops any lines that arrive after it fills up. In return, the application keeps running at full speed even if the logging driver falls behind, a trade some organizations accept for busy services. Anyone choosing it for a high-volume workload should raise max-buffer-size and still expect to lose lines during a large burst.
Three of these five causes lead to the same outcome, which is evidence that disappears because it never left the host. That is the strongest argument for collecting container logs centrally.
How do You Collect Logs from Docker Containers at Scale?
To collect logs from Docker containers at scale, you need to send each container's output from its host to a central platform, and that has to happen before the container is removed or moved to another host.
The docker logs command was built for one container on one host, and production raises different questions:
Which of dozens of containers threw the first error
What a service logged before the last deployment replaced it
Whether that error lines up with a CPU spike or a slow database call
Answering them needs logs gathered in one observability platform, next to the metrics that show resource use, which our guide on how to monitor Docker containers covers. Three approaches get container output off the host:
Logging driver to a central endpoint: Set the syslog, fluentd or gelf driver so Docker sends each line straight to a collector, while dual logging keeps docker logs available locally
Agent on each host: Run a log agent that reads the json-file logs under /var/lib/docker/containers and forwards them, which keeps local files intact and adds host details
Direct from the application: Send logs from application code through a logging library or an OpenTelemetry SDK, which suits services that already emit traces
Pick any route, but write logs as JSON objects with consistent field names. Consistent fields are what structured logging is about, and they let a central platform filter by service or request ID without depending on fragile text parsing. Kubernetes follows the same principles, although a few details work differently.
What Changes for Container Logs on Kubernetes?
Container logs on Kubernetes work on the same stdout and stderr model as Docker, except that the container runtime and the kubelet take over the driver's job. Output goes to files under /var/log/pods on whichever node runs the pod, and the kubelet handles their rotation. Engineers read them with kubectl logs, which has the same limits as docker logs, because the logs follow the pod's lifecycle and stay on that one node.
One pod: kubectl logs checkout-7d9f
The previous container after a crash: kubectl logs checkout-7d9f --previous
Per-pod commands are fine for a single workload, but seeing what is happening across a whole cluster takes more, as our guide to Kubernetes monitoring explains.
What Should a Central Platform Do with Container Logs?
A central observability platform should keep container output searchable after the container is gone. It should also tie that output to the other signals an engineer checks during an incident.
Collect from every source: Container hosts, servers, network devices and cloud services feeding one normalized stream, through universal log collection
Search and stream: Interactive search and live streaming across hosts, filtered by service, host or severity
Connect the signals: Error lines placed beside the metrics and traces from the same moment, through log correlation
Retain and report: Retention and access controls that keep evidence available for incident reviews and audits
Motadata ObserveOps handles this in its Log Monitoring module, and logs from containerized services correlate with their traces when those services are instrumented through Docker application monitoring. The same approach extends to Kubernetes clusters, including managed Kubernetes services.
What are the Best Practices for Docker Logging in Production?
The best practices for Docker logging come down to six habits that keep logs complete, bounded and available after a container is replaced:
Log to stdout and stderr: Let Docker capture the output, and link any file-based logs to the console streams
Write structured JSON: Use consistent field names for service, request ID and standard log levels
Cap every log on every host: Set max-size and max-file in daemon.json, then recreate existing containers
Match delivery mode to the service: Keep blocking mode where every line matters, and use non-blocking mode with a larger buffer for high-volume services
Ship logs off the host: Forward output to a central platform before containers are removed or rescheduled
Keep secrets out of logs: Strip tokens, passwords and personal data at the source, since anyone with Docker access on a host can read container output
With these six in place, docker logs becomes a quick local check, and the central platform holds the record that incident reviews and audits depend on.
Keep Container Logs After the Container is Gone with Motadata ObserveOps
The docker logs command does its job well on a single host, where it is quick and needs no setup. In production its limits show up together: output is spread across hosts and tied to containers that every deployment replaces, with no link to the metrics and traces that explain it.
For a development laptop or a single small host, docker logs with sensible rotation is often enough, and a central platform adds setup and cost that a small deployment may not justify. Once services span several hosts or a cluster, Motadata ObserveOps brings container output into the same observability view as the rest of your infrastructure logs. It keeps that output searchable after containers are replaced and places each error beside the traces and metrics around it, with clusters covered through Kubernetes APM.
FAQs
How do I see the last 100 lines of docker logs?
Run docker logs --tail 100 followed by the container name, or use the short form -n 100. Add -f to keep streaming new lines after those 100 appear, and press Ctrl+C when you want to stop following without stopping the container itself.
Where are docker logs stored on Linux?
With the default json-file driver, each container's log lives at /var/lib/docker/containers/CONTAINER_ID/CONTAINER_ID-json.log on the host. Run docker inspect with the LogPath format string to print the exact path for any container, and use sudo to read the file directly, since the folder is owned by root.
Can I view docker logs for a stopped container?
Yes. A stopped container keeps its logs until it is removed, so docker logs works the same way after a crash or a clean exit. Run docker ps -a to find the container name, then read its output before any cleanup or redeployment deletes it.
How do I clear docker logs without stopping the container?
Truncate the container's json-file log to zero bytes with truncate -s 0, pointed at the path that docker inspect returns. Treat this as an emergency step, then set max-size and max-file rotation in daemon.json so the log cannot grow without limit again.
How can I collect logs from all Docker containers in one place?
Send container output off each host with a logging driver such as syslog, or run a log agent that reads the container log files and forwards them. Platforms such as Motadata ObserveOps then keep that output searchable alongside metrics and traces after the containers themselves are replaced.
Author
Poonam Lalani
Content Strategist
Poonam Lalani is a B2B content strategist and writer with a background in computer engineering and experience across enterprise technology domains, including AI, cloud, DevOps, data engineering, and IT operations. She specializes in creating research-driven content that simplifies complex ideas and supports product education, thought leadership, and business growth.


