Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
5883369
added flags for enabling and disabling all telemetry - test_spans cur…
mportdata Dec 27, 2025
8aa526c
test(telemetry): cover disable flags
mportdata Dec 27, 2025
541be5f
test(telemetry): cover disable paths
mportdata Dec 27, 2025
6965880
fix(telemetry): restore cache helper
mportdata Dec 27, 2025
ba0ce7a
fixed examples in docstring for is_telemetry_enabled which previously…
mportdata Dec 27, 2025
849b281
moved docstring to 1 line for conciseness
mportdata Dec 27, 2025
181a4fd
Merge branch 'main' into feature/disable-telemetry
mportdata Dec 27, 2025
f272712
Merge branch 'main' into feature/disable-telemetry
mportdata Dec 28, 2025
a6a70be
refactor(agents): simplify span handling
mportdata Dec 28, 2025
8435ad5
refactor(agents): align run_live span handling
mportdata Dec 28, 2025
231c2f2
refactor(telemetry): align span contexts
mportdata Dec 28, 2025
628658b
refactor(flows): simplify call_llm tracing
mportdata Dec 28, 2025
2a2c7f2
refactor(flows): simplify execute_tool tracing
mportdata Dec 28, 2025
75b375c
refactor(telemetry): unify cache span handling
mportdata Dec 28, 2025
6a3a388
chore(samples): revert GEPA formatting
mportdata Dec 28, 2025
276c5ba
refactor(agents): reduce telemetry boilerplate
mportdata Dec 28, 2025
ea1d30c
refactor(agents): keep telemetry flag in validator
mportdata Dec 28, 2025
cfca1f3
refactor(flows): gate tracing on telemetry
mportdata Dec 28, 2025
6e8c2fa
refactor(core): gate telemetry spans
mportdata Dec 28, 2025
a097fcf
refactor(models): rename cache helper
mportdata Dec 28, 2025
de5ac88
removed unnecessary formatting change for easier code review
mportdata Dec 28, 2025
a4026e7
removed unnecessary formatting change for easier code review
mportdata Dec 28, 2025
cafe5e1
reordered the lines on changes to base_agent to minimise diffs for re…
mportdata Dec 28, 2025
7905c89
reordered the lines on changes to base_agent to minimise diffs for re…
mportdata Dec 28, 2025
eee9b47
reordered lines to make review easier - now closer to original code
mportdata Dec 28, 2025
9fe906d
removed abstraction _create_gemini_cache_body as this is only used on…
mportdata Dec 28, 2025
aedf35f
removed _run_callbacks_and_impl to keep diffs at a minimum per PR
mportdata Dec 29, 2025
bdea88f
tidied up diffs that aren't needed
mportdata Dec 29, 2025
1d79472
tidied up diffs that aren't needed
mportdata Dec 29, 2025
eaf028b
used nullcontext in google_llm for more efficient span handling when …
mportdata Dec 29, 2025
149c736
tidied up diffs that aren't needed
mportdata Dec 29, 2025
5449dff
made diffs smaller on runners using contextlib
mportdata Dec 29, 2025
a309268
tidied up diffs that aren't needed
mportdata Dec 29, 2025
ed8e613
tidied up diffs that aren't needed
mportdata Dec 29, 2025
8a601da
tidied up diffs that aren't needed
mportdata Dec 29, 2025
350006c
tidied up diffs that aren't needed
mportdata Dec 29, 2025
8f30332
tidied up diffs that aren't needed
mportdata Dec 29, 2025
0bdf44e
fixed typo telemetryare in docstring
mportdata Dec 29, 2025
6ee7c24
corrected return examples in is_telemetry_enabled
mportdata Dec 29, 2025
c7c8cf4
ran autoformat.sh
mportdata Dec 29, 2025
7100e48
fixed is_telemetry_disabled so type checking does not cause issues
mportdata Dec 29, 2025
314cbf0
fixed typing import so the type Any is imported
mportdata Dec 29, 2025
27527f2
Merge branch 'main' into feature/disable-telemetry
mportdata Dec 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion contributing/samples/gepa/experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
from tau_bench.types import EnvRunResult
from tau_bench.types import RunConfig
import tau_bench_agent as tau_bench_agent_lib

