Operations
Health checks, logs, queues, scaling and retention.
Health
| Service | Readiness | Ready when | Liveness |
|---|---|---|---|
api |
/health/ready |
PostgreSQL and ClickHouse | /health/live |
api-ingest |
/healthz |
PostgreSQL, ClickHouse, Redis | /health/live |
mcp |
/healthz |
PostgreSQL, ClickHouse, Redis | /health/live |
worker-errors |
/healthz on :4400 |
PostgreSQL and Redis | /health/live |
worker-jobs |
/healthz on :4200 |
PostgreSQL | /health/live |
web |
— | — | /health/live |
/healthz of api-ingest and worker-errors also reports the queue: pending, retrying, in-flight and dead entries, the lag of the oldest entry and how long draining has been paused.
api-ingest and mcp answer /healthz in full only to a caller whose address is in TRUSTED_PROXIES. Any other caller gets the status code and status, without the dependencies or the queue.
Logs
Each service writes pino JSON to stdout, one record per line. LOG_LEVEL sets the lowest level. Records carry no service name: take it from the container.
{
"level": "info",
"time": "2026-11-05T14:02:15.871Z",
"requestId": "01JC9X4M2T8Q6R0B5N7V3W1YZK",
"organizationId": "…",
"userId": "…",
"module": "http",
"method": "POST",
"path": "/api/v1/alert-rules",
"status": 201,
"durationMs": 18,
"msg": "POST /api/v1/alert-rules 201"
}
- Fields.
level,timeandmsgare always set.modulenames the component. A failure carrieserrwithtype,messageandstack, including its causes. - Requests.
api,api-ingestandmcpwrite one record per request when it ends.api-ingestandmcpwrite the route template asrouteinstead ofpath. Health probes and preflights are not logged.api-ingestwrites successful intake requests atdebug. - Errors. A 5xx is logged once at
errorwith itserr. So is a failed background job, with itsqueueandjobId. - Request IDs. Each request gets an ID, logged as
requestId. A service keeps an incomingx-request-idinstead only from one of theTRUSTED_PROXIES, and only when it holds 1 to 64 letters, digits,_or-.apireturns it in error responses. - Redaction. Records hold no headers, query strings or bodies. The
paramsof a failed SQL query and thedetailof a database error are written as[REDACTED].
Queues
Telemetry waits in the state Redis, in ingest:queue:<table> lists, until it’s inserted into ClickHouse. A batch inserted twice is deduplicated.
| Failure | What happens |
|---|---|
| ClickHouse down | Draining of the failing table pauses with a growing backoff; other tables keep draining. Intake accepts until a queue reaches INGEST_QUEUE_LIMIT, then answers 429. |
| Rejected batch | Retried with a growing backoff, then moved to ingest:dead:<table> after INGEST_DEAD_LETTER_AFTER_MS. A batch that keeps failing while other batches reach the same table counts as rejected. |
| Redis full | Intake answers 429. Run the state Redis with maxmemory-policy noeviction so nothing queued is evicted. |
Background jobs live in PostgreSQL, in the pgboss schema, and survive restarts.
Scaling
| Service | Scale with | Notes |
|---|---|---|
api-ingest |
Incoming telemetry | Each instance also drains logs and spans. |
worker-errors |
Error volume | Each instance keeps its own source map cache of SOURCE_MAP_CACHE_BYTES. |
worker-jobs |
Alert rules and notifications | One or two instances. Concurrency settings apply per instance. |
api, web |
Dashboard users | Stateless. |
Retention
Each ClickHouse table sets its retention as a TTL: 180 days for logs, spans and error events. Change it with a new ALTER TABLE … MODIFY TTL migration. Fired alert events are kept for ALERT_EVENT_RETENTION_DAYS.
Deleting a project removes its ClickHouse rows and its source maps through a project-cleanup job.