The Events Tab — the History That Survives When Logs Rotate Away
Every application has an Events tab, and it answers a question logs can't: when did this start, and how often has it happened? It records the app's lifecycle — initializing, preparing, starting, started, stopping, stopped — plus every exit with its exit code, flagged as an error when that code isn't zero. The crucial difference from logs is persistence: container logs rotate at roughly 10 MB and vanish entirely when you redeploy, while the event history is still there afterwards. Logs tell you why; events tell you when, and events survive.
Logs and events answer different questions
| Logs | Events | |
|---|---|---|
| Tells you | Why it failed — the traceback | When it happened, and how often |
| Granularity | Every line your app writes | One entry per lifecycle transition |
| Survives a redeploy | No | Yes |
| Survives rotation | No, ~10 MB window | Yes |
| Contains your app's output | Yes | No |
The practical consequence: when you're debugging something intermittent, the log almost never covers the whole story, because the interesting failure happened before the window you can still see. The event history does cover it.
What gets recorded
Lifecycle, in the order you'll see it: initializing, preparing, starting, started, then stopping and stopped when it comes down.
Exits. An exited event carries the exit code as its data and is flagged as an error when the code is non-zero. This is the one that earns the tab its place — the exit code is the most useful diagnostic you have, and here you get a timestamped history of every one rather than whatever is still in the log buffer.
Failed starts. A failed_start entry, flagged as an error, when the app couldn't come up at all — distinct from starting and then dying.
Housekeeping. Apps that go stale are gc_warned, then gc_marked_stale, then gc_soft_deleted, and eventually purged. There's a recovered_from_delete event too, which tells you something useful: a soft-deleted app is a state you can come back from, not an immediate loss.
Scheduled restarts, if you have them: restart_scheduled (with the time it's set for), restart_announced, restart_executed, restart_cancelled, restart_failed with the error message, plus the ones explaining why a scheduled restart didn't happen — restart_skipped_stopped and restart_dropped_manual_restart.
That last group is worth knowing about, because "the restart didn't run" has an entry explaining itself rather than leaving you guessing.
Reading a crash loop from the history
Here's where it pays off. Your bot reports as running but keeps restarting, and the logs are full of identical recent failures with no sign of the first one.
The event history gives you the shape of the problem:
- A wall of
exitedevents, seconds apart — a hard crash loop. The exit code tells you which kind:1for an unhandled exception,137for out-of-memory,0for a process that finished rather than crashed. exitedevery few hours — something periodic. A memory leak reaching the limit, an upstream that fails on a schedule, a token expiring.exitedevents starting at a specific timestamp — compare with when you last deployed. If they begin at your deploy, it's your change. If they begin hours later, it isn't.
That last comparison is the one people can't make from logs alone, because the logs from before the deploy are gone with the old container. The events aren't.
The question it's best at
"Has this always been happening, or did it start today?"
It's remarkably hard to answer from logs and trivial from the event list. A bot that's been quietly restarting twice a day for three weeks looks identical in the logs to one that started restarting an hour ago — same traceback, same recent entries. The event history distinguishes them immediately, and that distinction usually determines where you look next.
Same for the opposite reassurance: if you've just shipped a change and want to know whether the restart you saw was normal, the history shows whether restarts are routine for this app.
Use it alongside, not instead of
Events don't contain your application's output, so they won't tell you why anything failed. The workflow that works:
- Events to establish when it started and how often it happens.
- Logs to find out why, while the relevant window is still there.
- Copy the log out before you deploy a fix, because that erases it.
And if you're about to redeploy in the middle of debugging, note the timestamps first. The events will still be there afterwards; the logs won't.
FAQ
Where do I find my app's event history?
On the application's Events tab in the panel. It's paged, most recent first.
Do events survive a redeploy?
Yes. Unlike container logs — which belong to the container and are discarded when it's recreated — the event history persists.
Does the event history include my application's log output?
No. It records lifecycle transitions and exits, not what your app printed. Use the logs for that.
What does an exited event tell me?
That the process stopped, when, and with which exit code — flagged as an error when the code isn't zero. Exit code 1 is usually an unhandled exception, 137 an out-of-memory kill, and 0 means your process finished rather than crashed.
What happens to an app that goes stale?
It's warned, marked stale, soft-deleted, and eventually purged — each step recorded. A soft-deleted app can be recovered, which is also recorded.
Why didn't my scheduled restart run?
Check the events. There are specific entries for a restart skipped because the app was stopped, and for one dropped because you restarted manually in the meantime.
Wrapping up
Most debugging effort goes into reconstructing a timeline, and most of the frustration comes from a log window too short to contain it. The event history is the timeline, kept for you, in the one place people forget to look. Check it first — before you scroll the logs, and definitely before you redeploy and lose the only copy of the evidence.