Guides
Guide

How to Use kubectl logs: Flags, Examples, and Fixes

By Sazabi Team

Last verified on Nov 8, 2026.

kubectl logs prints what a container wrote to standard output and standard error. It is the first command to reach for when a pod misbehaves, and it has enough flags to handle crashed containers, multi-container pods, and whole deployments. This guide covers the flags worth knowing, the limits that make output look truncated, where logs live on the node, and how to forward them somewhere durable.

The Basics

Kubernetes captures the output of every container in a running pod. If the pod has only one container, the container name is optional:

kubectl logs my-pod

Common variations:

# Specific namespace
kubectl logs my-pod -n production

# Follow (stream) new lines, like tail -f
kubectl logs -f my-pod

# Last 50 lines, then keep following
kubectl logs --tail=50 -f my-pod

# Everything from the last hour, with timestamps
kubectl logs --since=1h --timestamps my-pod

# From an absolute RFC3339 time
kubectl logs my-pod --since-time=2026-11-08T06:00:00Z

# Cap the output size
kubectl logs my-pod --limit-bytes=500000

--since and --since-time cannot be used together. Without them you get all available lines. --tail defaults to -1, meaning every line, unless you use a selector, in which case it defaults to 10.

You can also name a workload instead of a pod, for example kubectl logs deployment/nginx or kubectl logs job/hello. That is not a view of every replica. Use --all-pods=true for that, as covered below.

Multi-Container Pods

When a pod has several containers, name the one you want with -c, or ask for all of them:

# One container
kubectl logs my-pod -c sidecar

# Every container in the pod
kubectl logs my-pod --all-containers=true

# Same, with the pod and container name on each line
kubectl logs my-pod --all-containers=true --prefix

--prefix adds the source, as pod name and container name, to every line. It matters as soon as more than one source is mixed into the output. Init containers are separate containers, so use -c <init-container-name> for a pod stuck in Init:.

Logs from Many Pods at Once

A label selector fetches logs for every pod that matches:

# Snapshot of all containers in pods with the label
kubectl logs -l app=nginx --all-containers=true

# Follow them all
kubectl logs -f -l app=nginx --all-containers=true

# Every pod behind a deployment
kubectl logs deployment/nginx --all-pods=true

Two limits apply. --max-log-requests caps how many logs are followed concurrently when you use a selector, and the default is 5, so raise it for a larger selector, for example --max-log-requests=20. And with a selector, --tail defaults to 10 lines per pod, so add --tail=-1 for everything. Selector syntax accepts =, ==, !=, in, and notin, as in -l 'tier in (web,api)'. Lines from different pods interleave, so use --timestamps and --prefix together.

For serious multi-pod work, a node-level agent and a log backend scale better than selectors, as described below.

Logs from a Crashed Container

When a container restarts, kubectl logs shows the new instance, which may have written nothing yet. To see the last run that failed, use --previous (-p):

kubectl logs my-pod -c app --previous

This works only while the kubelet still has the old container. By default the kubelet keeps one terminated container, with its logs, per container. If the pod is evicted from the node, its containers and logs go with it.

CrashLoopBackOff

A pod with CrashLoopBackOff in kubectl get pods or kubectl describe pod is starting, exiting, and being restarted with growing delays. Work through it in this order:

  1. kubectl describe pod my-pod and read the container's Last State, Reason, and Exit Code.
  2. kubectl logs my-pod -c app --previous for the final output of the crashed run.
  3. If --previous says there is nothing, the container may never have started. Look at Events in describe, such as image pull errors or failing probes.
  4. If the output stops with no error, think about out-of-memory kills and failed liveness probes, both of which end a process without an application message.

The crash loops guide covers detecting repeated restarts across a cluster. While a pod is rolling over, read its previous logs quickly, because a later restart can replace what --previous returns.

Why Output Looks Truncated

kubectl logs asks the kubelet, and the kubelet reads the log file on the node. The kubelet rotates container logs: containerLogMaxSize defaults to 10Mi and containerLogMaxFiles to 5. Only the contents of the latest file are available through kubectl logs, so a pod that wrote 40 MiB with 10 MiB rotation returns at most 10 MiB. Older logs may still be on the node, but are not served through the API.

