From 5ba63f4015d369bc58ad7dfe76198acf003e7450 Mon Sep 17 00:00:00 2001 From: Google Team Member Date: Mon, 26 Jan 2026 08:10:59 -0800 Subject: [PATCH] feat: updating Telemetry BACKWARD INCOMPATIBLE - The IDs of attributes are changing to comply with Python ADK standards. Updates the telemetry system by moving and renaming `Telemetry.java` to `telemetry/Tracing.java`. Here's a breakdown of the changes: * **File Relocation**: `com.google.adk.Telemetry.java` has been moved to `com.google.adk.telemetry.Tracing.java`. * **Tracing Implementation Changes**: * The OpenTelemetry tracer name and various span attribute keys have been updated from using a `"gcp.vertex.agent"` namespace to a `"com.google.adk"` or `"adk."` prefix. * A new static field `CAPTURE_MESSAGE_CONTENT_IN_SPANS` has been added. This boolean, configurable via the `ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS` environment variable (defaulting to `true`), controls whether the full content of LLM requests and responses is included in the OpenTelemetry spans. PiperOrigin-RevId: 861198428 --- .../java/com/google/adk/JsonBaseModel.java | 2 +- .../java/com/google/adk/agents/BaseAgent.java | 10 +-- .../adk/flows/llmflows/BaseLlmFlow.java | 12 +-- .../google/adk/flows/llmflows/Functions.java | 14 ++-- .../java/com/google/adk/runner/Runner.java | 10 +-- .../Tracing.java} | 73 +++++++++++-------- .../com/google/adk/runner/RunnerTest.java | 8 +- 7 files changed, 69 insertions(+), 60 deletions(-) rename core/src/main/java/com/google/adk/{Telemetry.java => telemetry/Tracing.java} (80%) diff --git a/core/src/main/java/com/google/adk/JsonBaseModel.java b/core/src/main/java/com/google/adk/JsonBaseModel.java index 921615f3a..e02a75774 100644 --- a/core/src/main/java/com/google/adk/JsonBaseModel.java +++ b/core/src/main/java/com/google/adk/JsonBaseModel.java @@ -56,7 +56,7 @@ private static ObjectMapper createObjectMapper() { } /** Serializes an object to a Json string. */ - protected static String toJsonString(Object object) { + public static String toJsonString(Object object) { try { return objectMapper.writeValueAsString(object); } catch (JsonProcessingException e) { diff --git a/core/src/main/java/com/google/adk/agents/BaseAgent.java b/core/src/main/java/com/google/adk/agents/BaseAgent.java index 6786ad4bf..7a9f14b6b 100644 --- a/core/src/main/java/com/google/adk/agents/BaseAgent.java +++ b/core/src/main/java/com/google/adk/agents/BaseAgent.java @@ -18,11 +18,11 @@ import static com.google.common.collect.ImmutableList.toImmutableList; -import com.google.adk.Telemetry; import com.google.adk.agents.Callbacks.AfterAgentCallback; import com.google.adk.agents.Callbacks.BeforeAgentCallback; import com.google.adk.events.Event; import com.google.adk.plugins.Plugin; +import com.google.adk.telemetry.Tracing; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.DoNotCall; @@ -222,7 +222,7 @@ private InvocationContext createInvocationContext(InvocationContext parentContex * @return stream of agent-generated events. */ public Flowable runAsync(InvocationContext parentContext) { - Tracer tracer = Telemetry.getTracer(); + Tracer tracer = Tracing.getTracer(); return Flowable.defer( () -> { Span span = @@ -234,7 +234,7 @@ public Flowable runAsync(InvocationContext parentContext) { InvocationContext invocationContext = createInvocationContext(parentContext); - return Telemetry.traceFlowable( + return Tracing.traceFlowable( spanContext, span, () -> @@ -361,7 +361,7 @@ private Single> callCallback( * @return stream of agent-generated events. */ public Flowable runLive(InvocationContext parentContext) { - Tracer tracer = Telemetry.getTracer(); + Tracer tracer = Tracing.getTracer(); return Flowable.defer( () -> { Span span = @@ -373,7 +373,7 @@ public Flowable runLive(InvocationContext parentContext) { InvocationContext invocationContext = createInvocationContext(parentContext); - return Telemetry.traceFlowable(spanContext, span, () -> runLiveImpl(invocationContext)); + return Tracing.traceFlowable(spanContext, span, () -> runLiveImpl(invocationContext)); }); } diff --git a/core/src/main/java/com/google/adk/flows/llmflows/BaseLlmFlow.java b/core/src/main/java/com/google/adk/flows/llmflows/BaseLlmFlow.java index fe6206db7..46b3f1952 100644 --- a/core/src/main/java/com/google/adk/flows/llmflows/BaseLlmFlow.java +++ b/core/src/main/java/com/google/adk/flows/llmflows/BaseLlmFlow.java @@ -16,7 +16,6 @@ package com.google.adk.flows.llmflows; -import com.google.adk.Telemetry; import com.google.adk.agents.ActiveStreamingTool; import com.google.adk.agents.BaseAgent; import com.google.adk.agents.CallbackContext; @@ -38,6 +37,7 @@ import com.google.adk.models.LlmRegistry; import com.google.adk.models.LlmRequest; import com.google.adk.models.LlmResponse; +import com.google.adk.telemetry.Tracing; import com.google.adk.tools.ToolContext; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; @@ -178,7 +178,7 @@ private Flowable callLlm( return Flowable.defer( () -> { Span llmCallSpan = - Telemetry.getTracer() + Tracing.getTracer() .spanBuilder("call_llm") .setParent(Context.current()) .startSpan(); @@ -199,7 +199,7 @@ private Flowable callLlm( .doOnNext( llmResp -> { try (Scope innerScope = llmCallSpan.makeCurrent()) { - Telemetry.traceCallLlm( + Tracing.traceCallLlm( context, eventForCallbackUsage.id(), llmRequestBuilder.build(), @@ -474,7 +474,7 @@ public Flowable runLive(InvocationContext invocationContext) { : Completable.defer( () -> { Span sendDataSpan = - Telemetry.getTracer() + Tracing.getTracer() .spanBuilder("send_data") .setParent(Context.current()) .startSpan(); @@ -484,7 +484,7 @@ public Flowable runLive(InvocationContext invocationContext) { .doOnComplete( () -> { try (Scope innerScope = sendDataSpan.makeCurrent()) { - Telemetry.traceSendData( + Tracing.traceSendData( invocationContext, eventIdForSendData, llmRequestAfterPreprocess.contents()); @@ -496,7 +496,7 @@ public Flowable runLive(InvocationContext invocationContext) { StatusCode.ERROR, error.getMessage()); sendDataSpan.recordException(error); try (Scope innerScope = sendDataSpan.makeCurrent()) { - Telemetry.traceSendData( + Tracing.traceSendData( invocationContext, eventIdForSendData, llmRequestAfterPreprocess.contents()); diff --git a/core/src/main/java/com/google/adk/flows/llmflows/Functions.java b/core/src/main/java/com/google/adk/flows/llmflows/Functions.java index 519a79c09..ce7687c3d 100644 --- a/core/src/main/java/com/google/adk/flows/llmflows/Functions.java +++ b/core/src/main/java/com/google/adk/flows/llmflows/Functions.java @@ -20,7 +20,6 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; -import com.google.adk.Telemetry; import com.google.adk.agents.ActiveStreamingTool; import com.google.adk.agents.Callbacks.AfterToolCallback; import com.google.adk.agents.Callbacks.BeforeToolCallback; @@ -31,6 +30,7 @@ import com.google.adk.events.Event; import com.google.adk.events.EventActions; import com.google.adk.events.ToolConfirmation; +import com.google.adk.telemetry.Tracing; import com.google.adk.tools.BaseTool; import com.google.adk.tools.FunctionTool; import com.google.adk.tools.ToolContext; @@ -178,11 +178,11 @@ public static Maybe handleFunctionCalls( var mergedEvent = maybeMergedEvent.get(); if (events.size() > 1) { - Tracer tracer = Telemetry.getTracer(); + Tracer tracer = Tracing.getTracer(); Span mergedSpan = tracer.spanBuilder("tool_response").setParent(Context.current()).startSpan(); try (Scope scope = mergedSpan.makeCurrent()) { - Telemetry.traceToolResponse(invocationContext, mergedEvent.id(), mergedEvent); + Tracing.traceToolResponse(invocationContext, mergedEvent.id(), mergedEvent); } finally { mergedSpan.end(); } @@ -552,7 +552,7 @@ private static Maybe> maybeInvokeAfterToolCall( private static Maybe> callTool( BaseTool tool, Map args, ToolContext toolContext) { - Tracer tracer = Telemetry.getTracer(); + Tracer tracer = Tracing.getTracer(); return Maybe.defer( () -> { Span span = @@ -561,7 +561,7 @@ private static Maybe> callTool( .setParent(Context.current()) .startSpan(); try (Scope scope = span.makeCurrent()) { - Telemetry.traceToolCall(args); + Tracing.traceToolCall(args); return tool.runAsync(args, toolContext) .toMaybe() .doOnError(span::recordException) @@ -579,7 +579,7 @@ private static Event buildResponseEvent( Map response, ToolContext toolContext, InvocationContext invocationContext) { - Tracer tracer = Telemetry.getTracer(); + Tracer tracer = Tracing.getTracer(); Span span = tracer .spanBuilder("tool_response [" + tool.name() + "]") @@ -615,7 +615,7 @@ private static Event buildResponseEvent( .build())) .actions(toolContext.eventActions()) .build(); - Telemetry.traceToolResponse(invocationContext, event.id(), event); + Tracing.traceToolResponse(invocationContext, event.id(), event); return event; } finally { span.end(); diff --git a/core/src/main/java/com/google/adk/runner/Runner.java b/core/src/main/java/com/google/adk/runner/Runner.java index ed0da96cc..574c3dcf0 100644 --- a/core/src/main/java/com/google/adk/runner/Runner.java +++ b/core/src/main/java/com/google/adk/runner/Runner.java @@ -16,7 +16,6 @@ package com.google.adk.runner; -import com.google.adk.Telemetry; import com.google.adk.agents.ActiveStreamingTool; import com.google.adk.agents.BaseAgent; import com.google.adk.agents.InvocationContext; @@ -39,6 +38,7 @@ import com.google.adk.summarizer.EventsCompactionConfig; import com.google.adk.summarizer.LlmEventSummarizer; import com.google.adk.summarizer.SlidingWindowEventCompactor; +import com.google.adk.telemetry.Tracing; import com.google.adk.tools.BaseTool; import com.google.adk.tools.FunctionTool; import com.google.adk.utils.CollectionUtils; @@ -450,7 +450,7 @@ public Flowable runAsync( RunConfig runConfig, @Nullable Map stateDelta) { Span span = - Telemetry.getTracer().spanBuilder("invocation").setParent(Context.current()).startSpan(); + Tracing.getTracer().spanBuilder("invocation").setParent(Context.current()).startSpan(); Context spanContext = Context.current().with(span); try { @@ -465,7 +465,7 @@ public Flowable runAsync( .userContent(newMessage) .build(); - return Telemetry.traceFlowable( + return Tracing.traceFlowable( spanContext, span, () -> @@ -645,7 +645,7 @@ private InvocationContext.Builder newInvocationContextBuilder(Session session) { public Flowable runLive( Session session, LiveRequestQueue liveRequestQueue, RunConfig runConfig) { Span span = - Telemetry.getTracer().spanBuilder("invocation").setParent(Context.current()).startSpan(); + Tracing.getTracer().spanBuilder("invocation").setParent(Context.current()).startSpan(); Context spanContext = Context.current().with(span); try { @@ -668,7 +668,7 @@ public Flowable runLive( return invocationContextSingle.flatMapPublisher( updatedInvocationContext -> - Telemetry.traceFlowable( + Tracing.traceFlowable( spanContext, span, () -> diff --git a/core/src/main/java/com/google/adk/Telemetry.java b/core/src/main/java/com/google/adk/telemetry/Tracing.java similarity index 80% rename from core/src/main/java/com/google/adk/Telemetry.java rename to core/src/main/java/com/google/adk/telemetry/Tracing.java index b37826fa9..23054b674 100644 --- a/core/src/main/java/com/google/adk/Telemetry.java +++ b/core/src/main/java/com/google/adk/telemetry/Tracing.java @@ -14,12 +14,13 @@ * limitations under the License. */ -package com.google.adk; +package com.google.adk.telemetry; import static com.google.common.collect.ImmutableList.toImmutableList; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; +import com.google.adk.JsonBaseModel; import com.google.adk.agents.InvocationContext; import com.google.adk.events.Event; import com.google.adk.models.LlmRequest; @@ -47,18 +48,22 @@ * LLM interactions, and data handling. It leverages OpenTelemetry for tracing and logging for * detailed information. These traces can then be exported through the ADK Dev Server UI. */ -public class Telemetry { +public class Tracing { - private static final Logger log = LoggerFactory.getLogger(Telemetry.class); + private static final Logger log = LoggerFactory.getLogger(Tracing.class); @SuppressWarnings("NonFinalStaticField") - private static Tracer tracer = GlobalOpenTelemetry.getTracer("gcp.vertex.agent"); + private static Tracer tracer = GlobalOpenTelemetry.getTracer("com.google.adk"); - private Telemetry() {} + private static final boolean CAPTURE_MESSAGE_CONTENT_IN_SPANS = + Boolean.parseBoolean( + System.getenv().getOrDefault("ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS", "true")); + + private Tracing() {} /** Sets the OpenTelemetry instance to be used for tracing. This is for testing purposes only. */ public static void setTracerForTesting(Tracer tracer) { - Telemetry.tracer = tracer; + Tracing.tracer = tracer; } /** @@ -73,10 +78,9 @@ public static void traceToolCall(Map args) { return; } - span.setAttribute("gen_ai.system", "gcp.vertex.agent"); + span.setAttribute("gen_ai.system", "com.google.adk"); try { - span.setAttribute( - "gcp.vertex.agent.tool_call_args", JsonBaseModel.getMapper().writeValueAsString(args)); + span.setAttribute("adk.tool_call_args", JsonBaseModel.getMapper().writeValueAsString(args)); } catch (JsonProcessingException e) { log.warn("traceToolCall: Failed to serialize tool call args to JSON", e); } @@ -97,16 +101,16 @@ public static void traceToolResponse( return; } - span.setAttribute("gen_ai.system", "gcp.vertex.agent"); - span.setAttribute("gcp.vertex.agent.invocation_id", invocationContext.invocationId()); - span.setAttribute("gcp.vertex.agent.event_id", eventId); - span.setAttribute("gcp.vertex.agent.tool_response", functionResponseEvent.toJson()); + span.setAttribute("gen_ai.system", "com.google.adk"); + span.setAttribute("adk.invocation_id", invocationContext.invocationId()); + span.setAttribute("adk.event_id", eventId); + span.setAttribute("adk.tool_response", functionResponseEvent.toJson()); // Setting empty llm request and response (as the AdkDevServer UI expects these) - span.setAttribute("gcp.vertex.agent.llm_request", "{}"); - span.setAttribute("gcp.vertex.agent.llm_response", "{}"); + span.setAttribute("adk.llm_request", "{}"); + span.setAttribute("adk.llm_response", "{}"); if (invocationContext.session() != null && invocationContext.session().id() != null) { - span.setAttribute("gcp.vertex.agent.session_id", invocationContext.session().id()); + span.setAttribute("adk.session_id", invocationContext.session().id()); } } @@ -158,26 +162,31 @@ public static void traceCallLlm( return; } - span.setAttribute("gen_ai.system", "gcp.vertex.agent"); + span.setAttribute("gen_ai.system", "com.google.adk"); llmRequest.model().ifPresent(modelName -> span.setAttribute("gen_ai.request.model", modelName)); - span.setAttribute("gcp.vertex.agent.invocation_id", invocationContext.invocationId()); - span.setAttribute("gcp.vertex.agent.event_id", eventId); + span.setAttribute("adk.invocation_id", invocationContext.invocationId()); + span.setAttribute("adk.event_id", eventId); if (invocationContext.session() != null && invocationContext.session().id() != null) { - span.setAttribute("gcp.vertex.agent.session_id", invocationContext.session().id()); + span.setAttribute("adk.session_id", invocationContext.session().id()); } else { log.trace( "traceCallLlm: InvocationContext session or session ID is null, cannot set" - + " gcp.vertex.agent.session_id"); + + " adk.session_id"); } - try { - span.setAttribute( - "gcp.vertex.agent.llm_request", - JsonBaseModel.getMapper().writeValueAsString(buildLlmRequestForTrace(llmRequest))); - span.setAttribute("gcp.vertex.agent.llm_response", llmResponse.toJson()); - } catch (JsonProcessingException e) { - log.warn("traceCallLlm: Failed to serialize LlmRequest or LlmResponse to JSON", e); + if (CAPTURE_MESSAGE_CONTENT_IN_SPANS) { + try { + span.setAttribute( + "adk.llm_request", + JsonBaseModel.getMapper().writeValueAsString(buildLlmRequestForTrace(llmRequest))); + span.setAttribute("adk.llm_response", llmResponse.toJson()); + } catch (JsonProcessingException e) { + log.warn("traceCallLlm: Failed to serialize LlmRequest or LlmResponse to JSON", e); + } + } else { + span.setAttribute("adk.llm_request", "{}"); + span.setAttribute("adk.llm_response", "{}"); } } @@ -196,13 +205,13 @@ public static void traceSendData( return; } - span.setAttribute("gcp.vertex.agent.invocation_id", invocationContext.invocationId()); + span.setAttribute("adk.invocation_id", invocationContext.invocationId()); if (eventId != null && !eventId.isEmpty()) { - span.setAttribute("gcp.vertex.agent.event_id", eventId); + span.setAttribute("adk.event_id", eventId); } if (invocationContext.session() != null && invocationContext.session().id() != null) { - span.setAttribute("gcp.vertex.agent.session_id", invocationContext.session().id()); + span.setAttribute("adk.session_id", invocationContext.session().id()); } try { @@ -216,7 +225,7 @@ public static void traceSendData( } } } - span.setAttribute("gcp.vertex.agent.data", JsonBaseModel.toJsonString(dataList)); + span.setAttribute("adk.data", JsonBaseModel.toJsonString(dataList)); } catch (IllegalStateException e) { log.warn("traceSendData: Failed to serialize data to JSON", e); } diff --git a/core/src/test/java/com/google/adk/runner/RunnerTest.java b/core/src/test/java/com/google/adk/runner/RunnerTest.java index 113812814..b0dbedcd6 100644 --- a/core/src/test/java/com/google/adk/runner/RunnerTest.java +++ b/core/src/test/java/com/google/adk/runner/RunnerTest.java @@ -31,7 +31,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import com.google.adk.Telemetry; import com.google.adk.agents.InvocationContext; import com.google.adk.agents.LiveRequestQueue; import com.google.adk.agents.LlmAgent; @@ -44,6 +43,7 @@ import com.google.adk.plugins.BasePlugin; import com.google.adk.sessions.Session; import com.google.adk.summarizer.EventsCompactionConfig; +import com.google.adk.telemetry.Tracing; import com.google.adk.testing.TestLlm; import com.google.adk.testing.TestUtils; import com.google.adk.testing.TestUtils.EchoTool; @@ -118,8 +118,8 @@ private BasePlugin mockPlugin(String name) { @Before public void setUp() { - this.originalTracer = Telemetry.getTracer(); - Telemetry.setTracerForTesting(openTelemetryRule.getOpenTelemetry().getTracer("RunnerTest")); + this.originalTracer = Tracing.getTracer(); + Tracing.setTracerForTesting(openTelemetryRule.getOpenTelemetry().getTracer("RunnerTest")); this.runner = Runner.builder() .app( @@ -134,7 +134,7 @@ public void setUp() { @After public void tearDown() { - Telemetry.setTracerForTesting(originalTracer); + Tracing.setTracerForTesting(originalTracer); } @Test