Bitdoze Logo

How to Redirect Docker Logs to a Single File

Learn how to redirect Docker logs to a single file using docker logs commands, json-file driver configuration, and the local driver. Practical guide with code examples.

DragosDragos7 min read
How to Redirect Docker Logs to a Single File

Docker stores each container’s logs in separate files under /var/lib/docker/containers/. When you’re running multiple containers, searching through scattered log files gets old fast. This guide shows three ways to redirect Docker logs to a single file — from a quick one-liner to daemon-wide configuration.

Other Docker guides you might find useful:

Method 1: One-off redirect with docker logs

The simplest way to dump container logs to a file:

docker logs my-container > container.log 2>&1

The 2>&1 part matters. Without it, you only capture stdout. stderr gets lost. This command merges both streams into one file.

To follow logs in real-time and write them continuously:

docker logs -f my-container > container.log 2>&1 &

The -f flag follows new output. The & runs it in the background. This is useful for debugging but has limitations — the process dies when your shell session ends.

To capture logs from multiple containers into one file:

for container in $(docker ps --format '{{.Names}}'); do
  echo "=== $container ===" >> all-logs.log
  docker logs "$container" >> all-logs.log 2>&1
done

When to use this method: Quick debugging, one-off log exports, or when you need a snapshot of what’s happening right now.

Method 2: Configure json-file driver with rotation

Docker uses the json-file logging driver by default. It writes logs as JSON to /var/lib/docker/containers/<id>/<id>-json.log. The catch: no rotation is enabled by default. A chatty container will fill your disk.

Per-container configuration

Set the logging driver when starting a container:

docker run -d \
  --name my-app \
  --log-driver json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  my-app:latest
  • max-size=10m — caps each log file at 10 MB
  • max-file=3 — keeps 3 rotated files (oldest gets deleted)

With these settings, the container uses at most 30 MB for logs.

Daemon-wide configuration

To apply rotation to every new container, edit /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

Restart Docker for the changes to take effect:

sudo systemctl restart docker

Important: Existing containers don’t pick up the new defaults. You need to recreate them. Also, all values in daemon.json must be strings — "max-file": 3 (without quotes) will break the daemon.

Verify the configuration

Check a container’s current logging driver:

docker inspect --format='{{.HostConfig.LogConfig}}' my-app

Find the log file path:

docker inspect --format='{{.LogPath}}' my-app

The local driver is Docker’s recommended replacement for json-file in most situations. It uses a more efficient binary format, compresses rotated files automatically, and has sensible defaults (20 MB per file, 5 files kept).

{
  "log-driver": "local"
}

Or per-container:

docker run -d \
  --name my-app \
  --log-driver local \
  my-app:latest

The docker logs command works the same way with both drivers.

Why json-file is still the default: Docker can’t switch without breaking tools that depend on the json-file layout — Kubernetes being the main one. If you’re not running Kubernetes, use local.

Docker Compose configuration

For Compose stacks, use the logging key:

services:
  api:
    image: my-app:latest
    logging:
      driver: local
  
  worker:
    image: my-worker:latest
    logging:
      driver: json-file
      options:
        max-size: "20m"
        max-file: "5"

To apply the same logging config across all services with a YAML anchor:

x-logging: &default-logging
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

services:
  api:
    image: my-app:latest
    logging: *default-logging
  
  worker:
    image: my-worker:latest
    logging: *default-logging

Where Docker stores logs by default

Before redirecting logs, it helps to understand the default behavior:

  • Docker captures stdout and stderr from every container
  • Each container gets its own log file under /var/lib/docker/containers/
  • Logs are stored in JSON format with timestamps and stream type
  • No rotation is enabled by default (this is the main problem)

Find the log file for a specific container:

docker inspect --format='{{.LogPath}}' my-container

Output looks like:

/var/lib/docker/containers/a4f8c9e1.../a4f8c9e1...-json.log

Each line is a JSON object:

{"log":"Listening on port 8080\n","stream":"stdout","time":"2023-07-03T10:14:02.123456789Z"}

Don’t use external log rotation tools (like logrotate) on Docker’s internal log files. Docker assumes exclusive access. External truncation can corrupt log state or prevent containers from being removed.

Forwarding logs to a central system

For production setups with multiple hosts, consider forwarding logs to a central system:

Syslog driver

docker run -d \
  --log-driver syslog \
  --log-opt syslog-address=tcp://logs.example.com:514 \
  --log-opt tag="{{.Name}}" \
  my-app:latest

Fluentd driver

docker run -d \
  --log-driver fluentd \
  --log-opt fluentd-address=localhost:24224 \
  --log-opt tag="docker.{{.Name}}" \
  my-app:latest

Since Docker 20.10, remote drivers (syslog, fluentd, splunk) automatically maintain a local cache alongside forwarding. docker logs still works. The cache uses the local driver internally with 5 files of 20 MB each.

Other available drivers: journald, gelf (Graylog), awslogs (CloudWatch), splunk.

Common issues

Container logs filling disk: Enable rotation with max-size and max-file. This is the most common Docker disk issue. Without rotation, json-file has no upper bound.

docker logs not showing output after changing driver: Make sure the container was created after the daemon configuration change. Existing containers keep their original settings.

Daemon won’t start after editing daemon.json: Validate the JSON first:

sudo dockerd --validate --config-file /etc/docker/daemon.json

If the daemon is already down, check journalctl -u docker for error details.

Want to disable local caching for remote drivers: Add "cache-disabled": "true" to log-opts.

Which method should you use?

Method Best for Persistence
docker logs > file Quick debugging, one-off exports No (runs in shell)
json-file with rotation Single-host setups, Kubernetes Yes (managed by Docker)
local driver Single-host production setups Yes (more efficient)
syslog/fluentd Multi-host, centralized logging Yes (external system)

For most self-hosted setups, the local driver with default settings is the right choice. It handles rotation automatically and uses less disk than json-file.