Skip to content

Feature request: BigQueryLoggerConfig.export_internal_spans flag to disable plugin span export #5889

Closed

Description

@rannn505

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 spans invoke_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

  1. Subclass SpanProcessor to drop spans with instrumentation_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
  2. 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

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.

— @rannn505

Activity

  1. added
    bq[Component] This issue is related to Big Query integration
    on May 29, 2026
  2. added theissue type on May 29, 2026
  3. llalitkumarrr commented on May 29, 2026

    @llalitkumarrr
    Collaborator

    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.

  4. added
    needs review[Status] The PR/issue is awaiting review from the maintainer
    on May 29, 2026
  5. caohy1988 commented on Aug 5, 2026

    @caohy1988

    Good news — this is fixed at HEAD, and more thoroughly than the proposed flag: the plugin no longer creates OpenTelemetry spans at all. The TraceManager was rewritten around an internal _SpanRecord stack — span/trace ids are generated internally (uuid4-derived), and no tracer.start_span call remains in the plugin, so there is nothing for a BatchSpanProcessor to export. The orphan agent/llm_request/tool spans with "(Missing span ID)" parents you saw in Cloud Trace are gone; only ADK's own readable invoke_agent {name} / execute_tool {name} spans export.

    Two things worth knowing about correlation after the change:

    • BQ rows still inherit the ambient Cloud Trace trace_id when one exists, so joining the analytics table to Cloud Trace by trace_id keeps working. span_id/parent_span_id in BQ form a plugin-internal, self-consistent tree (intentional, per BigQueryAgentAnalyticsPlugin: parent_span_id Points to Unlogged OTel Spans #5310).
    • If you need span-level correlation, set enable_otel_correlation=True on BigQueryLoggerConfig — rows then carry attributes.otel.span_id / attributes.otel.trace_id captured 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_spans since 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_analytics instrumentation scope) on a current version.

  6. caohy1988 commented on Aug 5, 2026

    @caohy1988

    Follow-up with the release boundary: this was fixed by commit a5fa3da0 and is included starting with ADK Python v2.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.0 is 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.

  7. caohy1988 commented on Aug 5, 2026

    @caohy1988

    Independently re-verified at HEAD (1026d2da): the fix is commit a5fa3da0 ("feat: BigQuery Agent Analytics reliability fixes", 2026-06-03). Zero tracer.start_span calls remain in the plugin, and test_push_pop_does_not_export_spans_through_real_provider (tests/unittests/plugins/test_bigquery_agent_analytics_plugin.py:2858-2907) wires a real TracerProvider + 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 tracer at bigquery_agent_analytics_plugin.py:101-103 is 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 see google.adk.plugins.bigquery_agent_analytics-scoped spans on a current release.

  8. caohy1988 commented on Aug 5, 2026

    @caohy1988

    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: TraceManager remains an internal ID-only stack and creates no OTel spans. The full plugin unit file passes (477 tests), including the real TracerProvider + in-memory exporter regression. The user-facing fix boundary remains ADK Python v2.2.0; this draft is only the small dead-code cleanup.

  9. added 2 commits that reference this issue on Aug 6, 2026
    027847e
    37abcef
  10. self-assigned this
    on Aug 6, 2026
  11. GWeale commented on Aug 6, 2026

    @GWeale
    Collaborator

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

bq[Component] This issue is related to Big Query integrationneeds review[Status] The PR/issue is awaiting review from the maintainer

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions