Every Kubernetes user knows `kubectl logs pod-name`. It's the first command you reach for when a pod misbehaves. But the default output is often useless — it dumps the entire log buffer, ignores timestamps, and hides logs from crashed containers. Over time, I've built a set of patterns that turn `kubectl logs` from a firehose into a precision tool.
This post covers the flags and workflows I use daily to debug pod failures, with real examples from incidents in production.
The Basics (and Why They Fail)
Running `kubectl logs my-pod` prints the entire log of the first container. If the pod restarted, you get the current (possibly empty) log. If there's a CrashLoopBackOff, you see nothing useful because the container keeps dying before writing logs. The default output also lacks timestamps, making it impossible to correlate with other metrics or events.
Always use `--timestamps` when debugging time-sensitive issues. It adds RFC3339 timestamps to each line, which you can feed into tools like `sort` or `jq` for cross-pod correlation.
Getting Logs from a Crashed Container
When a pod is in CrashLoopBackOff, the current container is either restarting or hasn't written any logs yet. The logs you need are in the *previous* instance. The `--previous` flag retrieves them.
# Get logs from the last run of a crashed container
kubectl logs my-pod --previous
# Combine with timestamps for precise timing
kubectl logs my-pod --previous --timestamps
# Tail only the last 50 lines to avoid noise
kubectl logs my-pod --previous --tail=50The Case of the Silent CrashLoopBackOff
- 14:02Deployment rolled out a new image tag.
- 14:03Pods enter CrashLoopBackOff. `kubectl logs` shows empty output.
- 14:05Engineer runs `kubectl logs --previous` and sees Java OOM error in the logs.
- 14:07Rollback to previous image resolves the issue.
Lesson
Without `--previous`, the OOM error would have been invisible. The pod's current instance had no logs because it crashed before the logger could flush.
Multi-Container Pods: The -c Flag Is Not Optional
If your pod has multiple containers (e.g., an app container and a sidecar), `kubectl logs` defaults to the first container listed in the pod spec. That might be the sidecar, not the main app. Always specify `-c`.
# List containers in a pod
kubectl get pod my-pod -o jsonpath='{.spec.containers[*].name}'
# Get logs from a specific container
kubectl logs my-pod -c app
# Follow logs from both containers in separate terminals
kubectl logs my-pod -c app -f
kubectl logs my-pod -c sidecar -fDon't forget init containers! They have their own flag: `--init-container`. Without it, `kubectl logs` ignores init container output entirely.
Streaming, Tailing, and Since — Controlling the Firehose
When following logs with `-f`, you often don't want to replay the entire buffer. Combine `--tail` with `-f` to start from the last N lines and then stream new ones. The `--since` flag is useful for time-boxed queries.
# Stream only new logs after the last 100 lines
kubectl logs my-pod --tail=100 -f
# Logs from the last 5 minutes
kubectl logs my-pod --since=5m
# From a specific time (RFC3339 format)
kubectl logs my-pod --since-time="2025-03-15T10:00:00Z"I once debugged a slow memory leak by comparing logs from `--since=1h` across three replicas. Without `--since`, I'd have been scrolling through gigabytes of data.
Putting It All Together: A Real Debugging Workflow
Here's a typical sequence I use when a pod starts failing health checks:
- 1Check pod status: `kubectl get pod my-pod` — note the restart count.
- 2If restarts > 0, grab previous logs: `kubectl logs my-pod --previous --timestamps | head -100`.
- 3If no previous logs, stream current logs with `--tail=50 -f` and trigger a manual request to the pod's endpoint.
- 4If the pod has sidecars, use `-c` to identify which container is failing.
- 5Use `--since=10m` to isolate logs around the failure time.
- 6Redirect to a file: `kubectl logs my-pod --timestamps --tail=-1 > pod.log` for offline analysis.
# One-liner to capture full log with timestamps from a crashed container
kubectl logs my-pod --previous --timestamps --tail=-1 > crash.log
# Then grep for errors with line numbers
grep -n "ERROR\|Exception" crash.logof Kubernetes incidents involve at least one pod restart — where --previous is the only way to see the root cause.
These patterns have saved me hours of frustration. The key is to treat `kubectl logs` not as a simple dump, but as a query language for container output. Combine flags, use timestamps, and always check the previous instance when things crash.
Frequently asked questions
How do I get logs from a container that already crashed?
Use `kubectl logs pod-name --previous`. This retrieves the logs from the previous instance of the container, which is exactly what you need when a pod is in CrashLoopBackOff.
How can I see logs from a specific container in a multi-container pod?
Use the `-c container-name` flag, e.g., `kubectl logs pod-name -c sidecar`. If you omit it, `kubectl` defaults to the first container, which may not be the one you want.
Can I stream logs with a delay or only new entries?
Yes, combine `--tail=N` with `-f` to stream only the last N lines plus new ones. For example, `kubectl logs pod-name --tail=50 -f` avoids dumping the entire log history.
How do I get logs from init containers?
Use `--init-container` flag: `kubectl logs pod-name --init-container init-container-name`. Without it, init container logs are not shown.