## Intro

Docker logging drivers and container observability basics matter because containers start quickly but operating them consistently is harder. A practical guide shows what to configure, which command proves the configuration works, and what failure looks like when the setup is wrong.

This guide explains how Docker logging works, how to inspect container logs, how logging drivers affect observability, and how to prevent uncontrolled disk growth from unrotated log files.

The goal is practical: understand the moving parts, test them locally, and avoid surprises when the same pattern is reused in CI/CD or a production‑like environment.

## Workflow Overview

Start by identifying the resource, the configuration change, and the verification command. Keep the workflow simple: configure one thing, verify the observed state, then document what breaks when the setup is missing, misconfigured, or moved to a production‑like host.

Key concepts: Docker logging, logging drivers, docker logs , log rotation, container observability. Related areas such as Docker debugging, production troubleshooting, and container operations matter because a storage choice influences deployment, debugging, backup, and rollback decisions.

Practical checks

- List running containers with details: docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

- View recent log lines: docker logs <container> --tail 100

- Inspect container configuration: docker inspect <container> (shows mounts, networks, environment, health status)

- For Compose projects: docker compose ps , docker compose logs -f <service> , docker compose exec <service> sh

Data location awareness

Before changing containers, confirm where files are stored.

- Named volume (managed by Docker): app_data:/var/lib/app – easier to reuse across rebuilds.

- Bind mount (host directory): ./data:/var/lib/app – useful for local development but can expose permission, portability, and backup problems if the path does not exist on another machine.

Restart test

Run a small production‑like test: stop the container, recreate it, and verify the application still sees the expected files. If data disappears, the service was likely writing to the container’s writable layer instead of a volume or mount.

Common logging drivers at a glance

<div class="my-stack-md overflow-x-auto">
<table class="w-full min-w-[42rem] border-collapse text-left">
<thead><tr><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Driver</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Typical Use</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Rotation Support</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Remote Destination</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">json-file</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Default on most Linux hosts; local file storage</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Size &amp; count via <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">max-size</code>, <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">max-file</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">No</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">syslog</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Centralised syslog server</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Handled by syslog daemon</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Yes (UDP/TCP)</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">journald</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">systemd journal integration</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Managed by journald</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">No (local)</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">gelf</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Graylog / Logstash</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Handled by remote endpoint</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Yes (UDP/TCP)</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">fluentd</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Fluentd forwarder</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Handled by Fluentd</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Yes (TCP)</td></tr></tbody>
</table>
</div>
Hidden assumptions to surface

- The default driver on many distributions is json-file , but some (e.g., Fedora, RHEL) default to journald .

- The host path /var/lib/docker must have enough free space for log files.

- The user running Docker must have permission to read the log directory for manual inspection.

- In CI runners, the default logging driver may be none ; explicitly set the driver in the job definition.

## Local Pilot Plan

Apply the same workflow to a local pilot. Choose a single service, enable a logging driver with rotation, and verify the behavior before scaling.

Example: enable json‑file driver with size‑based rotation

docker run -d \
 --name webapp \
 --log-driver json-file \
 --log-opt max-size=10m \
 --log-opt max-file=3 \
 nginx:alpine 
 Verify the driver and options

docker inspect --format '{{.HostConfig.LogConfig}}' webapp
# Expected output: map[Type:json-file Config:map[max-size:10m max-file:3]] 
 Observe rotation in action

Generate enough log data to trigger rotation, then list the log files on the host:

# Find the log path
docker inspect --format '{{.LogPath}}' webapp
# Example output: /var/lib/docker/containers/<id>/<id>-json.log
ls -lh /var/lib/docker/containers/<id>/ 
 You should see up to three files, each ≤ 10 MiB. Without max-size and max-file , the single log file grows until the host disk fills – a common production failure.

Compose equivalent

services:
 webapp:
 image: nginx:alpine
 logging:
 driver: "json-file"
 options:
 max-size: "10m"
 max-file: "3" 
 Run docker compose up -d and verify with docker compose logs -f webapp .

Additional verification commands

- Show log disk usage: docker system df -v (look for "Log" column).

- Filter logs by time: docker logs --since 1h --until 2h webapp .

- Follow live output with timestamps: docker logs --follow --timestamps webapp .

Simulate log growth for testing

docker run --rm \
 --log-driver json-file \
 --log-opt max-size=1m \
 --log-opt max-file=2 \
 alpine sh -c 'for i in $(seq 1 5000); do echo "log line $i\); done' 
 After the command finishes, inspect the container’s log directory to confirm two rotated files of roughly 1 MiB each.

## Conclusion

Docker logging drivers and container observability basics work best when the team treats the configuration as something to test, not just copy. Keep examples small, run the commands locally, and confirm the expected behavior before adding more services or automation.

Next step: pick one service, document the exact commands used to build, run, inspect, stop, and recreate it. Compare the results with related areas such as Docker debugging, production troubleshooting, and container operations so the implementation fits the larger operating model.

A reliable container workflow makes failure visible: logs are easy to find, persistent data survives container rebuilds, and local behavior is close enough to production to catch mistakes early.