Skip to main content

OTLP tracing setup

Crewship emits OpenTelemetry GenAI spans for every LLM call via internal/telemetry. Any OTLP-compatible backend (self-hosted or managed) can receive those spans by setting two env vars on the Crewship process — no code change required.

Prerequisites

  • An OTLP/HTTP-capable tracing backend reachable from the Crewship process.
  • Credentials supplied by your backend (typical formats: a bearer token, a Basic-auth pair, or an API-key header).
  • OTEL_EXPORTER_OTLP_* env vars supported by Crewship since the internal/telemetry package was added.

Configure

Set the env vars on the Crewship process (.env.local for dev.sh, systemd unit Environment= for prod, container -e for Docker):
If your backend documents a project-scoped path (e.g. /api/public/otel), append it to OTEL_EXPORTER_OTLP_ENDPOINT — the OTel SDK still appends /v1/traces to whatever you set here. Compute a Basic-auth header once if needed:
Restart crewship. The init logs one of:
  • OTel GenAI telemetry enabled endpoint=http://... → working
  • telemetry init failed, falling back to noop tracer → check endpoint reachability and that header values parse (no quotes, no newline in base64).

Smoke test

Verify endpoint + auth without waiting for an LLM call:
A 2xx response confirms the endpoint accepts spans. Most backends expose a Traces / Spans UI where the crewship-smoke service should appear shortly after.

What you get

Crewship’s internal/telemetry wires GenAI Semantic Convention attributes on every LLM call (defined in internal/telemetry/spans.go):
  • gen_ai.systemanthropic, openai, ollama
  • gen_ai.request.model — model identifier
  • gen_ai.usage.input_tokens / output_tokens / cached_input_tokens
  • gen_ai.usage.cache_creation_tokens
  • gen_ai.cost.total_usd
Crewship-specific correlation keys, also from spans.go:
  • crewship.agent.id, crewship.agent.type
  • crewship.crew.id, crewship.mission.id
  • crewship.tool.name, crewship.tool.args_hash, crewship.tool.side_effect
Routine-step traces add (from spans_routine.go):
  • crewship.routine.slug, crewship.routine.run_id, crewship.routine.pipeline_id
  • crewship.routine.step.id, crewship.routine.step.type, crewship.routine.step.attempt
Filter on these in your backend for per-provider, per-crew, or per-mission views.

Operational notes

  • Same-host loopback avoids the reverse-proxy hop. If the backend is on a different host, point the endpoint at its public DNS — Crewship uses HTTPS automatically when the endpoint URL starts https://.
  • Batching is 5 s / 2048 spans / 512 per batch (see internal/telemetry/provider.go). Spans emitted shortly before a forced shutdown may drop; the shutdown hook flushes whatever is still queued.
  • No-op fallback — empty OTEL_EXPORTER_OTLP_ENDPOINT keeps the binary running without an observability stack, which is the local dev default.
  • Per-deployment isolation — if your backend supports per-project credentials, give every deployment its own pair so dev/staging/prod traces stay sorted. Only OTEL_EXPORTER_OTLP_HEADERS needs to change.

Troubleshooting