Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

View Container Logs

Learn to view Docker container logs in real time. This lesson covers tailing logs, filtering outputs, and using docker logs effectively.

Focus: view container logs in real time

Sponsored

You’ve deployed a containerized application, but when something goes wrong, you’re staring at a blank terminal. No error messages, no clues — just a silent process. Every developer hits this wall: without real-time logs, debugging a container is like fixing a car engine blindfolded. In this lesson, you’ll learn to view container logs in real time using docker logs with flags like --follow and --tail, so you can stream stdout and stderr, filter noise, and pinpoint issues within seconds.

The problem this lesson solves

Containers run in isolation — unless you explicitly capture their output, you miss crucial runtime information. Standard docker logs shows past output, but modern apps (web servers, API workers, batch jobs) produce streams of events you need to monitor live. The problem: static snapshots hide transient errors, connection drops, or slow memory leaks. Without real-time visibility, you either restart the container blindly or waste hours adding print statements.

Pro tip: Real-time logging isn't just for debugging; it's essential for monitoring health during deployments, load testing, or when your CI/CD pipeline fails.

Core concept / mental model

Think of a container's logs as its memory — everything the application wrote to stdout and stderr since it started. The docker logs command reads that memory. When you add --follow (or -f), it turns that memory into a live stream — like a recoding that keeps playing new parts as they happen.

  • stdout (standard output) → normal operational messages (e.g., "Server started on port 3000")
  • stderr (standard error) → errors or warnings (e.g., "Connection refused")

Docker captures both automatically — you don't need to configure anything. The mental model: docker logs is a window into the container's terminal, and --follow keeps that window open.

How it works step by step

Step 1: Start a container with process output

Run a container that writes to stdout periodically. For example, a simple alpine container that prints a timestamp every 2 seconds:

docker run -d --name logger alpine sh -c "while true; do echo \"Log entry at $(date)\"; sleep 2; done"

Step 2: View existing logs

To see all logs generated so far:

docker logs logger

Output snippet:

Log entry at Tue Apr  1 12:00:00 UTC 2025
Log entry at Tue Apr  1 12:00:02 UTC 2025
...

Step 3: Follow logs in real time

Add the --follow (or -f) flag to stream new log lines as they appear:

docker logs -f logger

Now every 2 seconds, a new line appears — your terminal stays live until you press Ctrl+C.

Step 4: Limit the initial backlog with --tail

If the container has run for hours, you don't want to scroll through thousands of lines. Use --tail to show only the last N lines:

docker logs --tail 10 -f logger

This prints the last 10 lines and then follows live output.

Hands-on walkthrough

Let's build a real-world scenario: a simple Node.js web server that logs requests. First, create a server.js file:

const http = require('http');
const server = http.createServer((req, res) => {
  console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
  res.end('Hello');
});
server.listen(3000, () => console.log('Server running on port 3000'));

Then create a Dockerfile:

FROM node:18-alpine
COPY server.js .
CMD ["node", "server.js"]

Build and run:

docker build -t my-server .
docker run -d -p 3000:3000 --name server my-server

Now test the server by sending requests:

curl http://localhost:3000
curl http://localhost:3000/health

View real-time logs:

docker logs --tail 5 -f server

You'll see:

Server running on port 3000
[2025-04-01T12:01:00.000Z] GET /
[2025-04-01T12:01:05.000Z] GET /health

As you send more requests, new lines appear instantly.

Filtering specific log streams

By default, docker logs shows both stdout and stderr. To see only errors:

docker logs server 2>&1 | grep -i error

Or combine with tail to watch errors live:

docker logs -f server 2>&1 | grep --line-buffered -i error

Note: The 2>&1 merges stderr into stdout so grep can process it.

Compare options / when to choose what

Command Use case What it does
docker logs <container> Quick peek Prints all logs at once, then exits
docker logs -f <container> Real-time monitoring Streams new log lines as they appear
docker logs --tail 50 -f <container> Focus on recent activity Shows last 50 lines then follows
docker logs --since 10m <container> Time-window debugging Logs from the last 10 minutes
docker logs --details <container> Advanced debugging Includes extra attributes (e.g., container ID)

When to choose each: - --follow: Always use for live troubleshooting — it's the core feature. - --tail: Combine with --follow when you don't want 10K lines of history. - --since: Useful for alert automation (e.g., check logs from the last 5 minutes). - --details: Rarely needed unless you're writing scripts that parse logs.

