Chapter 23Lesson 01~120 minutes

Logs, Logging Drivers, Rotation, stdout/stderr Contracts, Events, stats, and Container Observability: Concepts, Architecture, and Mental Model

Separate Docker application stdout/stderr, logging-driver storage or transport, Engine events, stats metrics, and daemon logs into a coherent observability model.

Container observabilityLogging driversEvents & statsRotation & retentionEvidence-first

Learning objectives

  • Separate application stdout/stderr from logging-driver storage or transport, Engine events, runtime metrics, and daemon logs.
  • Explain how a container log line becomes driver-owned evidence without treating Docker-managed files as an application API.
  • Record container identity, image digest, logging configuration, timestamps, event actor, and stats sample as one correlated evidence set.
  • Recognize retention, delivery, and platform boundaries before an incident occurs.
Chapter 23 principle. Observability is a chain of distinct evidence sources. Application stdout/stderr says what the process emitted; a logging driver decides how Docker stores or transports it; Engine events record lifecycle actions; docker stats samples runtime counters; daemon logs describe Engine-side problems; and an external platform proves only what actually arrived there. Never collapse those into one “Docker log.”

1. The practical problem: one incident, several evidence planes

A container can be unhealthy while its application log is perfectly readable. A container can also emit useful stdout while a remote logging sink is unavailable, or consume memory rapidly without emitting any application error. If all of those are called “the logs,” diagnosis becomes guesswork.

The operational goal is therefore to identify the producer, transport/storage path, retention policy, and identity/timestamp for each signal. Chapter 22 measured resource controls; this chapter turns those runtime observations into a coherent incident timeline.

2. Mental model: process output, Engine events, and metrics are parallel signals

The application writes bytes to stdout and stderr. Docker connects those streams to the selected logging driver. A file-based driver stores records on the daemon host; a remote driver transports them to another system. Separately, the Engine emits object lifecycle events, and the runtime exposes resource counters that docker stats samples. The daemon itself has its own logs. Correlation happens only when you preserve shared identity and time.

Container observability signal paths
  flowchart TD
    A[Application process] -->|stdout / stderr| B[Container stdio]
    B --> C[Docker logging driver]
    C --> D[Local driver-owned storage]
    C --> E[Remote logging sink]
    F[Docker Engine lifecycle] --> G[Engine event stream]
    H[Runtime / cgroups / network counters] --> I[docker stats / API]
    J[dockerd / containerd / Desktop VM] --> K[Daemon logs]
    D --> L[Correlated incident timeline]
    E --> L
    G --> L
    I --> L
    K --> L
            

3. The stdout/stderr contract

A container-friendly application normally emits operational logs to stdout and stderr and treats files inside the container writable layer as ephemeral runtime state. Docker captures stdout/stderr and passes it to the active logging driver. The driver is an Engine concern; the application should not need to know whether the operator selected local, json-file, journald, or a remote service.

stdout versus stderr is useful context, not a severity schema. Many applications write all structured logs to stdout; others reserve stderr for errors. If severity matters, include an explicit structured field such as "level":"error".

# Read-only baseline before creating anything
docker context show
docker version
docker info --format 'default_logging_driver={{.LoggingDriver}}'
docker ps --format 'table {{.ID}}	{{.Image}}	{{.Names}}	{{.Status}}'

4. Logging drivers: storage/transport policy belongs to the container configuration

Driver / mode What it does Important evidence
json-file Daemon default; JSON records for stdout/stderr. No rotation unless configured. HostConfig.LogConfig, explicit max-size/max-file, disk trend.
local Docker-optimized local format with rotation and compression by default. Driver type; default or explicit size/count; docker logs output.
Remote driver Transports records to syslog/journald/fluentd/GELF/cloud/vendor endpoint depending on driver. Endpoint, delivery status, driver errors, remote receipt, local dual-log cache behavior.
Blocking delivery Application writes can backpressure behind a slow driver. Driver/sink latency and application stalls.
Non-blocking delivery Per-container buffer decouples the application; new messages are dropped if buffer fills. Buffer setting plus a documented acceptance of possible message loss.
Do not read Docker-managed log files directly. Docker documentation warns that json-file and local files are daemon-owned implementation storage. Use docker logs, the Engine API, or the configured external sink; external mutation/read tooling against those files can interfere with Docker.

5. Identity and time are part of the observation

A log line without container/image identity is ambiguous after replacement. A container name is convenient but reusable. Preserve the container ID, image reference and immutable repository digest where available, creation/start timestamps, logging driver/options, labels, and project/service labels for Compose workloads.

# Replace NAME with an existing disposable container if you have one
docker inspect NAME --format 'container={{.Id}} image_id={{.Image}} created={{.Created}} log={{json .HostConfig.LogConfig}} labels={{json .Config.Labels}}'

6. Engine events answer “what changed?”

docker events is a real-time Engine event stream, not a durable audit database. Current Docker documentation states that only the last 256 events are returned from the daemon history. Use narrow time ranges and filters during an incident, and export durable audit/monitoring data elsewhere when retention matters.

Useful container events include create, start, die, stop, restart, oom, health_status, and exec_*. Multiple filters on different keys are ANDed; repeating the same filter is ORed.

docker events   --since '10m'   --filter type=container   --filter event=die   --format '{{json .}}'

7. stats answers “what was the runtime doing at this sample?”

docker stats reports a live stream for running containers, or one sample with --no-stream. It includes CPU, memory, network I/O, block I/O, and PIDs on Linux. The CLI and Engine API are not identical representations: on Linux the CLI subtracts cache from displayed memory usage, while the API exposes raw usage plus cache fields so clients can calculate their own view.

The PIDs field includes processes and kernel threads. A large PIDs count with few visible processes may indicate a highly threaded application rather than a process leak.

docker stats --no-stream --format '{{json .}}' NAME

8. Daemon logs are a different failure domain

If the logging driver cannot write, the Engine cannot connect to a remote sink, or container lifecycle operations fail before the application runs, daemon logs may contain the relevant evidence. Location is platform-specific: Linux commonly uses journalctl -xu docker.service; Docker Desktop stores VM service logs under its platform-specific Desktop log path; Windows containers use Windows Event Log.

Do not enable debug logging casually on a shared daemon. First capture normal daemon evidence and reproduce the smallest safe scope.

9. DevOps connection: observability must be independently verifiable

A reproducible operating model records exact image identity, runtime configuration, logging policy, event time, metric sample, and external delivery proof. A dashboard screenshot alone is not enough if you cannot tie it to a container ID and image digest. Conversely, raw logs alone are not enough if you cannot tell whether the process was OOM-killed, restarted, or disconnected from its sink.

Knowledge check

Why is “check the Docker logs” an incomplete instruction?

Does the default json-file driver rotate automatically?

What does a docker events die record prove?

Why might docker stats memory differ from raw API memory usage on Linux?

Why preserve image digest alongside container logs?

Next lesson

Next: Logs, Logging Drivers, Rotation, stdout/stderr Contracts, Events, stats, and Container Observability: Guided Hands-On Workflow and Core Operations

Continue with the next lesson in the course sequence and carry forward the evidence-first Docker operating model.

Official references and version notes

Version baseline, verified 2026-09-21.

Docker Engine 29.8.1 is the current Engine baseline used for compatibility notes. The daemon default logging driver remains json-file; Docker recommends local for general use because it rotates by default. The mandatory labs configure logging per container so they do not require editing daemon.json or restarting Docker. Always record docker version, docker info, context, the actual per-container HostConfig.LogConfig, and platform-specific daemon-log location instead of assuming defaults.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.