feat: OpenTelemetry (OTLP) exporter following the GenAI semantic conventions - #54
Open
brainsparker wants to merge 1 commit into
Open
feat: OpenTelemetry (OTLP) exporter following the GenAI semantic conventions#54brainsparker wants to merge 1 commit into
brainsparker wants to merge 1 commit into
Conversation
…ntic conventions Co-Authored-By: Claude Fable 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.
What this does
Adds an
otelexport format that writes each evaluation run as an OpenTelemetry trace (OTLP/JSON), following the OTel GenAI semantic conventions. Eval scores can now land in the same observability backend as production traces: Grafana Tempo, Jaeger, Datadog, Honeycomb, AWS, or any OTLP-compatible collector.How to use it
Mapping
chat <model>CLIENT span withgen_ai.*attributes (operation name, provider, request/response model, input/output tokens, finish reasons).gen_ai.evaluation.resultspan event withgen_ai.evaluation.name,gen_ai.evaluation.score.value, a pass/failgen_ai.evaluation.score.labelderived from the--fail-underthreshold, andgen_ai.evaluation.explanation. Per-criteria sub-scores and tool usage scores are additional events.error.type.promptlens.*.Why now (market rationale)
gen_ai.evaluation.resultevent, which is exactly the shape of PromptLens output: https://john-hodge.com/blog/opentelemetry-genai-semantic-conventions/ and https://github.com/open-telemetry/semantic-conventionsPromptLens already exports HTML, JSON, CSV, Markdown, and JUnit. This closes the observability gap with zero new dependencies, which keeps the lightweight, local-first positioning intact.
Runner-up candidates considered today: a nested AGENTS.md / Copilot instructions exporter for you.md (lower value since Copilot's coding agent already reads AGENTS.md), and further A2A interop work in youagent (an outbound interop PR is already in flight, so stacking more felt premature).
Implementation notes
promptlens/exporters/otel_exporter.py: emits the OTLP JSON protobuf encoding directly (proto3 JSON mapping, int64 as strings, hex trace/span ids, nanosecond timestamps). No OTel SDK dependency.<endpoint>/v1/tracesvia stdlib urllib. A push failure logs a warning and never fails the run, so a down collector cannot break CI. The file on disk is the source of truth.promptlens run(new--otel-endpointflag),promptlens export --format otel, configoutput.formats, and the exporter registry.junit(already supported by the run command) was rejected in YAML configs. The validator now acceptsjunitandotel, with a regression test for each.Test status
tests/test_otel_exporter.pycovering document shape, span parenting, gen_ai attribute mapping, evaluation events (overall, criteria, tool scores, pass/fail labels), error status, None-attribute dropping, endpoint push (path handling, env var, failure tolerance), and config validation.promptlens export --format otelon a synthetic run.🤖 Generated with Claude Code