Metrics & Logs
Every app has three views of what it’s doing right now: Metrics (resource and traffic charts), Logs (the running container’s output), and the per-deployment build logs on each deployment.
Metrics
The Metrics tab shows six live tiles, each with a sparkline:
| Tile | Source |
|---|---|
| CPU % | docker stats on the app’s container |
| Memory | docker stats (with the container’s memory limit) |
| Requests/s | Traefik’s Prometheus counters for the app’s router |
| Error rate | Traefik 5xx responses as a share of requests |
| Latency p50 / p95 | Traefik request-duration histogram, over the last 15-second interval |
A collector job samples every running app every 15 seconds, writes the
sample to Postgres, and publishes it to subscribers. The tab loads the last
24 hours of history, then follows the live stream over SSE — the connection
state is shown next to the page title (streaming / disconnected).
Traffic figures come from Traefik’s Prometheus endpoint on an internal-only
listener (:8082), so they reflect what actually reached the proxy, not what
the app thinks it served. Traefik keeps a separate histogram per status code,
method, and protocol; Cargo sums them per app, and computes percentiles from
the change since the previous sample — a latency spike shows up in the
interval it happened, rather than being averaged into everything since
Traefik started. If Traefik restarts, the first sample after it uses the
fresh totals.
Samples are kept for 48 hours and purged by the daily
housekeeping job. The history endpoint accepts a
window of 6h, 24h (default), or
48h.
Instance-wide monitoring
App metrics answer “is this app healthy”. The Admin page answers “is the server healthy”, with two views instance admins see across every organization.
Server shows four live tiles on the same 15-second tick and 48-hour retention as app metrics:
| Tile | Source |
|---|---|
| Host CPU % | /proc/stat, as a delta between ticks |
| Host memory | /proc/meminfo — used is derived from MemAvailable, so reclaimable page cache doesn’t read as “full” |
| Disk used | statfs on the data directory |
| Containers | docker ps — every container on the host, not just apps |
All applications lists the newest sample for every app on the instance — CPU, memory, requests/s, error rate, and p95 — with a link through to each app. An error rate above 5% is badged so it stands out. This is the one view that deliberately crosses organization boundaries, so it is instance-admin only.
The controlplane runs in a container, but Docker does not namespace
/proc/stat or /proc/meminfo — so the CPU and memory
readings describe the whole machine, not the controlplane's own container.
The container count includes the platform's own three containers and any
managed databases, which is why it is usually higher than the number of
running apps.
Each source degrades independently: if the Docker socket is unavailable the container count reports zero, but the CPU, memory, and disk series keep recording. Losing the whole sample exactly when something is wrong with the host would be the worst possible time for the charts to go blank.
Metrics appear roughly 15 seconds after an app starts running. A stopped app has no container to sample, so its charts flatten out.
Runtime logs
The Logs tab streams the running container’s stdout/stderr over SSE, starting from the last 200 lines. If the stream drops — a redeploy restarts the container, or the session needs refreshing — the tab reconnects on its own and starts over from the latest 200 lines, without duplicating what was already shown. For apps on a worker host, logs are read from that host. This is your application’s own output — distinct from the build output of a deployment. Any org member (viewer and up) can read it.
If the app has never deployed successfully, or is stopped, there’s no container to attach to and the tab reports that no running container exists yet.
Deployment logs
Build and deploy logs are captured per deployment and streamed live while the deploy runs (see Deployments). The stream ends on its own once the deployment finishes. Logs are kept with their deployment rows: the newest five per app always, plus the live deployment and any still in progress — older finished deployments’ logs and images are reclaimed by the prune job (see Image retention).
Platform-level metrics
Separately from per-app metrics, the control plane exposes its own Prometheus endpoint (deploy counts and durations, job-queue depth, DB-pool gauges) on an internal listener. See Operations & Hardening.