Troubleshooting & edge cases

Common mistakes

  1. Forgetting -f and wondering why new logs don't appear — without --follow, docker logs exits after displaying existing logs.
  2. Running docker logs without the container name — you'll get an error like Error: No such container. Always specify the container name or ID.
  3. Assuming logs persist after container removaldocker rm deletes logs permanently. Use docker logs before removing, or configure a logging driver (see variations).
  4. Accidentally merging stderr into stdout when you don't mean to2>&1 changes stream behavior; skip it if you want separate streams.

Edge case: Container produces no output

If your container doesn't write to stdout/stderr (e.g., it's a batch job that writes to a file), docker logs returns nothing. In that case, docker exec into the container and check file-based logs.

Edge case: Logs are truncated on large output

Very verbose containers may cause logs to be truncated by Docker's default log driver (json-file with max-size). Configure --log-opt max-size=10m when running the container to avoid this.

Variations

  1. Using docker-compose logs -f — When you have multiple services (e.g., web + database), run docker-compose logs -f to stream logs from all services simultaneously, with colored prefixes.
  2. Log drivers for production — Docker supports multiple log drivers: journald (systemd), syslog (centralized logging), awslogs (CloudWatch). Each has its own way to view logs (e.g., journalctl).
  3. Third-party tools — Use docker logs with grep, awk, or jq for advanced filtering, or tools like stern (Kubernetes native) for multi-container streams.

Real-world use cases

  1. Web server debugging: When your Express.js app returns 500 errors, tail logs to see the stack trace immediately after a request.
  2. CI/CD pipeline monitoring: Watch test container logs in real time to catch the exact moment a flaky test fails.
  3. Data pipeline health: Stream logs from an ETL container to spot slow queries or connection failures before they cascade.

What you learned & what's next

You can now view container logs in real time using docker logs -f and combine it with --tail and --since for focused monitoring. You understand the mental model of stdout/stderr streams and can filter logs with Unix commands. This skill is essential before learning Docker Compose logging, where you'll manage multi-container logs with centralized drivers and external tools.

Key takeaways: - Use docker logs -f <container> to follow live output. - Combine --tail N with -f to avoid information overload. - Logs are ephemeral — persist them with external log drivers for production. - Filter logs with grep after redirecting stderr (2>&1). - Remember docker logs captures stdout and stderr by default — no setup needed. - Always stop the follow mode with Ctrl+C.

Practice recap

Now it's your turn: run a container that prints "TICK" every second for 30 seconds. Use docker logs --tail 5 -f to see only the last 5 ticks and watch the rest live. Then stop it with Ctrl+C and verify the container still exists with docker ps -a. This reinforces the mindset of combining --tail and --follow for focused real-time monitoring.

Common mistakes

  • Forgetting -f and assuming new logs will automatically appear — run docker logs -f for real-time streaming.
  • Assuming logs survive docker rm — all log history is lost when a container is removed.
  • Running docker logs without specifying a container name or ID, producing an error like Error: No such container.
  • Ignoring edge case where a container writes no output to stdout/stderr — use docker exec to check file-based logs instead.

Variations

  1. Use docker-compose logs -f to stream logs from all services in a multi-container setup with colored prefixes.
  2. Switch log drivers (e.g., journald, syslog, awslogs) for centralized production logging — each has its own viewing method (e.g., journalctl).
  3. Pipe docker logs -f into tools like grep, awk, or jq for advanced real-time filtering and pattern matching.

Real-world use cases

  • Debug a production web server by tailing logs immediately after a 500 error to see the stack trace in context.
  • Monitor a CI/CD pipeline's test container live to catch the exact moment a flaky test fails, without waiting for the full run.
  • Stream logs from an ETL container to detect slow SQL queries or connection drops before they corrupt a data pipeline.

Key takeaways

  • Use docker logs -f <container> to follow live output in real time.
  • Combine --tail N with -f to avoid scrolling through thousands of past lines.
  • Logs by default capture only stdout and stderr — no additional configuration needed.
  • Forget -f and you'll only see static historical logs, not new entries.
  • Container logs are lost upon docker rm — persist them via log drivers for production.
  • Filter logs on the fly by piping into grep after redirecting stderr with 2>&1.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.