import utils


Expand Down
1 change: 0 additions & 1 deletion contributing/samples/gepa/run_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from absl import flags
import experiment
from google.genai import types

import utils

_OUTPUT_DIR = flags.DEFINE_string(
Expand Down
22 changes: 18 additions & 4 deletions src/google/adk/agents/base_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

from __future__ import annotations

import contextlib
import inspect
import logging
from typing import Any
Expand Down Expand Up @@ -44,6 +45,7 @@
from ..telemetry.tracing import tracer
from ..utils.context_utils import Aclosing
from ..utils.feature_decorator import experimental
from ..utils.telemetry_utils import is_telemetry_enabled
from .base_agent_config import BaseAgentConfig
from .callback_context import CallbackContext

Expand Down Expand Up @@ -132,6 +134,8 @@ class MyAgent(BaseAgent):
"""
sub_agents: list[BaseAgent] = Field(default_factory=list)
"""The sub-agents of this agent."""
disable_telemetry: bool = False
"""Whether to disable telemetry for this agent."""

before_agent_callback: Optional[BeforeAgentCallback] = None
"""Callback or list of callbacks to be invoked before the agent run.
Expand Down Expand Up @@ -282,9 +286,14 @@ async def run_async(
Event: the events generated by the agent.
"""

with tracer.start_as_current_span(f'invoke_agent {self.name}') as span:
span_context = contextlib.nullcontext()
if is_telemetry_enabled(self):
span_context = tracer.start_as_current_span(f'invoke_agent {self.name}')

with span_context as span:
ctx = self._create_invocation_context(parent_context)
tracing.trace_agent_invocation(span, self, ctx)
if span:
tracing.trace_agent_invocation(span, self, ctx)
if event := await self._handle_before_agent_callback(ctx):
yield event
if ctx.end_invocation:
Expand Down Expand Up @@ -315,9 +324,14 @@ async def run_live(
Event: the events generated by the agent.
"""

with tracer.start_as_current_span(f'invoke_agent {self.name}') as span:
span_context = contextlib.nullcontext()
if is_telemetry_enabled(self):
span_context = tracer.start_as_current_span(f'invoke_agent {self.name}')

with span_context as span:
ctx = self._create_invocation_context(parent_context)
tracing.trace_agent_invocation(span, self, ctx)
if span:
tracing.trace_agent_invocation(span, self, ctx)
if event := await self._handle_before_agent_callback(ctx):
yield event
if ctx.end_invocation:
Expand Down
5 changes: 5 additions & 0 deletions src/google/adk/agents/llm_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
from ..tools.tool_context import ToolContext
from ..utils.context_utils import Aclosing
from ..utils.feature_decorator import experimental
from ..utils.telemetry_utils import is_telemetry_enabled
from .base_agent import BaseAgent
from .base_agent import BaseAgentState
from .base_agent_config import BaseAgentConfig
Expand Down Expand Up @@ -814,6 +815,10 @@ def __maybe_save_output_to_state(self, event: Event):

@model_validator(mode='after')
def __model_validator_after(self) -> LlmAgent:
root_agent = getattr(self, 'root_agent', None) or self
disable_telemetry: bool = not is_telemetry_enabled(root_agent)
if hasattr(self.model, 'disable_telemetry'):
self.model.disable_telemetry = disable_telemetry
return self

@field_validator('generate_content_config', mode='after')
Expand Down
20 changes: 14 additions & 6 deletions src/google/adk/flows/llm_flows/base_llm_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from abc import ABC
import asyncio
import contextlib
import datetime
import inspect
import logging
Expand Down Expand Up @@ -50,6 +51,7 @@
from ...tools.google_search_tool import google_search
from ...tools.tool_context import ToolContext
from ...utils.context_utils import Aclosing
from ...utils.telemetry_utils import is_telemetry_enabled
from .audio_cache_manager import AudioCacheManager

if TYPE_CHECKING:
Expand Down Expand Up @@ -129,13 +131,16 @@ async def run_live(
async with llm.connect(llm_request) as llm_connection:
if llm_request.contents:
# Sends the conversation history to the model.
with tracer.start_as_current_span('send_data'):
# Combine regular contents with audio/transcription from session
span_context = contextlib.nullcontext()
if is_telemetry_enabled(invocation_context.agent):
span_context = tracer.start_as_current_span('send_data')
with span_context as span:
logger.debug('Sending history to model: %s', llm_request.contents)
await llm_connection.send_history(llm_request.contents)
trace_send_data(
invocation_context, event_id, llm_request.contents
)
if span:
trace_send_data(
invocation_context, event_id, llm_request.contents
)

send_task = asyncio.create_task(
self._send_to_model(llm_connection, invocation_context)
Expand Down Expand Up @@ -752,7 +757,10 @@ async def _call_llm_async(
llm = self.__get_llm(invocation_context)

async def _call_llm_with_tracing() -> AsyncGenerator[LlmResponse, None]:
with tracer.start_as_current_span('call_llm'):
span_context = contextlib.nullcontext()
if is_telemetry_enabled(invocation_context.agent):
span_context = tracer.start_as_current_span('call_llm')
with span_context:
if invocation_context.run_config.support_cfc:
invocation_context.live_request_queue = LiveRequestQueue()
responses_generator = self.run_live(invocation_context)
Expand Down
9 changes: 7 additions & 2 deletions src/google/adk/flows/llm_flows/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
from ...tools.tool_confirmation import ToolConfirmation
from ...tools.tool_context import ToolContext
from ...utils.context_utils import Aclosing
from ...utils.telemetry_utils import is_telemetry_enabled

if TYPE_CHECKING:
from ...agents.llm_agent import LlmAgent
Expand Down Expand Up @@ -255,7 +256,7 @@ async def handle_function_call_list_async(
function_response_events
)

if len(function_response_events) > 1:
if len(function_response_events) > 1 and is_telemetry_enabled(agent):
# this is needed for debug traces of parallel calls
# individual response with tool.name is traced in __build_response_event
# (we drop tool.name from span name here as this is merged event)
Expand Down Expand Up @@ -425,6 +426,8 @@ async def _run_with_trace():
)
return function_response_event

if not is_telemetry_enabled(agent):
return await _run_with_trace()
with tracer.start_as_current_span(f'execute_tool {tool.name}'):
try:
function_response_event = await _run_with_trace()
Expand Down Expand Up @@ -486,7 +489,7 @@ async def handle_function_calls_live(
merged_event = merge_parallel_function_response_events(
function_response_events
)
if len(function_response_events) > 1:
if len(function_response_events) > 1 and is_telemetry_enabled(agent):
# this is needed for debug traces of parallel calls
# individual response with tool.name is traced in __build_response_event
# (we drop tool.name from span name here as this is merged event)
Expand Down Expand Up @@ -575,6 +578,8 @@ async def _run_with_trace():
)
return function_response_event

if not is_telemetry_enabled(agent):
return await _run_with_trace()
with tracer.start_as_current_span(f'execute_tool {tool.name}'):
try:
function_response_event = await _run_with_trace()
Expand Down
25 changes: 18 additions & 7 deletions src/google/adk/models/gemini_context_cache_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from __future__ import annotations

import contextlib
import hashlib
import json
import logging
Expand All @@ -24,6 +25,7 @@
from typing import TYPE_CHECKING

from google.genai import types
from opentelemetry.trace import Span

from ..utils.feature_decorator import experimental
from .cache_metadata import CacheMetadata
Expand All @@ -45,13 +47,15 @@ class GeminiContextCacheManager:
cache compatibility and implements efficient caching strategies.
"""

def __init__(self, genai_client: Client):
def __init__(self, genai_client: Client, disable_telemetry: bool = False):
"""Initialize cache manager with shared client.

Args:
genai_client: The GenAI client to use for cache operations.
disable_telemetry: A bool to flag whether or not telemetry should be disabled.
"""
self.genai_client = genai_client
self.disable_telemetry = disable_telemetry

async def handle_context_caching(
self, llm_request: LlmRequest
Expand Down Expand Up @@ -356,9 +360,14 @@ async def _create_gemini_cache(
Returns:
Cache metadata with precise creation timestamp
"""
from ..telemetry.tracing import tracer

with tracer.start_as_current_span("create_cache") as span:
span_context = contextlib.nullcontext()
if not self.disable_telemetry:
from ..telemetry.tracing import tracer

span_context = tracer.start_as_current_span("create_cache")

with span_context as span:
# Prepare cache contents (first N contents + system instruction + tools)
cache_contents = llm_request.contents[:cache_contents_count]

Expand Down Expand Up @@ -386,9 +395,10 @@ async def _create_gemini_cache(
if llm_request.config and llm_request.config.tool_config:
cache_config.tool_config = llm_request.config.tool_config

span.set_attribute("cache_contents_count", cache_contents_count)
span.set_attribute("model", llm_request.model)
span.set_attribute("ttl_seconds", llm_request.cache_config.ttl_seconds)
if span is not None:
span.set_attribute("cache_contents_count", cache_contents_count)
span.set_attribute("model", llm_request.model)
span.set_attribute("ttl_seconds", llm_request.cache_config.ttl_seconds)

logger.debug(
"Creating cache with model %s and config: %s",
Expand All @@ -403,7 +413,8 @@ async def _create_gemini_cache(
created_at = time.time()
logger.info("Cache created successfully: %s", cached_content.name)

span.set_attribute("cache_name", cached_content.name)
if span is not None:
span.set_attribute("cache_name", cached_content.name)

# Return complete cache metadata with precise timing
return CacheMetadata(
Expand Down
19 changes: 16 additions & 3 deletions src/google/adk/models/google_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from ..utils._client_labels_utils import get_client_labels
from ..utils.context_utils import Aclosing
from ..utils.streaming_utils import StreamingResponseAggregator
from ..utils.telemetry_utils import is_telemetry_enabled
from ..utils.variant_utils import GoogleLLMVariant
from .base_llm import BaseLlm
from .base_llm_connection import BaseLlmConnection
Expand Down Expand Up @@ -127,6 +128,11 @@ class Gemini(BaseLlm):
```
"""

disable_telemetry: bool = False
"""A bool to flag whether or not telemetry should be being disabled for
Gemini LLM interactions.
"""

@classmethod
@override
def supported_models(cls) -> list[str]:
Expand Down Expand Up @@ -165,11 +171,18 @@ async def generate_content_async(
cache_metadata = None
cache_manager = None
if llm_request.cache_config:
from ..telemetry.tracing import tracer
from .gemini_context_cache_manager import GeminiContextCacheManager

with tracer.start_as_current_span('handle_context_caching') as span:
cache_manager = GeminiContextCacheManager(self.api_client)
span_context = contextlib.nullcontext()
if is_telemetry_enabled(self):
from ..telemetry.tracing import tracer

span_context = tracer.start_as_current_span(f'handle_context_caching')

with span_context as span:
cache_manager = GeminiContextCacheManager(
self.api_client, disable_telemetry=self.disable_telemetry
)
cache_metadata = await cache_manager.handle_context_caching(llm_request)
if cache_metadata:
if cache_metadata.cache_name:
Expand Down
10 changes: 9 additions & 1 deletion src/google/adk/runners.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from __future__ import annotations

import asyncio
import contextlib
import inspect
import logging
from pathlib import Path
Expand Down Expand Up @@ -63,6 +64,7 @@
from .tools.base_toolset import BaseToolset
from .utils._debug_output import print_event
from .utils.context_utils import Aclosing
from .utils.telemetry_utils import is_telemetry_enabled

logger = logging.getLogger('google_adk.' + __name__)

Expand Down Expand Up @@ -434,7 +436,13 @@ async def _run_with_trace(
new_message: Optional[types.Content] = None,
invocation_id: Optional[str] = None,
) -> AsyncGenerator[Event, None]:
with tracer.start_as_current_span('invocation'):
span_context = contextlib.nullcontext()
if is_telemetry_enabled(self.agent):
from .telemetry.tracing import tracer

span_context = tracer.start_as_current_span(f'invocation')

with span_context as span:
session = await self.session_service.get_session(
app_name=self.app_name, user_id=user_id, session_id=session_id
)
Expand Down
Loading