[Discuss][Observability] OpenTelemetry GenAI export for Agent Traces (follow-up to #900) #929
Replies: 2 comments 4 replies
|
Thanks for driving this discussion. OpenTelemetry is becoming a widely adopted standard for agent observability, so I believe supporting the conversion of Flink Agents Event Logs into OpenTelemetry GenAI traces would be very valuable. It would also allow users to integrate with existing observability backends without Flink Agents having to provide its own visualization stack. The proposed mapping and overall design look reasonable to me, and I have no major concerns with this direction. |
|
Thanks for making the mapping explicit rather than leaving it implicit in #900. OTLP export is worth pursuing, and a standalone exporter looks like the right direction. Could the proposal include a short rejected-alternatives note for Flink's Before implementation, could we clarify the architecture and recording contract on which the exporter would depend? 1. What durable source would the standalone exporter consume? Today, Event Log output is either SLF4J or TaskManager-local files under Could Phase 1 define durability, partition discovery, checkpoints, replay, retention, failover, and handling of incomplete or out-of-order lifecycle events? Would 2. Could #924 capture the telemetry-neutral metadata while its contract is still open? Several proposed OTel attributes currently have no reliable source:
The existing Could the contract also define how agent, action, LLM, parser, and tool executions become spans? It currently records no agent entity, while action roots have no parent and parser executions have no proposed mapping. Without explicit run, root, and parent semantics, could chained actions appear as unrelated roots or recorded executions be omitted? 3. Could the contract remain language-neutral from the start? Python actions already report through Java, and Java's 4. Would an optional module provide a safer dependency boundary? The Elasticsearch integration already brings an unrelocated OTel API 1.29.0 into the uber JAR, and the default OTLP sender would add a second okhttp package alongside the one already there. Introducing the 1.54.1 SDK/exporter can produce incompatible dependency mediation, including the observed missing 5. Could delivery semantics be defined separately from ID derivation? Stable derived IDs would help with reconstruction, but they would not make OTLP delivery idempotent. Could the proposal describe consumer checkpoints, retries, and replay behavior for complete and partial spans? Would it make sense to frame Phase 1 as:
In-process export, content capture, and further enrichment could then build on that foundation in later phases. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Motivation
#900 defines how Agent Traces are recorded in the Event Log, and deliberately lists OTel export as a non-goal of the recording scope. In that thread, @joeyutong agreed that OpenTelemetry export should be a supported follow-up once the recording contract settles, with the exact GenAI attribute mapping to be worked out as part of the exporter design. This discussion is that follow-up: a config-gated exporter that maps recorded Execution Events to the OpenTelemetry GenAI semantic conventions, so any OTLP-compatible backend (Jaeger, Grafana Tempo, Langfuse, Phoenix, vendor APMs) can visualize and analyze agent runs without flink-agents shipping its own UI.
Proposed mapping
Trace topology, aligned with the #900 recording model:
input_run_id)execution_id/parent_execution_id)invoke_agent {agent_name};gen_ai.operation.name = invoke_agent,gen_ai.agent.nameexecute_tool {tool_name};gen_ai.operation.name = execute_tool,gen_ai.tool.namechat {model};gen_ai.operation.name = chat,gen_ai.request.model,gen_ai.provider.namebusiness_keygen_ai.conversation.idstatus/problem_categoryerror.typegen_ai.usage.input_tokens/gen_ai.usage.output_tokensID derivation. Framework IDs stay opaque, as preferred in #900; the exporter derives fixed-width OTel IDs deterministically, e.g.
trace_id = truncate(SHA-256(input_run_id), 128 bits)andspan_id = truncate(SHA-256(execution_id), 64 bits). Deterministic derivation keeps re-exports idempotent.Design points to agree on
Where the exporter runs. Two candidate shapes:
I lean toward (b) first, since it derives everything from the recording contract and adds no runtime risk, keeping (a) as a later option. Opinions welcome.
Config surface.
event-log.trace.otel.enabled(defaultfalse, mirroring the recording flag), OTLP endpoint/protocol/headers,service.name. Content capture (prompt/response bodies) stays off by default and is opted into separately — gen_ai content capture has privacy and volume implications.Semconv version. The
gen_ai.*conventions are stilldevelopmentstability; we should pin the exportedschema_urland document the target version. I'm engaging in the OTel GenAI SIG, so we can track upstream changes as they stabilize.Scope for 0.4. Phase 1 = Java, spans-only, out-of-band exporter + config; Phase 2 = usage-metrics enrichment; Phase 3 = Python parity. Is Phase 1 realistic for the 0.4 feature freeze (Sept 15)?
What I'd deliver
I've already implemented the inverse mapping (OTel GenAI → storage) in a side project, so the attribute table above is grounded in working code. If maintainers agree with the general shape, I'll break this into concrete issues and start with Phase 1.
Updates (2026-08-07) — incorporating the review feedback above:
Rejected alternative: Flink's
OpenTelemetryTraceReporterFactory. Flink 2.3 ships a nativeOTel trace reporter, but it cannot serve as the export path for agent traces: it does not
preserve caller-derived trace/span ids or span status, it requires related spans to be reported
together, and it is not consistently available across the 1.20 / 2.0 / 2.1 distributions this
project ships for. A standalone converter avoids all three constraints.
Scope clarifications:
continuous tailer. Durability, partition discovery, checkpoints, and retention are properties
of a durable Event Log sink, which deserves its own design track; a continuous OTel consumer
would build on that. Delivery is at-least-once; deterministic ids make duplicates identifiable,
and idempotent coalescing is a backend property.
(endpoint, protocol, service.name) — the earlier
event-log.trace.otel.*naming is dropped.writer, so one converter serves both Java and Python agents. "Java" refers only to the
converter's implementation language; there is no separate Python-parity phase.
its OTel dependencies aligned through the
opentelemetry-bom, keeping them off thedistribution classpath entirely.
usage) are best addressed by recording them in
entityMetadataat recording time, as raisedabove — tracked as part of the recording-contract conversation on [api][runtime][python] Add Agent Trace recording to Event Log #924.
All reactions