What Is Docker Logging? Improve Visibility and Troubleshoot Containers Faster (2026)
Docker logging captures container stdout and stderr so you can troubleshoot failures, track behavior, and manage log volume more effectively. Learn the core commands, logging drivers, storage paths, and best practices for keeping container logs useful at scale.
Docker logging makes container behavior visible fast, but keeping logs useful at scale takes the right drivers, rotation, and centralized collection.
docker logs <container> reads a container’s stdout and stderr, regardless of logging driver (Docker Engine 20.10+).
By default, Docker stores logs on Linux at /var/lib/docker/containers/<container-id>/<container-id>-json.log.
The local driver is a better default than json-file because it rotates logs automatically.
Common flags include –follow, –tail, –since, –until, –timestamps, –details.
Docker logs are the stdout and stderr streams from a running container, captured by a logging driver and sent to a destination such as a local file, syslog, or a remote service. You read them with docker logs <container>, and by default Docker stores them as JSON files under /var/lib/docker/containers/<container-id>/.
In this article, we’ll show you the commands, flags, file paths, and log-management choices, which are important when a container is failing, filling disk space, or generating logs you need to search.
What Is a Docker Container?
A Docker container is a packaged unit of software that includes the application code and every dependency it needs to run, so the program behaves consistently across any environment with compatible runtimes.
Containers isolate the application from the host, which means the code you test on a laptop runs identically in staging and production.
Docker containers work on both Linux and Windows. The open-source Docker Engine launched in 2013 and became the default format for this kind of packaging.
What Is a Docker Image?
A Docker image is a read-only template that contains the code, libraries, system tools, and settings needed to create and run a container. You run an image to create a container.
An image is like a blueprint, and the container is the running instance. You can share images privately inside a team or publicly on Docker Hub.
What Is Docker Logging?
Docker logging is the process of capturing the output of containerized applications, specifically the stdout and stderr streams, and routing that output through a logging driver to a destination where you can store, search, read, and analyze it.
Logs show you what the application is doing: requests served, errors thrown, queries run, processes started, and stopped. Without them, a failing container is a black box.
Why Docker Logging Is Different From Traditional Logging
Traditional applications write logs to a predictable file on a stable server. Docker containers typically write logs to stdout and stderr instead of persistent files. They’re short-lived, they write to streams instead of files, and a single application often runs across many containers at once.
Three things make container logging harder:
Containers are temporary: When a container stops or is removed, any logs written inside it are gone. If you care about historical data, logs have to leave the container before it dies.
Logs come from multiple layers: Application logs, container runtime logs, and host-level daemon logs all matter for debugging, and they rarely share a format.
Scale changes the problem: Ten containers producing a few hundred log lines each is manageable. A thousand containers producing millions of lines is a data pipeline problem.
What Are Docker Container Logs?
Container logs are the stdout and stderr output of the processes running inside a container. Docker captures these streams and stores or forwards them to whichever logging driver is configured.
You view them with these commands:
docker logs <container>: Shows logs from a single container
docker service logs <service>: Shows logs from all containers in a Docker Swarm service
The docker logs Command: Complete Reference
docker logs fetches the logs of a container. In Docker Engine 20.10 and later, it works with most logging drivers because Docker maintains a local cache of logs for command-line access.
Its basic syntax is:
docker logs [OPTIONS] CONTAINER
You can use either the container name or the container ID. Short IDs work; you don’t need the full hash.
Common Command Examples
Here are some common Docker commands:
To read all available logs from a container, use the following command:
To follow logs and keep only the last 50 lines of history, use:
docker logs -f --tail 50 web-app
docker logs Flags: Full Table
“Flags” refers to the optional command-line parameters you can pass to the docker logs command to control how logs are retrieved and displayed.
Flag
Shorthand
Default
What It Does
--follow
-f
false
Streams new log output as it’s written. Exits only when the container stops or you kill the command.
--tail
—
all
Number of lines to show from the end of the logs. Useful on noisy containers.
--since
—
—
Streams new log output as it’s written. Exits only when the container stops, or you kill the command.
--until
—
—
Show logs before a timestamp or relative time. Same format as --since.
--timestamps
-t
false
Prefixes each line with its RFC3339Nano timestamp.
--details
—
false
Shows extra details provided by the logging driver, such as labels or environment variables, if configured.
-n
—
—
Alias for --tail.
Real-Time Log Streaming
docker logs -f attaches your terminal to the container’s log stream and prints new lines as they arrive. It’s the container equivalent of tail -f on a log file.
Use it when you’re watching a deployment, debugging a live request, or confirming that an error has stopped repeating after a fix.
Here are some of its practical uses:
1. If you want to watch logs from all services running in a Docker Compose setup, run:
docker compose logs -f
2. In case you only need logs from a specific service (for example, the web service), use:
docker compose logs -f web
3. To see the last 100 log lines of a container, keep watching new ones as they come in:
docker logs -f --tail 100 web-app
Limits to know about
docker logs -f has the following limitations.
The buffer is in memory. If the log volume is very high, lines can be delayed before they reach your terminal.
docker logs -f doesn’t tail across hosts. For multi-host or scaled workloads, use a log aggregator (Fluentd, Loki, ELK) instead of running -f on each host.
When the container stops, no new logs are produced, and the stream ends. You’ll need to rerun the command to see logs from a new instance.
Filtering and Searching Docker Logs
Docker doesn’t provide a query language for logs. You filter by time with --since and --until, limit volume with --tail, and pipe the output to grep for pattern matching.
Here are the patterns you’ll use most often during an incident.
Filter by Time
1. If you only want to see logs from the last hour, use:
docker logs --since 1h web-app
2. You can check logs from a specific time by setting a start and end time, then use:
This matches any line timestamped between 09:05 and 09:15 on April 17, 2026, assuming timestamps are included in the output.
What Is a Docker Logging Driver?
A logging driver is the component that decides where container output goes after it leaves stdout and stderr. Docker ships with about a dozen drivers, and you can also use plugin-based or install third-party logging drivers from Docker Hub.
If you don’t specify a driver, Docker uses json-file by default.
Three behaviors of json-file worth knowing:
No rotation by default: A chatty container will eat disk space until the host runs out.
It’s the default for backward compatibility: Older Docker versions and some Kubernetes runtimes expect it.
The local driver is usually a better choice: It rotates logs and uses a more efficient on-disk format.
Comparison of Common Docker Logging Drivers
Here’s a tabular comparison of the most common Docker logging drivers:
Set a default driver for the whole Docker daemon by editing /etc/docker/daemon.json:
{
"log-driver": "local"
}
Restart the daemon after editing. Override the default for a single container with --log-driver:
docker run -it --log-driver local alpine ash
Check the active default with:
docker info
Docker Logs With Remote Logging Drivers
Before Docker Engine 20.10, docker logs only worked with the drivers that stored logs locally, such as json-file, and journald. If you used fluentd, awslogs, or another remote driver, the command returned an error because the logs weren’t available locally.
Docker Engine 20.10 fixed this with built-in dual logging. Docker writes a local cache of logs for the CLI to read, even when a remote driver is also active. No configuration needed.
Where Are Docker Logs Stored? (File Locations by Platform)
On Linux, Docker stores container logs in /var/lib/docker/containers/<container-id>/<container-id>-json.log. On macOS and Windows, Docker Desktop runs inside a VM, so you won’t find it at that path on the host. Rootless Docker uses a path under $HOME (typically ~/.local/share/docker/containers/).
Default Linux Path
The default Linux path is /var/lib/docker/containers/<full-container-id>/<full-container-id>-json.log, but the directory structure looks like this:
Note: When using Docker Desktop, the Docker daemon runs inside a virtual machine. Because of this, you usually cannot access the log files directly from your Mac or Windows system unless you connect to that VM. So for day-to-day work, use docker logs. It reads through the API and works the same everywhere.
Docker Logging Delivery Modes: Blocking vs. Non-Blocking
Blocking mode blocks the application’s log writes when the logging driver can’t keep up. Non-blocking mode buffers logs in memory instead. Blocking trades latency for guaranteed delivery. Non-blocking trades guarantee delivery for performance.
Blocking Mode (Default for Supported Drivers)
Every log write waits for the driver to accept the message. If the driver is fast (like json-file writing locally), the wait is invisible. If the driver is slow (like a network-based driver sending to a remote service during network trouble), the application pauses.
Non-Blocking Mode
The container writes logs into an in-memory ring buffer and keeps running. A background worker drains the buffer to the driver. If the buffer fills before the worker can drain it, new log lines are dropped.
Here’s how to configure non-blocking mode in daemon.json:
docker run -it --log-opt mode=non-blocking --log-opt max-buffer-size=4m alpine
When to Use Which Mode
You should choose the mode based on your situation:
Situation
Mode
Why
Default json-file or local driver, normal traffic
Blocking (default behavior for supported drivers)
Local writes are fast enough that blocking isn’t noticeable.
Remote driver (fluentd, awslogs, splunk)
Non-blocking (recommended)
Network hiccups shouldn’t stall the application.
High-volume application, logs are not critical
Non-blocking
Performance matters more than catching every line.
Audit-critical application (payments, healthcare)
Blocking
You need every log line, even at the cost of latency.
Memory-constrained container
Blocking
Non-blocking needs RAM for the buffer. If RAM is tight, the buffer can’t do its job.
Multi-Container and Orchestration Logging
One container is easy. Fifty containers across five hosts is a different problem. At scale, you need orchestration-aware tooling because docker logs only sees the host it runs on.
Docker Compose
Docker Compose is a tool for running multi-container applications defined in a single or more Compose files (commonly docker-compose.yml). A typical Compose project might include a web server, a database, a cache, and a background worker, all running as separate containers that communicate with each other.
When you’re debugging a Compose stack, running docker logs on each container one by one is slow. You’d have to list containers, copy each ID, and check them individually.
Compose solves this with its own logging commands that operate on the whole project.
# To see logs from all services in the project:
docker compose logs
# To follow logs from all services in real time:
docker compose logs -f
# To see only the last 200 lines from a specific service (here, 'web'):
docker compose logs --tail 200 web
# To follow logs from multiple specific services:
docker compose logs -f web worker
Compose prefixes each line with the service name (for example, web_1 | or worker_1 |), which makes cross-service timelines readable. When a request moves from your web service to your worker and then fails, you can watch it traverse services in a single stream instead of jumping between terminal tabs.
Kubernetes
Kubernetes runs containers, but the logging model is different:
kubectl logs <pod> reads from the kubelet, which reads from the container runtime (often containerd, not the Docker daemon directly).
Logs rotate at the kubelet level, not through Docker’s logging drivers.
The node-level agent pattern (Fluent Bit, Vector, Promtail) is the standard way to ship logs off the cluster.
If you’re moving from plain Docker to Kubernetes, expect your logging driver config not to follow you. You’ll configure logging at the node and cluster level instead.
Scaling Challenges
Three problems show up as you scale:
Volume: A thousand containers can generate gigabytes per hour. The local disk can’t retain that long-term.
Correlation: A single user request can span ten services. Without shared trace IDs, you can’t follow it.
Retention: Compliance rules may require 90 or 365 days of logs. Per-host rotation deletes logs long before that.
To fix these three, ship logs off the host into a central store. This is the point at which most of our customers start looking at a dedicated observability platform. When you’re managing container logs alongside metrics from VMs, cloud services, and network gear, stitching it together yourself stops being worth the engineering time.
Clearing, Rotating, and Managing Docker Log Size
docker logs doesn’t have a delete command. To clear logs, you can truncate the underlying JSON file, remove and recreate the container, or configure rotation so logs don’t grow without limit in the first place.
Why Log Size Matters: Disk Space Risk
The json-file driver writes to /var/lib/docker/containers/<id>/<id>-json.log with no size cap by default. A single container printing debug output can fill a 100 GB disk in days. Once the partition is full, Docker operations start failing, so containers can’t write, pull images, or write logs.
Check current log sizes:
sudo du -ch /var/lib/docker/containers/*/*-json.log | sort -h
This caps each log at 10 MB and keeps three rotated files per container (~30 MB total per container). Restart the Docker daemon after saving. Or configure rotation per container:
Truncation is generally safe. The file descriptor stays valid, and Docker continues writing new lines. Deleting the file with rm will disrupt logging for that container until it restarts.
To clear all container logs on a host, use:
sudo sh -c "truncate -s 0 /var/lib/docker/containers/*/*-json.log"
To remove a container entirely (deletes its logs too), use:
docker rm -f <container>
Automate Cleanup
For hosts without rotation configured, a cron job can keep logs bounded:
Better: configure rotation properly and avoid manual log truncation.
Troubleshooting Docker Logs
When docker logs returns nothing, incomplete output, or an error, the cause is almost always one of four things:
The wrong logging driver
A container that exited before writing
An application that logs to files instead of stdout
Buffered output that hasn’t been flushed yet
No Logs Appear
You run docker logs <container> and get nothing back. This usually means one of two things: logging is turned off for the container, or the application is writing its logs somewhere Docker can’t see.
If it’s none, logging is disabled for that container. Remove --log-driver=none from the run command.
2. Check what the process writes:
Docker only captures stdout and stderr. If your application writes logs to a file inside the container (a common pattern for older apps expecting a traditional server environment, for example, /var/log/app.log or /app/logs/server.log), Docker doesn’t capture those lines.
The logs exist, but they’re trapped inside a temporary filesystem that disappears when the container is removed.
You have two ways to fix this:
Reconfigure the application to log to stdout: This is the long-term fix and the pattern Docker is designed for. Most modern frameworks support it through an environment variable or a config change. For example, nginx can be configured to log to /dev/stdout, and most logging libraries (Log4j, Winston, Python’s logging module) support a console handler.
Mount the log file to the host with a volume: If you can’t change the application, bind-mount the log directory so the files survive outside the container: docker run -v /host/logs:/var/log/app myapp. You’ll still need a separate process to tail or ship those files, but at least they’re accessible.
Logs Are Delayed or Incomplete
Python and some JVM (Java Virtual Machine) applications buffer stdout when they detect they aren’t writing to a terminal. The container runs, but logs may not appear until the buffer flushes.
To fix this using Python, run:
docker run -e PYTHONUNBUFFERED=1 myapp
Or add python -u to the command. For Node.js, it typically flushes logs per line, but some libraries may introduce buffering. If yours doesn’t, check its documentation for a flush option.
Container Exits Immediately
If the container exists before you can read logs, run:
docker logs <container-id>
Logs survive as long as the container exists. If you used --rm, the container and its logs are already gone. Rerun without --rm for debugging.
Error: “configured logging driver does not support reading”
You’re on a Docker Engine older than 20.10 with a remote driver like fluentd or awslogs. Either upgrade Docker (dual logging is built in from 20.10+) or read the logs at the remote destination instead.
Wrong Logging Driver for the Use Case
If docker logs works but the volume is overwhelming, you’re probably on json-file with no rotation. Switch to local or add max-size and max-file to the driver options to limit the log growth.
What Are Daemon Logs?
Daemon logs record what the Docker engine itself is doing: container starts and stops, image pulls, network creation, plugin loading, and errors from Docker itself. They’re separate from container logs and are stored and managed by the host operating system.
Container logs tell you what your application did. Daemon logs tell you what Docker did (or failed to do). When a container exits before writing anything, the daemon log is usually the only record of why.
Where to Find Daemon Logs
They are stored in different locations depending on the operating system and setup.
Platform
Location
Linux (systemd)
journalctl -u docker.service
Linux (non systemd)
/var/log/docker.log or /var/log/syslog
macOS (Docker Desktop)
~/Library/Containers/com.docker.docker/Data/log/
Windows (Docker Desktop)
%APPDATA%\Docker\log\
Windows Server
Event Viewer → Applications and Services Logs → Docker
Note: On modern Linux, go to sudo journalctl -xu docker.service
Understanding Docker Dual Logging
Docker dual logging sends container output to two destinations at once, usually a local file and a remote aggregator. If one destination fails, the other still has the data. Docker Engine 20.10 also uses the term internally for its built-in feature that caches logs locally, so docker logs works with remote drivers.
Two different meanings, same name:
Built-in dual logging or Local log cache (20.10+): Docker automatically writes to a local cache alongside the configured driver, so docker logs can read from any driver. No config needed.
User-configured dual logging: You set up a logging pipeline that writes to two destinations for redundancy, audit, or regional compliance.
Benefits of User-Configured Dual Logging
Some of the most common benefits of user-configured dual logging include:
Redundancy: A network outage to your remote aggregator doesn’t lose log data if a local copy is also being written.
Compliance: Some regulations require local retention and off-site backup. One pipeline, two destinations handle both.
Faster triage: On-host logs are instantly available for grep during an incident. Aggregated logs give you cross-host context.
Docker Dual Logging in Practice
IT teams use Docker dual logging it in:
E-commerce, GDPR, and CCPA compliance: logs kept locally for fast debugging and shipped to regional cloud storage for retention audits.
Financial services: logs mirrored to an on-premises SIEM and a cloud archive. If the SIEM is compromised, the archive is untouched.
SaaS reliability: local logs for per-host debugging, centralized logs for the on-call engineer dashboarding across the fleet.
How to Implement Dual Logging
Docker itself doesn’t let you configure two drivers on one container. The standard pattern is:
Use one Docker logging driver that writes locally (json-file or local).
Run a log shipper on the host that tails those files and forwards them to a remote destination.
Centralized Logging Architecture: Agent, Driver, or Sidecar?
There are three common ways to get container logs off a host:
Node-level agent that reads log files
Docker logging driver that pushes directly
Sidecar container per application
Each has trade-offs.
In our experience working with customers across hybrid environments, the node-level agent pattern wins the most often. It’s simpler to operate, it survives container restarts, and it works consistently whether you’re on bare metal, VMs, or Kubernetes.
Node-Level Agent (Recommended for Most Teams)
A single agent (Fluent Bit, Vector, Promtail, Filebeat) runs on every host. It tails container log files commonly under /var/lib/docker/containers/*/*-json.log and forwards to a central store.
Pros
Cons
One config per host, not per container
If the agent crashes, all containers on that host lose shipping until it restarts
Containers don’t need to be aware of logging
Handles rotation gracefully
Works with any logging driver
Logging Driver
The Docker logging driver pushes directly to the destination (Fluentd, AWS CloudWatch, Graylog).
Pros
Cons
No extra process on the host
Network problems can block containers (blocking mode) or lose logs (non-blocking mode)
Switching destinations means reconfiguring every container
Sidecar Container
A second container runs alongside the app container, tailing its logs from a shared volume.
Pros
Cons
Per-app customization
Doubles the container count
Good for Kubernetes where the sidecar pattern is already idiomatic
Adds resource overhead per workload
When to Use Each
Here’s when you should use either of these:
Use a node-level agent when the default choice for VM or bare-metal hosts running many containers
Use the logging driver in small environments, or when you want the simplest possible config
Use a sidecar when Kubernetes workloads need per-pod log transformation before shipping
Best Practices for Docker Logging
Follow these best practices:
Log to stdout and stderr, never to files inside the container because files disappear when the container is removed; streams are captured by Docker.
Use structured logs (JSON) when you can because free-text logs are fine for humans, but parsers and dashboards need structure.
Turn on log rotation from day one. Add max-size and max-file to every production host.
Prefer the local driver over json-file unless you have a reason to stay on the default.
Ship logs off the host. Any production workload should be forwarded to a central store.
Tag logs with service name, environment, and version. This makes searching across a fleet possible.
Monitor the logging pipeline itself. Track disk usage on hosts, queue depth in the shipper, and ingestion rate at the aggregator.
Encrypt log transport. Use TLS between shipper and aggregator, especially over untrusted networks.
Get More from Docker Logs with LM Envision
Docker logs are helpful, but on their own, they only show part of the picture. To troubleshoot containers effectively, you need to connect log activity to infrastructure health, performance metrics, alerts, and recent changes.
With logs, metrics, and events unified in one platform, LogicMonitor helps you move faster from detection to resolution. Instead of treating Docker logs as an isolated troubleshooting step, you can analyze them as part of the full operational story.
That means less time switching between tools and more time resolving issues with confidence. If you want to go beyond manual Docker log review, LogicMonitor can help you turn container data into actionable insights across your environment.
Analyze Docker logs in context with LM Envision
Unify logs, metrics, and events to reduce investigation time and resolve container issues with clearer operational context.
1. What happens to Docker logs when a container is deleted?
When you delete a container (docker rm), its logs are deleted with it. Docker stores logs alongside the container’s metadata, so once the container is gone, the log files are removed as well. To retain logs, you need to ship them to a remote destination or store them outside the container lifecycle.
2. Do Docker logs persist after a container restarts?
Yes. If a container restarts (not removed), its existing logs remain available and new logs are appended to the same log stream. However, if the container is removed and recreated, the logs start fresh unless you’ve configured external log storage.
3. Can I search Docker logs without external tools?
Not really. Docker only provides basic filtering options like --since, --until, and --tail. For keyword or pattern searches, you need to pipe logs to tools like grep or use a centralized logging solution with built-in search capabilities.
4. What’s the difference between docker logs and log files on disk?
docker logs reads container output through the Docker API, giving you a consistent way to view logs regardless of where they’re stored. Log files on disk (like JSON logs under /var/lib/docker/containers/) are the raw storage format used by certain drivers. Accessing files directly can be faster or useful for integrations, but docker logs is safer and more portable for day-to-day use.