Repository navigation
feat: export OpenTelemetry traces and metrics over OTLP - #74
Merged
Merged
Conversation
Every CLI command can export the harness's spans and metrics through Effect's built-in OTLP exporter, configured only by the standard OTEL_* environment variables. Without an endpoint nothing is exported, and a configuration that fails to build runs the command without export. - harness: GenAI attributes on the LLM, tool and agent spans; a failed provider request now ends its span with an error status. - harness: metrics for token usage, request/tool/agent duration, time to first token, time per output token, cost, retries, sandbox provisioning and tool output truncation, plus Effect's fiber runtime metrics. - cli: per-signal http/protobuf (default) or http/json, OTLP exporters default to otlp as the spec says, and resource attributes for the instance, release channel and command. - E2E test against a fake provider and collector, snapshotted to __artifacts__/telemetry.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also adds the blank line the formatter expects before the Internal heading. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The GenAI semantic conventions are still in development and have renamed
their metrics more than once, so metrics now use codework's own names and
short labels; spans keep the gen_ai.* attributes trace views read.
- codework.llm.{duration,ttft,tokens,cost}, codework.agent.duration,
codework.tool.duration, codework.sandbox.{provision,exec}.duration and
codework.sandbox.active, plus Effect's fiber runtime metrics.
- Spans: gen_ai.usage.cache_write/reasoning.output_tokens names,
conversation id, stream flag, time to first chunk, agent name.
- Drop the retries and truncation counters and per-signal protocol vars.
- Test drives a bash call so the sandbox exec metric is covered.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A single run produced ~500 spans, a third of them Effect's own sql.execute. Spans now default to Debug and export starts at Info. The command, agent loop, model and tool calls, and sandbox create/wake are marked Info, so a run exports about a dozen spans. CODEWORK_TRACE_LEVEL=debug exports every span again. Effect drops a span's children with it, so every span on the path from a command to a model or tool call is Info, Loop.settleTools included. The E2E test pins the exported span tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…11-otel-9496e4 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Most instruction candidates are missing, and a stat on a missing path fails its span even when the caller treats absence as normal: every debug trace carried ~54 SandboxFileSystem.stat errors per run. Candidates are now probed with exists, which answers absence without failing, and only the files that exist are stat'ed. Not-found stays silent and other failures still warn on every driver. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Export sandbox provisioning: CLI.selectSandbox and Sandbox.resolve are Info, and the server RPCs that provision a sandbox start their own Info trace, since RpcServer's Debug request span would drop them. - Record tokens and cost of an interrupted model call from the terminal the consumer drains. - E2E covers CODEWORK_TRACE_LEVEL=debug; the instruction test asserts stat only runs for existing files. - Drop comments that restated the code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Every CLI command can now export the harness's spans and metrics over OTLP/HTTP using Effect's built-in exporter (
effect/observability). No OpenTelemetry SDK packages are added.Configuration is env only.
OTEL_EXPORTER_OTLP_ENDPOINTturns it on. The standard variables cover headers, per-signal endpoints, protocol (http/protobufby default,http/json),OTEL_SDK_DISABLED,OTEL_SERVICE_NAMEandOTEL_RESOURCE_ATTRIBUTES. Without an endpoint nothing is exported, and a configuration that fails to build runs the command without export.Only high-level spans are exported by default. All spans default to
Debugand export starts atInfo. The command root, the agent loop (Loop.run→runTurn→runTurnAttempt→settleTools→handleTool),LLM.run, and sandbox create/wake are markedInfo. A run exports about 11 spans instead of about 490, which were mostly Effect'ssql.execute, file checks and event publishes.CODEWORK_TRACE_LEVEL=debugexports every span again. Metrics are unaffected.Spans (
LLM.runclient span,Loop.handleTool,Loop.run) carry the OpenTelemetry GenAI attributes: provider, model, session (gen_ai.conversation.id), response id, finish reason, token counts and time to first chunk. A failed provider request ends its span with an error status. Prompts, file contents and model output are never exported.Metrics use codework's own names, because the GenAI metric conventions are still in development and keep renaming:
codework.llm.durationprovider,model,errorcodework.llm.ttftprovider,modelcodework.llm.tokensprovider,model,type(input,output,cache_read,cache_write,reasoning)codework.llm.costprovider,modelcodework.agent.durationerrorcodework.tool.durationtool,errorcodework.sandbox.provision.durationdriver,operation,errorcodework.sandbox.exec.durationdriver,errorcodework.sandbox.activedriverchild_fibers_*Resource attributes:
service.instance.id,deployment.environment.name(the release channel) andcodework.command.aikit is unchanged. All data comes from its terminal assistant message.
Notes
OTEL_{TRACES,METRICS}_EXPORTERexplicitly listsotlp. The spec default isotlp, so the CLI supplies that default; anything set in the environment still wins.unitattribute, sounitalso appears as a data point attribute.OTEL_EXPORTER_OTLP_TIMEOUTshortens that.codework.sandbox.provision.durationandcodework.sandbox.activeonly record for remote and managed sandboxes, so the local E2E test doesn't cover them.Test plan
packages/codework/test/telemetry.test.ts:bashcall, then a text reply.Infospans, nosql.*.__artifacts__/telemetry.json. Stable over 8 runs.grpcexports nothing, an invalid endpoint is ignored.vp check,vp run typecheck, harness and codework test suites.🤖 Generated with Claude Code