docker logs is the fastest way to inspect the output of one Docker container on a known host. It retrieves the container's stdout and stderr records that Docker can currently expose, then exits unless you ask it to follow new output.
That makes the command excellent for local incident triage: checking a failed startup, watching a restart loop, or capturing a precise time window. The two most useful patterns are docker logs --tail for bounded history and docker logs --follow for new output. It is not a central archive. What remains available depends on the container's logging driver, local cache, rotation settings, and host storage.
Tail Docker logs for a bounded, timestamped view
The basic form accepts a container name or ID:
docker logs CONTAINER
List running containers before choosing one:
docker ps
Include stopped containers when the process has already exited:
docker ps -a
For an active incident, begin with a small amount of context instead of dumping the entire retained log:
docker logs --tail 100 --timestamps payments-api
This returns the last 100 records and adds Docker's RFC 3339 nanosecond timestamps. The timestamps make it easier to compare container output with a deployment, alert, or request trace.
Follow Docker logs after the initial tail
To keep reading new output after the initial 100 lines, add --follow:
docker logs --tail 100 --follow --timestamps payments-api
The short forms are equivalent:
docker logs -n 100 -f -t payments-api
--follow continues streaming new stdout and stderr output until the command is interrupted. It does not restart the container, attach to its input, or make old records durable. Docker documents the current behavior and accepted options in the official docker container logs reference.
Docker logs flags with practical examples
| Option | What it does | Example |
|---|---|---|
--follow, -f |
Continue with new output | docker logs -f api |
--tail, -n |
Return a number of lines from the end | docker logs -n 200 api |
--timestamps, -t |
Add an RFC 3339 nanosecond timestamp | docker logs -t api |
--since |
Start at a timestamp or relative duration | docker logs --since 15m api |
--until |
Stop before a timestamp or after a relative follow duration | docker logs --until 2026-09-15T13:20:00Z api |
--details |
Include configured log attributes when available | docker logs --details api |
Combine Docker logs tail and follow
Running docker logs -f without a boundary prints all locally available output before it follows new records. On a noisy container, combine follow with tail:
docker logs --tail 50 --follow worker
--tail defaults to all. Docker treats a negative number or a non-integer value as all, so validate variables used in scripts rather than assuming an invalid value will fail safely.
Read a relative time window
Use a Go-style duration for a window relative to now:
docker logs --since 20m --timestamps checkout-api
Durations can include values such as 90s, 20m, or 1h30m. The precise result still depends on what Docker retains locally.
Reconstruct an absolute incident window
Use timestamps with explicit time-zone offsets for a reproducible handoff:
docker logs \
--since 2026-09-15T13:00:00Z \
--until 2026-09-15T13:20:00Z \
--timestamps \
checkout-api
Docker also accepts Unix timestamps and several RFC 3339-compatible forms. If an absolute timestamp has no Z or numeric offset, the Docker client uses its local time zone. Include the offset to avoid shifting the investigation window when another engineer runs the same command elsewhere.
--until requires Docker API 1.35 or newer. It also works with --follow; a relative value can stop a live command after the stated duration:
docker logs --tail 100 --follow --until 15m --timestamps checkout-api
Show configured labels and environment attributes
--details can add labels or environment variables that were explicitly selected through Docker logging options:
docker logs --details --tail 50 checkout-api
It does not expose every container label or environment variable automatically. It also cannot invent application fields such as severity, request ID, trace ID, or customer-safe account ID. Emit those fields in structured application logs when they are needed for investigation, and never place passwords, tokens, cookies, or payment data in log messages or attributes.
Read logs from Docker Compose services
docker compose logs reads service output for a Compose project. It accepts zero or more service names, which is usually clearer than finding generated container names yourself.
Follow two services with a bounded initial tail:
docker compose logs --tail 100 --follow --timestamps api worker
Read a fixed incident window without following:
docker compose logs \
--since 2026-09-15T13:00:00Z \
--until 2026-09-15T13:20:00Z \
--timestamps \
api worker
Compose prefixes lines so you can see which service or replica produced them. Keep the prefix for multi-service incident output. Use --no-log-prefix only when another tool already preserves source identity.
For a scaled service, --index selects one replica:
docker compose logs --index 2 --tail 100 --timestamps worker
The exact output order across containers should be treated as representative, not as a perfectly synchronized distributed timeline. Host clock differences, buffering, and concurrent writes can affect how records appear. The current options are listed in Docker's docker compose logs reference.
Know what the logging driver changes
Every container uses a logging driver. Docker's default is json-file, but a daemon or individual container may use local, journald, syslog, fluentd, or another supported driver.
Check the daemon default:
docker info --format '{{.LoggingDriver}}'
Check the driver assigned to one container:
docker inspect --format '{{.HostConfig.LogConfig.Type}}' payments-api
The none driver records no logs, so docker logs returns no output for that container. For remote drivers that cannot be read directly, Docker normally enables a local dual-logging cache so recent output remains available through docker logs. If that cache is disabled, the command can fail with an error saying the configured driver does not support reading.
Docker currently limits the default dual-logging cache to five files of 20 MB each before compression, per container. That cache is for recent local inspection, not long-term retention. Review Docker's dual logging documentation before changing its limits or disabling it.
Configure rotation before local logs fill the host
The default json-file driver does not rotate logs unless limits are configured. A noisy container can therefore consume substantial disk space. Docker recommends the local driver for general non-Kubernetes use because it rotates by default and uses a more efficient format.
If json-file is required, set explicit limits in the Docker daemon configuration:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "20m",
"max-file": "5",
"compress": "true"
}
}
These values are examples, not universal sizing advice. Choose them from container log rate, available disk, and the time needed for local diagnosis. max-size is unlimited by default, max-file only takes effect when max-size is set, and compression is disabled unless requested.
After changing daemon.json, restart Docker and recreate the affected containers. New daemon defaults do not retroactively change existing containers. Confirm the result with docker inspect rather than assuming the restart updated every workload.
Do not parse or modify json-file storage directly with shell tools. Docker documents those files as daemon-managed. Use docker logs, a supported logging driver, or a deliberately configured collector path. The json-file driver reference documents its rotation controls, while the logging-driver guide covers driver selection and delivery modes.
Rotation protects the host by deleting older local files. It does not preserve the deleted records elsewhere.
Send Docker logs to Fluxtail with a collector
Use docker logs for immediate inspection. Use a continuously running collector when records must remain searchable across containers, hosts, restarts, and local rotation.
Fluxtail documents a Fluent Bit path that reads Docker JSON logs from a read-only host mount, keeps file offsets and retry chunks in writable collector storage, and sends JSON batches to one shared HTTP receiver. The receiver uses TLS on port 443 and a Bearer token bound to that exact receiver.
Keep receiver values outside the collector image and configuration repository:
FLUXTAIL_RECEIVER_HOST=ingest.fluxtail.io
FLUXTAIL_RECEIVER_PORT=443
FLUXTAIL_RECEIVER_PATH=/v1/receivers/YOUR_RECEIVER_ID/logs
FLUXTAIL_TOKEN=YOUR_RECEIVER_TOKEN
The placeholders must be replaced with values copied from one active Fluxtail HTTP JSON receiver. Do not add a guessed path or combine a token from another receiver.
A compact collector configuration follows the same message mapping as the Fluxtail Docker integration. It renames Docker's log field to the required top-level message, rejects empty messages, sends JSON with an explicit content type, verifies TLS, tracks file offsets, and caps the output's filesystem queue:
[SERVICE]
Flush 5
Log_Level info
Parsers_File parsers.conf
Storage.Path /var/lib/fluent-bit/storage
Storage.Backlog.Mem_Limit 10M
[INPUT]
Name tail
Path /var/lib/docker/containers/*/*.log
Parser docker
Tag docker.*
DB /var/lib/fluent-bit/tail.db
DB.Sync normal
Refresh_Interval 5
Skip_Long_Lines on
Docker_Mode on
Storage.Type filesystem
[FILTER]
Name modify
Match docker.*
Rename log message
[FILTER]
Name grep
Match docker.*
Regex message .
[OUTPUT]
Name http
Match docker.*
Host ${FLUXTAIL_RECEIVER_HOST}
Port ${FLUXTAIL_RECEIVER_PORT}
URI ${FLUXTAIL_RECEIVER_PATH}
Format json
Json_Date_Key timestamp
Json_Date_Format iso8601
Header Authorization Bearer ${FLUXTAIL_TOKEN}
Header Content-Type application/json
TLS on
TLS.Verify on
Retry_Limit false
Storage.Total_Limit_Size 1G
Mount both the log directory and state directory into the collector:
volumes:
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./fluxtail-state:/var/lib/fluent-bit
Keep parsers.conf from the documented integration mounted with the main configuration. The Docker log directory stays read-only; the separate state directory holds the offset database and buffered chunks across collector restarts on that host.
Retry_Limit false keeps retrying failed output, while Storage.Total_Limit_Size 1G prevents that output queue from growing without a limit. When the queue reaches its cap, Fluent Bit discards the oldest chunks to accept newer data. Adjust 1G to the host's available disk and required outage window, and monitor the directory rather than treating the example value as a guarantee. Fluent Bit documents the queue behavior in its backpressure guide and the request settings in its HTTP output reference.
The collector's parser, metadata, and filtering configuration determines the final fields. Do not assume that container names, labels, or severity exist until the deployed mapping has been tested. Fluxtail normalizes documented fields such as message, timestamp, severity, service_name, service_namespace, host, and small exact-match labels; additional structured data can be preserved where the receiver permits it.
Follow the current Docker with Fluent Bit documentation for the complete collector path. The Docker container logs guide covers the centralized architecture without replacing this command reference.
Verify collection before depending on it
Generate a unique marker from a named container and keep it running long enough for the collector to read the file:
CHECK_ID="fluxtail-docker-check-$(date +%s)"
CHECK_CONTAINER="fluxtail-log-check-$(date +%s)"
docker run -d --name "$CHECK_CONTAINER" alpine \
sh -c "echo \"$CHECK_ID\"; sleep 300"
docker logs --timestamps "$CHECK_CONTAINER"
Then check the collector and destination in order:
- Confirm the Fluent Bit process is running.
- Inspect its output for file-access, parsing, TLS, authentication, or HTTP errors.
- Open the receiver's named stream in Fluxtail Live Tail.
- Search for the complete
fluxtail-docker-check-...marker. - Confirm the expected host, service, severity, and labels only after verifying how the collector maps them.
- Temporarily block collector egress in a disposable environment and confirm the filesystem queue grows, remains within its limit, and drains after connectivity returns.
A successful HTTP response proves the receiver accepted a batch. Finding the marker in Live Tail proves the event was stored and can be read by the account. Both checks matter.
Remove the test container after both checks pass:
docker rm -f "$CHECK_CONTAINER"
If docker logs is empty but the application should be noisy, inspect the container's logging driver and confirm that the process writes to stdout or stderr. If local logs exist but Fluxtail remains empty, check the collector's file mount, offset database, receiver path, token pairing, TLS status, and active stream filters.
Use the command for local evidence, not retention
The most useful Docker logs command during an incident is usually a bounded combination:
docker logs --since 20m --tail 200 --follow --timestamps CONTAINER
Use --since and --until with explicit offsets for a reproducible historical window. Use Compose service names for multi-container applications. Record the container, host, command, and time assumptions when handing evidence to another engineer.
For history that must survive rotation, container deletion, or host loss, collect the records before the incident. A tested Fluent Bit receiver path gives Fluxtail a continuous stream while docker logs remains available for the fast local check it performs best.