Observability
Last updated
You have four things to look at, and one important gap to fill yourself.
What you get
| Tool | What it's for |
|---|---|
| Logs | Your process's stdout and stderr, streamed live |
| Events | Platform actions on the app — starts, stops, restarts, exit codes |
| Shell | A shell inside the running container |
| Files | Browse, download, upload and edit files in the running container |
Shell and Files need the app to be running, so retrieve anything you need before stopping something.
Logs rotate
Container logs are capped and rotate — roughly 10 MB is retained. That's generous for a quiet service and nothing for a chatty one.
The practical consequence: a fast crash loop scrolls its own cause out of retention. By the time you look, the original error is gone and only the last hundred identical failures remain. Keep normal output to one line per meaningful event, and put verbose output behind a flag.
If your app logs nothing at all, check buffering. Python in particular buffers stdout when it isn't a terminal — set PYTHONUNBUFFERED=1 as an environment variable.
Nothing checks whether your app works
There are no health checks. The platform does not send requests to your app, poll an endpoint, or test a port. Restarts are triggered by your process exiting, never by it becoming unresponsive.
So these produce no alert and no visible change:
- A bot that disconnected and went quiet
- An HTTP service returning errors to every request
- A deadlocked or hung process
- A background job failing every run
You need to provide that signal yourself:
- Exit non-zero on unrecoverable errors, so the failure becomes a visible restart with an exit code instead of silence.
- Add a watchdog — record a heartbeat during normal work and exit if it goes stale.
- Report failures outward to a push service or chat webhook, so you hear about them.
- Check from outside — for a worker with no port, have it call out on a schedule and alert when the calls stop.
Notifications reach your email
The panel's Notifications section covers platform events — resource limits exceeded, balance changes, scheduled restarts, and messages from support. Each one is also sent as email to the address on your account.
That makes your account email important: it's the channel that tells you your apps were stopped. Make sure it's an address you actually read.
Notifications never cover your application's behaviour. That half is the section above.
Reading exit codes
Exit codes appear in the app's events and are usually the fastest diagnosis:
| Code | Usually means |
|---|---|
0 |
The process finished normally — for a long-running app, that's a bug |
1 |
Unhandled exception or explicit error exit |
137 |
Killed — almost always out of memory |
139 |
Segfault, often in a native dependency |