From ac836348ae856b2dbc9f2089b00311c9d18676c7 Mon Sep 17 00:00:00 2001 From: Douwe Osinga Date: Fri, 15 May 2026 10:41:19 -0400 Subject: [PATCH] fix(otel): emit trace_output as span attribute instead of event trace_output was emitted via tracing::info!() which becomes an OTEL event (log line on the span), not a span attribute. Observability backends like MLflow and Langfuse (via OTEL ingestion) look for span attributes, so the output was invisible to them. Declare trace_output as a field on reply_stream_span and use Span::record() so it becomes a proper OTEL span attribute. The Langfuse custom layer handles both paths identically (on_record and on_event both call handle_record), so this is a no-op for that path. Fixes #8586 Signed-off-by: Douwe Osinga --- crates/goose/src/agents/agent.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index b2fe6d08ce99..7c353dc5da57 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -1505,7 +1505,7 @@ impl Agent { .count(); let working_dir = session.working_dir.clone(); - let reply_stream_span = tracing::info_span!(target: "goose::agents::agent", "reply_stream", session.id = %session_config.id); + let reply_stream_span = tracing::info_span!(target: "goose::agents::agent", "reply_stream", trace_output = tracing::field::Empty, session.id = %session_config.id); let inner = Box::pin(async_stream::try_stream! { let mut turns_taken = 0u32; let max_turns = session_config.max_turns.unwrap_or_else(|| { @@ -2090,7 +2090,7 @@ impl Agent { } if !last_assistant_text.is_empty() { - tracing::info!(target: "goose::agents::agent", trace_output = last_assistant_text.as_str()); + tracing::Span::current().record("trace_output", last_assistant_text.as_str()); } }.instrument(reply_stream_span)); Ok(inner)