View and Follow Container Logs with Podman

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:

bash
mkdir -p ~/podman-container-logs-lab && cd ~/podman-container-logs-lab

Start a detached Alpine container that prints an incrementing line every two seconds:

bash
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:

bash
podman logs log-demo

Sample output:

output
message 1
message 2
message 3

podman 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:

bash
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:

bash
podman logs --tail 20 log-demo

Combine tail with follow for live troubleshooting without replaying the entire buffer:

bash
podman logs --tail 20 --follow log-demo

Filter logs with --since

Relative durations work for recent windows:

bash
podman logs --since 10m log-demo

Sample output:

output
message 1
message 2
message 3

Accepted 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:

bash
podman logs --since 30m --until 5m log-demo

On 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:

bash
podman logs --timestamps log-demo

Sample output:

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 3

Timestamps matter when you compare container output with journalctl, application logs, or an event timeline. Combine with a time filter:

bash
podman logs --timestamps --since 5m log-demo

Read logs from multiple containers

Podman accepts several container names in one command:

bash
podman logs web worker

Create two echo loops first if you are reproducing the lab:

bash
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:

bash
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:

bash
podman logs --color web worker

Sample output (ANSI color codes trimmed in the transcript):

output
3dbb04ab4f75 web 1
3dbb04ab4f75 web 2
efd91e8f823e worker 1
efd91e8f823e worker 2

Interleaved 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:

bash
podman pod create --name application-pod

Attach a web-style member that prints every two seconds:

bash
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:

bash
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:

bash
podman pod logs --tail 8 application-pod

Sample output:

output
70495fe5706a web 1
70495fe5706a web 2
30c08ae999d6 worker 1
30c08ae999d6 worker 2

Each line is prefixed with the container ID so you can tell which member printed it. Filter one container:

bash
podman pod logs --container app-web --tail 5 application-pod

Sample output:

output
web 1
web 2
web 3
web 4

Follow the whole pod:

bash
podman pod logs -f application-pod

If 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:

bash
podman info --format '{{.Host.LogDriver}}'

Sample output on this RHEL 10.2 host:

output
journald

Linux-relevant drivers include:

text
journald
k8s-file
none
passthrough
passthrough-tty

json-file is accepted as an alias for k8s-file for Docker compatibility.


Use the journald log driver

Make journald explicit on a new container:

bash
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:

bash
podman logs journal-demo --tail 3

Sample output:

output
journal 1
journal 2
journal 3

Correlate with the system journal on a rootful host:

bash
journalctl CONTAINER_NAME=journal-demo -n 5

Sample output:

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 5

With 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:

bash
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:

bash
podman logs file-log-demo --tail 3

Sample output:

output
file 1
file 2
file 3

On Podman 5.8.2, resolve the on-disk path from inspect — not Docker's {{.LogPath}} template, which errors on this build:

bash
podman inspect --format '{{.HostConfig.LogConfig.Path}}' file-log-demo

Sample output:

output
/var/lib/containers/storage/overlay-containers/6c7c3143ee18c3f7b00947f2e8f6844d592ea3e6f975731206f8dee616f5cea7/userdata/ctr.log

Confirm the file exists:

bash
ls -lh "$(podman inspect --format '{{.HostConfig.LogConfig.Path}}' file-log-demo)"

Sample output:

output
-rw-r-----. 1 root root 574 Aug 23 07:50 .../userdata/ctr.log

Find Podman logs on disk

For k8s-file and compatible drivers, always derive the path from the container you care about:

bash
podman inspect --format '{{.HostConfig.LogConfig.Path}}' file-log-demo

Do 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:

bash
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:

bash
ls -l /tmp/podman-demo.log

Sample output:

output
-rw-r-----. 1 root root 62 Aug 23 07:50 /tmp/podman-demo.log

Rootless 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:

bash
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:

bash
ls -lh "$(podman inspect --format '{{.HostConfig.LogConfig.Path}}' maxsize-demo)"

Sample output:

output
-rw-r-----. 1 root root 21K Aug 23 07:50 .../userdata/ctr.log

When 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:

toml
[containers]
log_size_max = 10485760

log_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:

bash
podman run -d --name none-demo --log-driver none docker.io/library/alpine:latest echo hello-none

podman logs has nothing to read:

bash
podman logs none-demo

Sample output:

output
Error: this container is using the 'none' log driver, cannot read logs: this container is not logging output

Use 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


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.


Frequently Asked Questions

1. Does podman logs read files inside the container filesystem?

No. podman logs reads captured stdout and stderr from the container runtime. Application log files such as /var/log/nginx/access.log are not included unless the process writes to stdout or stderr or you inspect those files separately with podman exec.

2. What is the default Podman log driver on RHEL?

On the RHEL 10.2 host tested here, podman info reports journald as the default LogDriver. Individual containers can override with --log-driver k8s-file, none, or passthrough variants.

3. How do I follow logs from every container in a pod?

Use podman pod logs -f POD_NAME. Filter one member with --container CONTAINER_NAME. If you add a container to a running pod while a follow session is active, restart the log command to include the new member.

4. Where are k8s-file logs stored on disk?

Use podman inspect --format '{{.HostConfig.LogConfig.Path}}' CONTAINER on Podman 5.8.2. Paths differ for rootful versus rootless stores and depend on storage configuration — do not hard-code a single directory.

5. What is the difference between podman logs and podman events?

podman logs shows application stdout and stderr captured by the log driver. podman events streams lifecycle actions such as create, start, stop, and die. Use events to learn what happened to a container; use logs to read what it printed before exit.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)