Repository navigation
Description
Context
BigQueryAgentAnalyticsPlugin (current as of ADK 1.34.1) emits internal spans agent, llm_request, tool via its TraceManager. Per the source docstring at google/adk/plugins/bigquery_agent_analytics_plugin.py:642-647, these spans intentionally do NOT attach to ambient OTel context to avoid corrupting framework span hierarchy.
Problem
When a global BatchSpanProcessor is configured for an external exporter (e.g., Cloud Trace), those internal spans STILL get exported — SpanProcessor.on_start / on_end fire for every span the tracer creates, regardless of context attachment.
Result in Cloud Trace UI:
- Generic spans
agent,llm_request,tool(no agent name) appear alongside the readable ADK spansinvoke_agent {name}/execute_tool {name} - Because they don't share OTel parent context, they appear as orphan top-level spans with "(Missing span ID xxxx)" parent references
- Hard to read
Current workarounds
- Subclass
SpanProcessorto drop spans withinstrumentation_scope.name == "google.adk.plugins.bigquery_agent_analytics"at export time. Works but burns CPU creating spans we then discard, and requires maintenance across ADK bumps - Disable the plugin entirely — loses the analytics writes which is the plugin's primary purpose
Proposal
Add a config flag on BigQueryLoggerConfig:
class BigQueryLoggerConfig:
...
export_internal_spans: bool = True
"""If False, plugin's internal spans (agent/llm_request/tool) are recorded for BigQuery row generation
but NOT exported via the global TracerProvider's SpanProcessors. Useful when an external trace
backend like Cloud Trace already receives readable spans from ADK's own _instrumentation.py."""Implementation: gate the tracer.start_span(...) calls in TraceManager.push_span to use a tracer whose spans bypass external SpanProcessors when the flag is False. One approach: maintain a separate TracerProvider internal to the plugin with no SpanProcessor for export — only feeds the plugin's own _SpanRecord stack.
Related issues
- OpenTelemetry contextvars leak across asynchronous generator boundaries in BaseAgent and Runner #5722 — contextvars leak across async generator boundaries (root cause of "Calling end() on an ended span" warnings this plugin also surfaces)
- BigQueryAgentAnalyticsPlugin: parent_span_id Points to Unlogged OTel Spans #5310 — orphan parent_span_id (partially addressed but still visible with this plugin)
- Support for Disabling or Extending Internal OpenTelemetry Tracing in Google ADK (Python) #2792 — general request to disable or extend internal OTel tracing
Running ADK 1.34.1 with this plugin active in production. The trace export pollution forces a choice between losing the analytics or fighting trace UI noise.
Activity
llalitkumarrr commentedon May 29, 2026
Hello @rannn505,
Thank you for sharing your inputs. We will review this request and let you know if any additional information is required. Thank you for your patience.
fix(models): gate Gemini cache creation on cacheable prefix tokens
caohy1988 commentedon Aug 5, 2026
Good news — this is fixed at HEAD, and more thoroughly than the proposed flag: the plugin no longer creates OpenTelemetry spans at all. The
TraceManagerwas rewritten around an internal_SpanRecordstack — span/trace ids are generated internally (uuid4-derived), and notracer.start_spancall remains in the plugin, so there is nothing for aBatchSpanProcessorto export. The orphanagent/llm_request/toolspans with "(Missing span ID)" parents you saw in Cloud Trace are gone; only ADK's own readableinvoke_agent {name}/execute_tool {name}spans export.Two things worth knowing about correlation after the change:
trace_idwhen one exists, so joining the analytics table to Cloud Trace by trace_id keeps working.span_id/parent_span_idin BQ form a plugin-internal, self-consistent tree (intentional, per BigQueryAgentAnalyticsPlugin: parent_span_id Points to Unlogged OTel Spans #5310).enable_otel_correlation=TrueonBigQueryLoggerConfig— rows then carryattributes.otel.span_id/attributes.otel.trace_idcaptured from the ambient framework span.There are regression tests asserting no spans reach a real TracerProvider's processors, so this shouldn't regress silently. We're intentionally not adding
export_internal_spanssince there's nothing left to toggle. Note that silencing ADK's framework-level spans is a separate request tracked in #2792. Closing this as fixed — please reopen if you still see plugin-scoped spans (google.adk.plugins.bigquery_agent_analyticsinstrumentation scope) on a current version.caohy1988 commentedon Aug 5, 2026
Follow-up with the release boundary: this was fixed by commit
a5fa3da0and is included starting with ADK Pythonv2.2.0.I also reran the two targeted regression tests against current main; both pass. The plugin still creates its internal stack only when no current OTel span exists and uses the existing span for correlation when one does, so no new flag or configuration change is required.
For users encountering the original behavior, upgrading to
google-adk >= 2.2.0is the fix. The broader tracing/export discussion remains separate in #2792. This issue can be closed as completed; please reopen only if a current-version repro shows plugin-created OTel spans.caohy1988 commentedon Aug 5, 2026
Independently re-verified at HEAD (
1026d2da): the fix is commita5fa3da0("feat: BigQuery Agent Analytics reliability fixes", 2026-06-03). Zerotracer.start_spancalls remain in the plugin, andtest_push_pop_does_not_export_spans_through_real_provider(tests/unittests/plugins/test_bigquery_agent_analytics_plugin.py:2858-2907) wires a realTracerProvider+ in-memory exporter and asserts push/pop/clear export nothing — so the regression protection the comment above mentions is real, not aspirational.One small fast-follow for the repo (not this issue): the module-level
traceratbigquery_agent_analytics_plugin.py:101-103is now dead code — its only remaining reference is a patch target in that regression test. A tiny cleanup PR can delete both.Note: the issue is still open even though the fix landed and was announced above — closing it now as fixed by
a5fa3da0. @rannn505 please reopen if you still seegoogle.adk.plugins.bigquery_agent_analytics-scoped spans on a current release.caohy1988 commentedon Aug 5, 2026
Cleanup follow-up: draft PR caohy1988#12 removes the dead module-level
tracer = trace.get_tracer(...)allocation identified above and updates the no-export regression tests so their temporary tracer patch target is test-created rather than a production symbol.This does not change the already-shipped behavior from
a5fa3da0:TraceManagerremains an internal ID-only stack and creates no OTel spans. The full plugin unit file passes (477 tests), including the realTracerProvider+ in-memory exporter regression. The user-facing fix boundary remains ADK Python v2.2.0; this draft is only the small dead-code cleanup.fix(plugins): stop creating duplicate analytics spans
fix(plugins): remove dead BigQuery analytics tracer
GWeale commentedon Aug 6, 2026
thanks for raising this, fixed in v2.2.0, the plugin no longer creates otel spans at all, so there's nothing plugin-scoped left for a BatchSpanProcessor to export and the flag has nothing to toggle.
fix(models): gate Gemini cache creation on cacheable prefix tokens