Watch Docker Activity Live with docker events

docker events streams live activity from the Docker daemon, the tool you reach for when a container died and nobody can say why. By the end of this guide you will watch live changes, replay a bounded period, narrow the stream to one kind of object, and emit JSON Lines for a script. The examples target Docker CLI 29.8.1 from the installed docker-ce-cli package.

Allow about 10 minutes. You need a working Docker client and access to the Docker daemon. Most commands only read daemon state, but the test in step 2 creates and removes a container. Do not run that test on a host where creating a container is not acceptable. You do not normally need sudo; add it only if your local Docker installation specifically requires elevated access.

1. Confirm the client and connection

  1. Check the installed client and its event options.
docker version --format '{{.Client.Version}}'
docker events --help

The local client reports version 29.8.1. The command is an alias for docker system events, and the installed manpage lists four options: filters, formatting, a start time, and an end time. The help command does not contact the daemon. A version error means the client is unavailable; a later daemon error usually means the socket is not running or your user lacks permission.

Verify daemon access without starting a stream:

docker info >/dev/null && echo "Docker daemon reachable"

Checkpoint: expected output is Docker daemon reachable. If this fails, fix the Docker service or socket permissions first.

Warning: do not work around a permission error by making the Docker socket broadly writable. Access to it is effectively administrative access to the host.

2. Watch one controlled container lifecycle

  1. Open a terminal and start the event stream for containers.
docker events --filter 'type=container'

The command waits for new events. In a second terminal, create and start a short-lived container:

docker create --name events-check alpine:latest true
docker start events-check
docker wait events-check
docker rm events-check

The first terminal should show entries such as container create, container start, container die, and container destroy. Exact timestamps, IDs and extra actions vary with the daemon and client. Press Ctrl+C to end the stream.

This test changes daemon state, although it cleans up the named container at the end. If a command stops halfway through, recover with:

docker rm -f events-check 2>/dev/null || true

The -f here belongs to docker rm, not to docker events. Check that no test container remains:

docker ps -a --filter 'name=^/events-check$'

Checkpoint: no rows after the column headings means the cleanup succeeded.

3. Replay a useful window

  1. Read recent events without leaving an unbounded listener running.
docker events --since 15m --until 1s --filter 'type=container'

--since and --until accept Unix timestamps, date-formatted timestamps, and Go duration strings such as 15m or 1h30m. Durations are relative to the client machine's clock. A timestamp without a timezone uses the local timezone; use an explicit offset when copying times between machines.

The one-second end offset gives the daemon time to close the bounded request while avoiding a stream that waits for future activity. For an exact audit window, use an RFC3339 timestamp:

docker events   --since '2026-09-23T09:00:00Z'   --until '2026-09-23T09:10:00Z'   --filter 'event=stop'

Only the last 256 events are returned, so a busy daemon can still omit older entries even when the time range is wide. If you need durable history, collect the stream continuously into a controlled log destination and protect that log as operational data.

4. Filter before you read

  1. Combine filters to remove unrelated activity.
docker events   --filter 'container=web'   --filter 'event=die'   --since 1h

Repeated uses of the same filter key are alternatives: two container filters match either container. Different filter keys are combined, so the command above means the web container and the die action. Supported filter keys include type, container, image, event, volume, network, plugin, service, node, secret, config, daemon, label and scope. Names and IDs can be used where the daemon supports them.

A common trap is filtering on a human name that no longer exists. Resolve the current name or ID first:

docker ps -a --format 'table {{.ID}}\t{{.Names}}\t{{.Image}}'

5. Make output safe for scripts

  1. Request one JSON object per event when another program will parse the output.
docker events   --filter 'type=container'   --since 10m   --until 1s   --format json

With the current CLI, --format json emits JSON Lines: one event object per output line. This is easier to process incrementally than treating the whole stream as one JSON document. The fields and actor attributes depend on the event, so scripts should tolerate fields they do not use.

docker events --filter 'event=stop' --format '{{json .}}'   --since 10m --until 1s

The explicit template is equivalent for JSON output. For a human-friendly narrow view, use a Go template instead:

docker events   --filter 'type=container'   --since 10m --until 1s   --format 'type={{.Type}} action={{.Action}} id={{.ID}}'

Do not parse the default human output by splitting on spaces. Names, labels and attributes can make that format unsuitable as an interface.

Common failure modes

Done means