docker stats shows how containers are doing; docker events shows what happened to them: every lifecycle step of containers, images, networks and volumes, live or replayed with --since. Watch a container from creation to an out-of-memory death:
timeout 12 docker events --filter container=l3-ev \
--format '{{.Time}} {{.Type}} {{.Action}} {{.Actor.Attributes.exitCode}}' &
sleep 1
docker run -d --name l3-ev --memory 32m alpine:3 \
sh -c 'sleep 2; head -c 100m /dev/zero | tail' >/dev/null
sleep 6; docker rm l3-ev >/dev/null
wait1790338533 container create <no value> 1790338533 container start <no value> 1790338535 container oom <no value> 1790338536 container die 137 1790338539 container destroy <no value>
The oom event arrives just before die, and it is the proof that exit code 137 alone does not give you: a plain docker kill also exits with 137. Healthchecks add health_status: healthy and health_status: unhealthy events, and docker exec adds exec_start and exec_die. A crash monitor filters with --filter event=die --filter event=oom. The daemon returns only the last 256 past events, so a real monitor streams continuously with --format '{{json .}}' into a collector. The same stream is the Engine API's /events endpoint, which is how Traefik 27,315 and Portainer 64,083 notice containers coming and going.