feat: OpenTelemetry GenAI semantic conventions#681
Open
vasspilka wants to merge 14 commits into
Open
Conversation
7c955c9 to
6dbe798
Compare
6dbe798 to
609bca8
Compare
ba32eaf to
6e6224c
Compare
6e6224c to
613773c
Compare
613773c to
dd55e78
Compare
This was referenced May 11, 2026
Open
34db5ef to
70489b4
Compare
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
Brings the OpenTelemetry bridges into full conformance with the GenAI semantic conventions so spans, metrics, and events emitted by
ReqLLM.OpenTelemetry(auto-attach handler) andReqLLM.Telemetry.OpenTelemetry(dependency-free mapper) drop into spec-aware backends like Langfuse, Grafana, and Honeycomb without bespoke instrumentation glue.Work is structured in four shippable phases (see
OPENTELEMETRY_GENAI_PLAN.md):gen_ai.input.messages,gen_ai.system_instructions,gen_ai.tool.definitions,gen_ai.output.messages(default:none; reasoning text stays redacted in every mode).operation.duration,token.usage,time_to_first_chunk,time_per_output_chunkwith spec bucket boundaries; streaming TTFC also surfaced as a span attribute.gen_ai.usage.cost, OpenAI extension attributes (openai.api.type,service_tier,system_fingerprint), Langfuse cost-details opt-in, docs.The two surfaces (auto-bridge and dependency-free mapper) now share five internal modules (
Attributes,Content,Metrics,SemConv,Shared) so they emit identical payloads.How past integrations are affected
Auto-bridge users (
ReqLLM.OpenTelemetry.attach()) — only the breaking changes below apply. Default options still emit no content payloads.Dependency-free mapper users (
ReqLLM.Telemetry.OpenTelemetry) — the breaking changes apply, plus the system-message split forcontent: :attributesconsumers (see Breaking changes #4).Native ReqLLM telemetry consumers (
[:req_llm, :request, *],[:req_llm, :token_usage]) — fully back-compat. The lifecycle event metadata gained three new optional keys (request_options,server,streaming); every pre-existing key is preserved.[:req_llm, :token_usage]is unchanged. Public function signatures onReqLLM.Telemetry,ReqLLM.OpenTelemetry, andReqLLM.Telemetry.OpenTelemetryare unchanged.Breaking changes
Downstream OTel dashboards/alerts that filtered on the old values need to be updated:
gen_ai.provider.namenormalized to spec enums::amazon_bedrock→aws.bedrock,:azure→azure.ai.openai,:google→gcp.gen_ai,:google_vertex→gcp.vertex_ai,:xai→x_ai,:openai_codex→openai. Other providers keep their stringified atom name.gen_ai.operation.namefor embeddings:embedding→embeddings(plural, per spec).error.typeis now also set on:stopspans whenhttp_status >= 400(previously only on:exceptionspans).content: :attributesmode: system messages are now split out ofgen_ai.input.messagesinto a newgen_ai.system_instructionsattribute. Consumers iteratinggen_ai.input.messageslooking forrole == "system"need to readgen_ai.system_instructionsinstead. Auto-bridge default users are not affected (default is stillcontent: :none).Test plan
mix test— 3,095 unit tests pass, 0 failures (11 skipped, 145 excluded).test/req_llm/open_telemetry/{attributes,content,metrics,sem_conv}_test.exs, plus extendedtest/req_llm/open_telemetry_test.exs,telemetry_open_telemetry_test.exs,telemetry_test.exs.SemConvtest) — auto-bridge and dependency-free mapper produce identical provider/operation/span names.mix quality,mix dialyzer.Related issues
Closes #