This is a self-hosting guide. The hosted product at https://www.orcapods.ai needs none of this — sign in and go.
Overview
Every Orca binary ships with three observability pillars out of the box:
No instrumentation code is required. The HTTP metrics endpoint is registered by each service process.
Public Status Page
The standalonestatus service serves the public status page and JSON endpoints under /api/*, including GET /api/status, GET /api/incidents, and GET /api/history. The dashboard sidebar and landing footer show a live status indicator by polling the status endpoint every 60 seconds, then link to the status page.
The dashboard reads its status page URL from the VITE_STATUS_URL environment variable; set it to your deployed status service. The landing site reads its status page URL from landing/src/content/site.ts.
Browser reads are controlled by the status service’s STATUS_ALLOWED_ORIGINS allowlist. Set it to a comma-separated list of first-party dashboard and landing origins that may read /api/* cross-origin. An empty value allows same-origin reads only, and a literal * restores wildcard CORS.
degraded or down for INCIDENT_OPEN_AFTER consecutive polls, resolves it after INCIDENT_RESOLVE_AFTER consecutive operational polls, and worsens an open degraded incident when the component becomes down. Defaults are INCIDENT_OPEN_AFTER=2 and INCIDENT_RESOLVE_AFTER=3.
Metrics
The conductor, runner, and standalone VirtualFS server expose Prometheus metrics at/metrics:
Shared Runtime Metrics
These collectors are registered by runner processes and by conductor components that execute runtime work locally.Conductor Metrics
Planner Metrics
VirtualFS Metrics
These collectors are registered byvfs serve. Dispatcher labels keep mount names and statuses bounded, and HTTP path labels use the matched http.ServeMux pattern instead of raw tenant paths.
Scrape Configuration
Structured Logs
Orca usesgo.uber.org/zap for machine-parseable logging. Most Go services emit JSON by default; vfs serve defaults to a compact console log format and switches to JSON with LOG_FORMAT=json.
The VirtualFS HTTP API emits an http.request access log for every request with request_id, method, routed path, status, duration, and remote address. Handler error sites also log structured warning or error events with the same request_id, such as auth.unauthorized, exec.executor_failed, cat.dispatch_failed, upload.write_failed, and tree.list_failed, so a failed request can be correlated with the underlying auth, dispatcher, cache, presign, upload, or executor error.
The conductor planner emits planner.run_aborted when a workflow run goroutine exits before execution, with plan_id, reason, and error fields. reason is no_tenant when the planner reached storage without tenant context, and store_get for other workflow-store lookup failures. Replay submission failures are logged as planner.replay_submit_failed.
The conductor artifact path emits artifacts.bucket_unavailable at fatal level during startup when S3_BUCKET is configured but the bucket cannot be listed with the configured endpoint and credentials. If INTERNAL_S3_BUCKET is configured, the conductor also probes that internal run-event bucket; failures emit internal_artifacts.bucket_unavailable at fatal level, while non-fatal initialization errors emit internal_artifacts.init_failed and fall back to the primary artifact bucket. S3-backed run-event persistence emits runs.s3.events_degraded once per run when writing the JSONL event object fails; the log includes run_id, object key, buffered_bytes, final, and error.
Runner Sandbox Boot Log Lines
Runner startup logs the sandbox manager state so operators can tell whether each provider was registered or skipped:
Sandbox provider-event handling emits
sandbox_event.unknown_provider or sandbox_event.undecodable when a delivery is ignored, and sandbox_event.invalidated with provider, sandbox_id, kind, and matching leases after an accepted event is applied. sandbox_event.fanout_shed is a warning that the 32 concurrent fan-out slots were full; the webhook still received 202, but cached liveness for those sandboxes stays stale until the next provider probe.
Sandbox Worker Lifecycle Log Lines
AworkerMode: "sandbox" session runs a paid sandbox for its whole life, so these lines are the cost and correctness trail for it:
A provider auto-stop frees compute but not disk: a stopped cloud sandbox still holds its full disk allocation, and only deletion or archiving releases it. Orphans left by a runner that died without releasing its leases therefore accumulate against the provider’s disk quota and eventually fail every new launch with a quota error, even though nothing is running.
WORKER_AUTO_ARCHIVE is what bounds that; see the local-development guide.
VirtualFS Boot Log Lines
vfs serve emits the following structured log events during startup for each backend it attempts to initialize:
Per-mount availability is also visible at runtime via
GET /vfs/mounts — check the status and reason fields.
Log Fields
Common fields included on structured log entries:Log Levels
Set
LOG_LEVEL=debug on any Go service for verbose output.
Querying Logs with jq
Distributed Tracing
Orca exports OpenTelemetry traces in OTLP format. Configure the exporter endpoint:Trace Coverage
Traces span the full request lifecycle: Trace context is propagated via standard W3Ctraceparent headers. VirtualFS adds spans for inbound HTTP requests, dispatcher operations, and Workspace.Execute calls when OTEL_EXPORTER_OTLP_ENDPOINT is set.
Jaeger Docker Compose Integration
Health Checks
The conductor, runner, VirtualFS, and billing service expose/healthz:
Grafana Dashboard
The metrics above compose naturally into a Grafana dashboard against your Prometheus data source (Dashboards → Import, or build from scratch). A useful starting layout includes panels for:- Active sessions per runner
- Run throughput (runs/min)
- Run duration percentiles (p50, p95, p99)
- Token usage rate
- Tool call breakdown
- Sidecar error rate
- Plan node throughput and repair counts
Alerting Examples
Centralized Logging (OTLP)
Beyond stdout, every service can export structured logs over OTLP to any OpenTelemetry-compatible backend, such as SigNoz, Grafana, Datadog, or Honeycomb. OTLP log export is additive: stdout logging is never affected, so whatever log collection your platform already does keeps working.Ingest path
Environment variables
Service name values:
When
OTEL_EXPORTER_OTLP_ENDPOINT is unset or OTEL_LOGS_ENABLED=false, the
logs exporter is a no-op and the service continues normally. Stdout is never
affected by the flag.
Log-to-trace correlation
WhenOTEL_LOGS_ENABLED=true, the otelzap bridge attaches the active span’s
trace_id and span_id to each log record. Any backend that links logs and
traces by these fields (most do) gives you click-through from a log line to
its trace without manual correlation queries.
Suggested starting points
- Build your primary triage view as a saved log query filtering
severity_text IN (ERROR, FATAL)grouped byservice.name. - Retention of around 15 days for logs and 7 days for traces is a reasonable starting point; tune to your volume and budget.