/metrics for Prometheus scraping, /api/v1/status for a structured snapshot, and the process logs for event-level diagnosis.
Signals and destinations
Prometheus metrics
/metrics is protected by the native bearer guard. The exporter is always present, even when no OTLP backend is configured, so a local Prometheus scrape does not require a collector.
OpenTelemetry names are converted to Prometheus names by replacing dots and hyphens with underscores, adding unit suffixes such as _seconds or _bytes, and adding _total to monotonic counters. Common instruments include:
preloop_job_completed_totalandpreloop_job_queue_wait_secondsfor conclusions and queue latency;preloop_broker_poll_total,preloop_runner_session_transition_total, andpreloop_concurrency_decision_totalfor protocol and scheduling activity;preloop_job_queue_depth,preloop_job_claimable,preloop_job_unclaimable, andpreloop_job_dependency_blockedfor queue pressure;preloop_pool_desired,preloop_pool_idle,preloop_pool_busy, andpreloop_pool_slot_failures_totalfor the local runner pool; andpreloop_host_mem_*,preloop_host_swap_*,preloop_host_engine_rss_bytes,preloop_host_vm_rss_bytes, and host RAM pressure gauges when host telemetry is available.
OTLP/HTTP export
preloop-observability reads the standard OpenTelemetry environment variables:
No OTLP endpoint is assumed when these variables are absent; Preloop does not silently send data to
localhost:4318. Export is fail-open: an exporter outage does not reject a workflow. Queues are bounded and local stderr/journald logging remains available when OTLP is configured.
Operational status
GET /api/v1/status returns the cached OperationalSnapshot. It includes:
- overall state (
ok,degraded,blocked, orshutting_down), service version, instance, and uptime; - queued, active, and completed runs;
- ready, dependency-blocked, concurrency-blocked, pending-expansion, claimable, and unclaimable jobs;
- concurrency groups, scheduler state, registered runners and sessions, leases, and assignments;
- runner-pool desired/preparing/building/provisioning/idle/busy/paused counts and queue labels;
- control-store backend and failure streak, state-directory storage, cache/artifact usage, and retention activity;
- GitHub webhook/check-run health and rate-limit observations;
- debug-session counts, OTLP enabled/export timestamps/dropped records, task heartbeats, and active conditions.
/readyz returns 503 when shutdown is requested, a critical task heartbeat is stale, or the sampler snapshot is older than 15 seconds. /healthz is a lighter liveness response and reports the protocol version and shutdown flag.
OpenObserve contribution setup
The repository includes an optional OpenObserve Compose setup undercontrib/openobserve. It is not started by Preloop. The compose file pins an image digest, binds the UI/API to 127.0.0.1:5080, requires ZO_ROOT_USER_PASSWORD, keeps a seven-day telemetry retention window, and stores data in the openobserve-data volume.
Start it from the repository with:
OTEL_EXPORTER_OTLP_* variables above. Keep the service loopback-bound or put an authenticated proxy in front of it; the Compose reference intentionally does not publish an unauthenticated telemetry UI.