Other reasons for a short or empty result:

  • Pod not running yet. --pod-running-timeout (default 20s) is how long to wait for at least one pod to be running.
  • Selector default. --tail is 10 per pod with -l.
  • Evicted pods and nodes. Logs disappear with the pod. Cluster-level logging exists for this reason.
  • Stale kubelet certificates. --insecure-skip-tls-verify-backend skips verifying the kubelet, which Kubernetes documents for expired serving certificates. It also means a compromised node could return false log content, so use it only to diagnose.

Where Logs Live on the Node

By default the kubelet directs the container runtime to write container logs to directories under /var/log/pods. You can change the path with podLogsDir in the kubelet configuration, though Kubernetes warns that processes may assume the default.

The kubelet and container runtime are not containers. On Linux nodes that use systemd they write to journald, so use journalctl -u kubelet. Without systemd they write .log files under /var/log. Control plane components such as the API server and scheduler typically run as static pods and write files under /var/log.

Kubernetes does not rotate logs for components that you point at a shared volume, so plan rotation yourself. See log retention. For audit logging of API activity rather than container output, see Kubernetes audit logs.

Keeping Logs Beyond the Pod

Kubernetes provides no native storage for logs, and kubectl logs only reads what is still on the node. For anything that must survive a crash, eviction, or node loss you need cluster-level logging with a separate backend. Kubernetes lists three approaches: a node-level logging agent on every node, a sidecar container in the pod, or pushing logs from the application. The agent approach is the common one, run as a DaemonSet with access to the node's log directory. See log aggregation and log forwarding.

Fluent Bit is one such agent. See the Fluent Bit integration and the kubectl integration for how Sazabi works with both.

Searching Kubernetes Logs with Sazabi

Sazabi, an AI-native observability and security platform, receives logs from any Fluent Bit v2.0 or later deployment through the built-in opentelemetry output plugin, so no extra plugin is needed. Add an output section to your Fluent Bit configuration with these settings, replacing the host with the hostname from your Sazabi intake URL (no scheme or path):

name         opentelemetry
match        *
host         <your intake hostname>
port         443
logs_uri     /v1/logs
tls          on
tls.verify   on

On Helm, add the output under config.outputs in your values file, then roll the DaemonSet. Check the Fluent Bit logs for connection or TLS errors on startup. After that, search those logs in Sazabi instead of running kubectl logs pod by pod. The Fluent Bit docs have the full steps.

Frequently Asked Questions

How do I follow pod logs with kubectl?

Run kubectl logs -f POD, optionally with -c CONTAINER. Add --tail=20 to start from the last 20 lines, or use -l app=name -f to follow every pod matching a label.

How do I see logs from a crashed or restarted container?

Run kubectl logs POD --previous (or -p), adding -c CONTAINER for a multi-container pod. It prints the logs of the previous instance of the container, if one still exists on the node.

How do I get logs from all pods in a deployment?

Use kubectl logs deployment/NAME --all-pods=true, or select pods by label with kubectl logs -l app=NAME. When you follow with a selector, 5 concurrent log streams are allowed by default, which --max-log-requests raises.

Why does kubectl logs only show a small part of my logs?

The kubelet rotates container logs, by default at 10Mi per file with 5 files kept, and kubectl logs reads only the latest file. With a selector, --tail also defaults to 10 lines.

Where are Kubernetes logs stored on the node?

Container logs are under /var/log/pods by default. On systemd nodes the kubelet and container runtime write to journald, which you read with journalctl -u kubelet.

Sources

  1. kubectl logs synopsis, every flag and default used here, and the example commands (accessed Nov 8, 2026)
  2. The kubelet keeps one terminated container with its logs, evicted pods lose logs, rotation defaults of 10Mi and 5 files, only the latest file is served, /var/log/pods, journald for the kubelet, and node-level logging agents as a DaemonSet (accessed Nov 8, 2026)
  3. Using kubectl logs with -c and --previous for crashed containers, and CrashLoopBackOff in kubectl describe output (accessed Nov 8, 2026)
  4. Fluent Bit v2.0 or later opentelemetry output, Helm config.outputs, and rolling the DaemonSet (accessed Nov 8, 2026)