Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

Observability

Reactor exposes a unified observability surface across all capabilities. Whether you run a single reactor-server on a VPS or a fleet of reactor-shared instances, the same endpoints and metric names apply.

SignalEndpointFormat
MetricsGET /metricsPrometheus text exposition
HealthGET /healthJSON aggregate
DiagnosticsGET /_admin/doctorJSON per-capability probes
LogsGET /_admin/logsSSE stream (JSON lines)
Tracingstdout / log aggregatorStructured JSON via tracing crate
flowchart TB
RS[reactor-server] --> M[/metrics]
RS --> H[/health]
RS --> D[/_admin/doctor]
RS --> L[/_admin/logs]
M --> Prom[Prometheus]
Prom --> Graf[Grafana]
L --> CLI[reactor logs]
RS --> Agg[Loki / Datadog / etc.]

Scrape GET /metrics on your server’s bind address. The unified binary aggregates counters and histograms from every mounted capability into a single registry.

prometheus.yml
scrape_configs:
- job_name: reactor
scrape_interval: 15s
static_configs:
- targets: ["reactor.internal:8000"]
metrics_path: /metrics

For Fly.io or Kubernetes, add a scrape annotation or use service discovery.

MetricTypeDescription
reactor_http_requests_totalcounterRequests by capability, method, status
reactor_http_request_duration_secondshistogramRequest latency
reactor_request_latency_p99gaugeP99 latency (shared cluster)
# Error rate by capability (5m window)
sum(rate(reactor_http_requests_total{status=~"5.."}[5m])) by (capability)
/ sum(rate(reactor_http_requests_total[5m])) by (capability)
# P95 request latency
histogram_quantile(0.95, sum(rate(reactor_http_request_duration_seconds_bucket[5m])) by (le, capability))
# Job queue backlog alert
reactor_jobs_queue_depth > 100
# Shared cluster tenant cache pressure
reactor_tenant_cache_active > 4500
groups:
- name: reactor
rules:
- alert: ReactorHighErrorRate
expr: |
sum(rate(reactor_http_requests_total{status=~"5.."}[5m]))
/ sum(rate(reactor_http_requests_total[5m])) > 0.05
for: 5m
labels:
severity: warning
annotations:
summary: "Reactor error rate above 5%"
- alert: ReactorHealthCheckFailing
expr: up{job="reactor"} == 0
for: 2m
labels:
severity: critical
- alert: JobQueueBacklog
expr: reactor_jobs_queue_depth > 500
for: 10m
labels:
severity: warning

Returns 200 only when every mounted capability’s internal health check passes. Returns 503 with the failing capability listed otherwise.

Terminal window
curl -s http://localhost:8000/health | jq
{
"status": "ok",
"capabilities": {
"auth": "ok",
"data": "ok",
"storage": "ok",
"functions": "ok",
"jobs": "ok",
"sites": "ok"
}
}

Use this endpoint for load balancer probes, Fly.io http_checks, and Kubernetes readiness probes.

Deep diagnostic probes — database connectivity, storage backend reachability, runtime presence, migration state. Requires admin bearer token.

Terminal window
curl -s \
-H "Authorization: Bearer $REACTOR_ADMIN_TOKEN" \
http://localhost:8000/_admin/doctor | jq
{
"auth": { "status": "ok", "checks": [{ "name": "db_ping", "status": "ok" }] },
"data": { "status": "ok", "checks": [{ "name": "migrations", "status": "ok" }] },
"storage": { "status": "ok", "checks": [{ "name": "fs_writable", "status": "ok" }] },
"functions": { "status": "ok", "checks": [{ "name": "wasmtime", "status": "ok" }] }
}

CLI equivalent:

Terminal window
reactor doctor

Configure log output in Reactor.toml:

[tracing]
filter = "info,reactor_auth=debug,reactor_data=warn,reactor_jobs=debug"
fmt = "json" # use "pretty" for local development

Each capability emits spans with its crate name as the tracing target. In the unified binary, all output fans into one stream.

Example JSON log line:

{
"timestamp": "2026-05-29T12:00:00.000Z",
"level": "INFO",
"target": "reactor_data",
"fields": {
"message": "request completed",
"method": "GET",
"path": "/data/v1/users",
"status": 200,
"duration_ms": 12
}
}

Tail logs remotely via SSE:

Terminal window
# All capabilities
curl -N \
-H "Authorization: Bearer $REACTOR_ADMIN_TOKEN" \
"http://localhost:8000/_admin/logs?follow=1"
# Filter by capability
curl -N \
-H "Authorization: Bearer $REACTOR_ADMIN_TOKEN" \
"http://localhost:8000/_admin/logs?capability=jobs&follow=1&since=2026-05-29T00:00:00Z"

CLI:

Terminal window
reactor logs --follow
reactor logs --capability functions --since 1h

On Reactor.cloud:

Terminal window
reactor cloud logs my-project --follow
reactor:
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"

Forward with Fluent Bit, Vector, or Promtail to Loki/Elasticsearch.


Reactor v0 uses the Rust tracing ecosystem with structured spans. OpenTelemetry export is on the roadmap — today, correlate requests via:

  1. Request ID — propagated in X-Request-Id response headers
  2. JWT sub claim — user-scoped log filtering
  3. Capability target — filter by reactor_auth, reactor_data, etc.

For shared cluster deployments, tenant ID appears in NATS topic names (reactor.{ref}.data.*) and quota metrics labels.

Terminal window
# Enable debug tracing temporarily
REACTOR_TRACING__FILTER="debug" reactor-server
# Or via config reload (restart required in v0)

Recommended Grafana panels for an O2 deployment:

PanelQuery
Request ratesum(rate(reactor_http_requests_total[5m])) by (capability)
Error rate5xx / total requests
Latency P50/P95/P99histogram quantiles
DB pool utilizationreactor_db_pool_size - reactor_db_pool_idle
Job queue depthreactor_jobs_queue_depth
Function invocationsrate(reactor_fn_invocations_total[5m])

For C6@fly shared cluster, add:

  • Tenant cache active vs capacity
  • Quota exceeded rate by resource type
  • Supavisor pool waiting count
  • NATS consumer pending messages

Terminal window
curl -H "Authorization: Bearer $TOKEN" http://localhost:8000/_admin/version
{
"reactor": "0.1.0",
"capabilities": {
"auth": "0.1.0",
"data": "0.1.0",
"storage": "0.1.0",
"functions": "0.1.0",
"jobs": "0.1.0",
"sites": "0.1.0"
}
}