Docker Logs and Debugging a Running Container

Things go wrong. A container exits unexpectedly, an app throws errors, a service does not start. Knowing how to read logs and debug containers is one of the most valuable Docker skills you can have. This topic covers every tool for diagnosing problems.

Reading Container Logs

Docker captures everything a container writes to stdout and stderr. The docker logs command reads this output.

View all logs from a container:
docker logs webapp

Follow logs in real-time (like tail -f):
docker logs -f webapp

Show last 50 lines:
docker logs --tail 50 webapp

Show logs with timestamps:
docker logs --timestamps webapp

Combine: last 100 lines, follow, with timestamps:
docker logs --tail 100 -f --timestamps webapp

Understanding Log Output

docker logs webapp

2024-01-15T10:23:01.123Z  INFO  Starting server on port 5000
2024-01-15T10:23:01.456Z  INFO  Connected to database
2024-01-15T10:23:02.789Z  ERROR Failed to connect to Redis: Connection refused
2024-01-15T10:23:02.790Z  WARN  Retrying in 5 seconds...

Reading this tells you:
- Server started OK
- Database connected OK
- Redis connection FAILED ← this is your problem
- It is retrying automatically

Debugging a Container That Fails to Start

A container starts and immediately exits. This is one of the most confusing situations for beginners. The container runs, fails, stops — and docker ps shows nothing.

Step 1: Find the stopped container
docker ps -a
CONTAINER ID  IMAGE     STATUS                   NAMES
a1b2c3d4e5f6  webapp    Exited (1) 5 seconds ago  my-webapp

Step 2: Read its logs (logs survive even after container exits)
docker logs a1b2c3d4e5f6
Error: Cannot find module '/app/dist/server.js'
    at Function.Module._resolveFilename

Step 3: The error tells you the compiled file is missing
Fix: Run npm run build before docker run, or fix the Dockerfile

Inspecting a Container's Configuration

docker inspect webapp

This returns a large JSON object. Useful sections to look at:

"State": {
    "Status": "running",
    "ExitCode": 0,
    "Error": ""
}
→ Check if container crashed and why

"HostConfig": {
    "Binds": ["/home/user/data:/app/data"],
    "PortBindings": {"5000/tcp": [{"HostPort": "5000"}]}
}
→ Verify volumes and port mappings are correct

"NetworkSettings": {
    "IPAddress": "172.17.0.2",
    "Ports": {"5000/tcp": ...}
}
→ Check network configuration

Getting a Shell Inside a Running Container

docker exec -it webapp bash

Once inside, you can investigate the container like you would any Linux system:

ls /app/              → check if files are where you expect
cat /app/config.json  → inspect configuration files
env                   → check environment variables
ps aux                → see running processes
netstat -tlnp         → check what ports are listening
curl localhost:5000   → test the app from inside the container

For minimal images (like Alpine) that do not have bash:

docker exec -it webapp sh   ← use sh instead

Debugging a Container That Has Already Exited

You cannot exec into a stopped container. But you can start a fresh container from the same image with a shell — overriding the normal startup command:

docker run -it --entrypoint bash my-python-app

Now you are inside a container built from the same image. You can check file paths, verify configurations, and test commands manually.

Checking Resource Usage

docker stats
CONTAINER   CPU %   MEM USAGE/LIMIT     NET I/O         BLOCK I/O
webapp      82.5%   450MiB / 2GiB       1.2GB / 200MB   10MB / 0B
db          5.2%    1.1GiB / 2GiB       50MB / 500MB    2GB / 1GB

High CPU on webapp?  → check for infinite loops, runaway queries
High memory?         → potential memory leak
High block I/O?      → disk-heavy operations, check database queries

Viewing Events

Docker records lifecycle events for every container. This helps you understand exactly what happened and when:

docker events --since "1h"
2024-01-15T10:20:00 container start (name=webapp, image=myapp:1.0)
2024-01-15T10:20:01 container die  (name=webapp, exitCode=137)
2024-01-15T10:20:02 container start (name=webapp, image=myapp:1.0)

exitCode=137 means killed by SIGKILL (out of memory or manually killed)
exitCode=1   means the application itself crashed
exitCode=0   means normal exit

Common Exit Codes

Exit Code 0   → Normal exit, task completed successfully
Exit Code 1   → Application error (check logs)
Exit Code 125 → Docker command itself failed
Exit Code 126 → Command found but not executable
Exit Code 127 → Command not found (check CMD in Dockerfile)
Exit Code 137 → Killed by SIGKILL (OOM or docker kill)
Exit Code 143 → Killed by SIGTERM (docker stop)

Leave a Comment