Skip to content

feat(callbacks/otel): add OpenTelemetry GenAI semantic convention handler - #980

Open
Ethanz11-creat wants to merge 3 commits into
cloudwego:mainfrom
Ethanz11-creat:feat/callbacks/otel-genai-handler
Open

feat(callbacks/otel): add OpenTelemetry GenAI semantic convention handler#980
Ethanz11-creat wants to merge 3 commits into
cloudwego:mainfrom
Ethanz11-creat:feat/callbacks/otel-genai-handler

Conversation

@Ethanz11-creat

Copy link
Copy Markdown

Implements cloudwego/eino#1028.

A backend-agnostic OpenTelemetry callback handler for Eino that reports component invocations as spans following the OpenTelemetry GenAI semantic conventions. Unlike the Langfuse / Cozeloop integrations, this emits standard spans to whatever exporter is configured on the TracerProvider, so it works with any OTLP collector or APM backend.

Placement

The handler lives in eino-ext (alongside langfuse and cozeloop) rather than eino core, to avoid introducing the OpenTelemetry SDK as a dependency of the core module — which currently has no observability dependencies. This follows the placement suggestion raised in cloudwego/eino#1028.

What it does

Maps component kinds to gen_ai.operation.name:

  • ChatModel / AgenticModelchat
  • Embedding / Indexerembeddings
  • Retrieverretrieve
  • Tool / tools nodes → execute_tool
  • Agent / Graph / Workflow / Chaininvoke_agent

Attributes attached:

  • gen_ai.system — component implementation type, lowercased (e.g. openai)
  • gen_ai.request.model — model name from chat model / embedding callbacks
  • gen_ai.usage.input_tokens / gen_ai.usage.output_tokens — from chat model / embedding callbacks

Streaming invocations are reported as spans whose lifetime follows the stream; usage attributes are only populated for non-streaming calls.

Tests

go test ./... covers chat model span attributes, tool operation name mapping, error status recording, and nil RunInfo handling.

…dler

Add a backend-agnostic OpenTelemetry callback handler that reports Eino
component invocations as spans following the GenAI semantic conventions.

Maps component kinds to gen_ai.operation.name (chat / embeddings /
retrieve / execute_tool / invoke_agent) and attaches gen_ai.system,
gen_ai.request.model and gen_ai.usage.* attributes from chat model and
embedding callbacks. Streaming invocations are covered by spans whose
lifetime follows the stream.

Placed in eino-ext alongside langfuse/cozeloop to avoid pulling the
OpenTelemetry SDK into eino core (closes cloudwego/eino#1028).
- Add stream/nil-info/nil-span coverage and operation-name table tests,
  raising statement coverage from 54% to 100% to satisfy the 70% gate.
- Add examples/main.go with an OTLP HTTP setup, required by the compliant
  check for newly added go.mod components.
- Add stream/nil-info/nil-span coverage and operation-name table tests so the
  package clears the 70% coverage gate (previously 54%).
- Add examples/main.go wired to the global TracerProvider, satisfying the
  compliant check that new components ship an examples directory.
- Keep otel pinned at v1.38.0 and go at 1.23 to avoid pulling OTLP/grpc deps
  that shift the workspace module graph.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant