| Tested on | Red Hat Enterprise Linux 10.2 (Coughlan) |
|---|---|
| Package | podman-5.8.2-5.el10_2.x86_64 |
| Applies to | Linux hosts with Podman where you need to read, follow, or filter container and pod stdout/stderr |
| Privilege | Normal user for rootless containers; root when inspecting rootful journal or system paths |
| Scope | podman logs and podman pod logs, -f/--follow, --tail, --since/--until, --timestamps, multi-container and --color output, log drivers (journald, k8s-file, none, passthrough), finding log paths with inspect, --log-opt path and max-size, global log_size_max pointer, podman logs versus journalctl, and logs versus podman events. Does not cover health-check log history, full journald administration, application-specific log files, or Podman events depth. |
| Related guides | Inspect Podman containers Podman Quadlet Run containers with Podman Podman vs Docker |
When a container misbehaves, the first question is usually what it printed. podman logs reads captured stdout and stderr from the container runtime — not arbitrary files under /var/log inside the image unless your application sends them to the console.
This guide walks through follow mode, time filters, pod-level aggregation, log drivers, and where Podman actually stores records on Podman 5.8.2.
Lab setup
Create a working directory and a container that emits a line every two seconds:
mkdir -p ~/podman-container-logs-lab && cd ~/podman-container-logs-labStart a detached Alpine container that prints an incrementing line every two seconds:
podman run -d --name log-demo docker.io/library/alpine:latest sh -c 'i=1; while true; do echo "message $i"; i=$((i+1)); sleep 2; done'Give it a few seconds to print before you read logs.
View container logs with podman logs
Fetch everything captured so far:
podman logs log-demoSample output:
message 1
message 2
message 3podman logs reads stdout and stderr the runtime captured. It does not tail /var/log/nginx/access.log or other in-container files unless nginx writes access lines to stdout or you open those paths with podman exec.
Follow logs in real time with -f
Attach to new lines as they appear:
podman logs -f log-demo-f and --follow keep the command open until you press Ctrl+C. If a container is removed while you follow — especially with --rm — the last lines can disappear before the reader consumes them. That is rare in day-to-day troubleshooting but worth knowing when debugging short-lived jobs.
Show only the last N lines
Skip the full history when you only need recent context:
podman logs --tail 20 log-demoCombine tail with follow for live troubleshooting without replaying the entire buffer:
podman logs --tail 20 --follow log-demoFilter logs with --since
Relative durations work for recent windows:
podman logs --since 10m log-demoSample output:
message 1
message 2
message 3Accepted forms include relative durations (10m, 2h) and absolute timestamps depending on your Podman build. Use --since when you care about output after a restart or deployment, not the container's entire lifetime.
Stop output at a time with --until
Narrow a window with both bounds:
podman logs --since 30m --until 5m log-demoOn a young lab container this may return the same lines as --since 10m because the workload has not existed long enough to hit the upper bound. On a long-running service, --since and --until help correlate stdout with an incident time, a Quadlet restart, or entries from Podman events on the same clock.
Add timestamps
Prefix each line with the capture time:
podman logs --timestamps log-demoSample output:
2026-08-23T07:49:29.205296000+05:30 message 1
2026-08-23T07:49:31.212518000+05:30 message 2
2026-08-23T07:49:33.226699000+05:30 message 3Timestamps matter when you compare container output with journalctl, application logs, or an event timeline. Combine with a time filter:
podman logs --timestamps --since 5m log-demoRead logs from multiple containers
Podman accepts several container names in one command:
podman logs web workerCreate two echo loops first if you are reproducing the lab:
podman run -d --name web docker.io/library/alpine:latest sh -c 'i=1; while true; do echo "web $i"; i=$((i+1)); sleep 2; done'Add a second container with a slightly slower cadence so interleaved output is easy to spot:
podman run -d --name worker docker.io/library/alpine:latest sh -c 'i=1; while true; do echo "worker $i"; i=$((i+1)); sleep 3; done'Colorize interleaved output in an interactive terminal:
podman logs --color web workerSample output (ANSI color codes trimmed in the transcript):
3dbb04ab4f75 web 1
3dbb04ab4f75 web 2
efd91e8f823e worker 1
efd91e8f823e worker 2Interleaved multi-container output does not guarantee strict chronological order across processes. Use --timestamps when ordering matters.
View all logs from a pod
Pods group containers that share a network namespace. Aggregate their stdout/stderr with podman pod logs:
podman pod create --name application-podAttach a web-style member that prints every two seconds:
podman run -d --pod application-pod --name app-web docker.io/library/alpine:latest sh -c 'i=1; while true; do echo "web $i"; i=$((i+1)); sleep 2; done'Add a worker member on a three-second loop:
podman run -d --pod application-pod --name app-worker docker.io/library/alpine:latest sh -c 'i=1; while true; do echo "worker $i"; i=$((i+1)); sleep 3; done'After a few seconds, read the combined stream:
podman pod logs --tail 8 application-podSample output:
70495fe5706a web 1
70495fe5706a web 2
30c08ae999d6 worker 1
30c08ae999d6 worker 2Each line is prefixed with the container ID so you can tell which member printed it. Filter one container:
podman pod logs --container app-web --tail 5 application-podSample output:
web 1
web 2
web 3
web 4Follow the whole pod:
podman pod logs -f application-podIf you add a container to a running pod while podman pod logs -f is already attached, restart the log command to include the new member — the follow session does not always pick up dynamically added containers.
Check the active Podman log driver
Do not assume the default from memory. Ask Podman:
podman info --format '{{.Host.LogDriver}}'Sample output on this RHEL 10.2 host:
journaldLinux-relevant drivers include:
journald
k8s-file
none
passthrough
passthrough-ttyjson-file is accepted as an alias for k8s-file for Docker compatibility.
Use the journald log driver
Make journald explicit on a new container:
podman run -d --name journal-demo --log-driver journald docker.io/library/alpine:latest sh -c 'i=1; while true; do echo "journal $i"; i=$((i+1)); sleep 3; done'Read through Podman:
podman logs journal-demo --tail 3Sample output:
journal 1
journal 2
journal 3Correlate with the system journal on a rootful host:
journalctl CONTAINER_NAME=journal-demo -n 5Sample output:
Aug 23 07:50:03 vm1.lab.example journal-demo[317999]: journal 3
Aug 23 07:50:06 vm1.lab.example journal-demo[317999]: journal 4
Aug 23 07:50:09 vm1.lab.example journal-demo[317999]: journal 5With journald, rotation and retention follow systemd-journald policy — not a ctr.log file under the graph root. Rootless hosts may need different journalctl selectors; inspect the fields your container actually receives.
Use k8s-file
File-backed logging writes CRI-style records Podman can replay:
podman run -d --name file-log-demo --log-driver k8s-file docker.io/library/alpine:latest sh -c 'i=1; while true; do echo "file $i"; i=$((i+1)); sleep 3; done'Read through the usual command:
podman logs file-log-demo --tail 3Sample output:
file 1
file 2
file 3On Podman 5.8.2, resolve the on-disk path from inspect — not Docker's {{.LogPath}} template, which errors on this build:
podman inspect --format '{{.HostConfig.LogConfig.Path}}' file-log-demoSample output:
/var/lib/containers/storage/overlay-containers/6c7c3143ee18c3f7b00947f2e8f6844d592ea3e6f975731206f8dee616f5cea7/userdata/ctr.logConfirm the file exists:
ls -lh "$(podman inspect --format '{{.HostConfig.LogConfig.Path}}' file-log-demo)"Sample output:
-rw-r-----. 1 root root 574 Aug 23 07:50 .../userdata/ctr.logFind Podman logs on disk
For k8s-file and compatible drivers, always derive the path from the container you care about:
podman inspect --format '{{.HostConfig.LogConfig.Path}}' file-log-demoDo not hard-code /var/lib/containers/storage/... in runbooks. Rootful and rootless graph roots differ, storage can be relocated in storage.conf, and journald containers may have no ctr.log at all.
Configure an explicit log path
Override the default file location when your environment allows it:
podman run -d --name custom-path --log-driver k8s-file --log-opt path=/tmp/podman-demo.log docker.io/library/alpine:latest sh -c 'echo custom-path-test; sleep 3600'Verify the file Podman created:
ls -l /tmp/podman-demo.logSample output:
-rw-r-----. 1 root root 62 Aug 23 07:50 /tmp/podman-demo.logRootless containers may not write arbitrary root-owned paths under /var/log without permissions and SELinux context. Prefer user-writable locations or adjust policy deliberately — not broad chmod on system directories.
Limit file log size
Cap growth for chatty workloads:
podman run -d --name maxsize-demo --log-driver k8s-file --log-opt max-size=1mb docker.io/library/alpine:latest sh -c 'i=1; while true; do echo "maxsize line $i $(date -Iseconds)"; i=$((i+1)); sleep 0.1; done'After fifteen seconds the log file was still only 21K, so the 1mb limit had not been reached:
ls -lh "$(podman inspect --format '{{.HostConfig.LogConfig.Path}}' maxsize-demo)"Sample output:
-rw-r-----. 1 root root 21K Aug 23 07:50 .../userdata/ctr.logWhen the file reaches max-size, Podman and conmon truncate and reopen the log rather than allowing it to grow beyond the configured limit. This is not Docker-style rotation into .1, .2, backup files. max-size applies to Podman's file log handling only — it does not replace journald retention when the backend is journald. For journald-backed containers, tune systemd-journald instead of --log-opt max-size.
Set a global container log size limit
Site-wide defaults can live in Podman containers.conf under the [containers] table:
[containers]
log_size_max = 10485760log_size_max sets the default maximum size for Podman's container log file. It applies to file-backed container logging; journald retention is controlled by systemd-journald instead. Positive values must be at least 8192 bytes — the 10485760 example above is valid.
Disable logging with none
Skip capture when another system owns observability:
podman run -d --name none-demo --log-driver none docker.io/library/alpine:latest echo hello-nonepodman logs has nothing to read:
podman logs none-demoSample output:
Error: this container is using the 'none' log driver, cannot read logs: this container is not logging outputUse none only when you intentionally log elsewhere. Do not disable capture merely to save disk without a replacement.
passthrough and passthrough-tty
These drivers pass stdio through rather than recording normal Podman logs. They suit specific foreground or TTY workflows, not typical detached services. Remote Podman and TTY edge cases make them a poor default for production containers you troubleshoot with podman logs.
Podman logs vs journalctl
| Topic | podman logs |
journalctl |
|---|---|---|
| Interface | Podman log abstraction | systemd journal |
| Drivers | Works with captured drivers Podman supports | Natural fit for journald backend |
| Portability | Same command across Podman hosts | systemd-specific |
| Scope | Container stdout/stderr | Broader system and unit messages |
For Quadlet-managed services, journalctl -u web.service can include systemd start/stop lines alongside container output — useful when the container exited but the unit still tells part of the story.
Logs vs events
| Source | Shows |
|---|---|
podman logs |
Application stdout/stderr |
podman events |
Lifecycle actions — create, start, stop, die, pull |
If a container vanished overnight, check Podman events for whether it was removed or OOM-killed, then use logs (or journal history) for what it printed leading up to exit. Events explain what happened; logs explain what the process said.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
cannot read logs with none driver |
Logging disabled intentionally | Use another driver or external logging |
Empty podman logs right after start |
No output yet or very fast exit | Wait, or check podman ps -a and events |
can't evaluate field LogPath |
Podman 5.x inspect template | Use {{.HostConfig.LogConfig.Path}} |
| No file at expected storage path | Wrong graph root or journald backend | podman info and inspect log driver |
pod pod logs missing new container |
Follow started before member joined | Restart podman pod logs -f |
Rootless cannot write custom /var/log path |
Permissions or SELinux | Use a user-writable path or adjust policy |
References
- podman-logs(1) — flags and multi-container usage
- podman-pod-logs(1) — pod aggregation and
--container - podman-run(1) — log-driver and log-opt — driver options
- Red Hat — Building, running, and managing containers — logging on RHEL-family systems
Summary
podman logs is how you read captured stdout and stderr from containers. Use -f to follow live output, --tail to limit history, and --since/--until with --timestamps when you are correlating incidents. Multiple containers interleave in one stream; podman pod logs adds pod-wide aggregation and --container filtering.
On this RHEL 10.2 host the default driver is journald, so retention follows the system journal. k8s-file stores CRI-style records on disk — resolve the path with podman inspect --format '{{.HostConfig.LogConfig.Path}}' rather than guessing under /var/lib/containers. --log-opt max-size truncates file logs at the configured limit; none disables capture entirely.
Logs show what the application printed. Podman events show lifecycle changes. Use both when a container disappears or misbehaves after a restart.

