Class TraceManager

java.lang.Object
com.google.adk.plugins.agentanalytics.TraceManager

public final class TraceManager extends Object
Manages the BQAA-internal execution tree of span IDs for one invocation.

No OpenTelemetry spans are created: records are ID-only, so a host with an SDK exporter configured never receives a duplicate plugin-owned span tree next to ADK's framework spans. Ambient OpenTelemetry context is still consulted for the trace_id (and the invocation root's span_id) so BigQuery rows stay joinable to Cloud Trace.

Span records are kept in per-branch stacks keyed by InvocationContext.branch(). Concurrently scheduled ParallelAgent branches (which share an invocation ID but carry distinct branch strings) never touch each other's stacks, so a branch completing first can no longer pop another branch's span. Within one branch, agent and model spans execute sequentially and use top-of-stack semantics, but ADK executes an event's function calls CONCURRENTLY by default: tool spans therefore carry an operation identity (the function-call ID) plus a parent captured at push time, and are popped by identity rather than stack position. Pops additionally verify the record's kind, so an error callback firing without its matching push cannot pop an unrelated record.

  • Method Details

    • getRootAgentName

      public String getRootAgentName()
    • initTrace

      public void initTrace(InvocationContext context)
    • initTraceIfNeeded

      public void initTraceIfNeeded(InvocationContext context)
      Sets the root agent name from the invocation context if it is still the sentinel default. Null-safe: workflow-driven callbacks with no current agent leave the sentinel in place for a later event to resolve.
    • getTraceId

      public String getTraceId(InvocationContext context)
    • pushSpan

      @CanIgnoreReturnValue public String pushSpan(InvocationContext context, String spanName)
      Pushes an ID-only span record onto the calling branch's stack. No OTel span is created.
    • attachCurrentSpan

      @CanIgnoreReturnValue public String attachCurrentSpan(InvocationContext context)
      Records the ambient OpenTelemetry span's IDs as the invocation root without creating or owning any span, so plugin-emitted rows correlate with the host's existing tracing.
    • ensureInvocationSpan

      public void ensureInvocationSpan(InvocationContext context)
    • popSpan

      @CanIgnoreReturnValue public Optional<com.google.adk.plugins.agentanalytics.TraceManager.RecordData> popSpan(InvocationContext context, String expectedKindPrefix)
      Pops the calling branch's top span record if its kind matches expectedKindPrefix.

      The branch scoping prevents a concurrently completing ParallelAgent branch from popping another branch's span; the kind check prevents a mismatched pop (e.g. an error callback firing without its corresponding push) from corrupting the stack.

    • popSpan

      @CanIgnoreReturnValue public Optional<com.google.adk.plugins.agentanalytics.TraceManager.RecordData> popSpan(InvocationContext context, String expectedKindPrefix, @Nullable String operationId)
      Pops the calling branch's matching span record.

      With an operationId, the record is located by kind AND operation identity (newest-first) rather than stack position: ADK executes an event's function calls concurrently by default within one branch, so a completion must remove its own record even when a sibling tool's record sits above it. Without an operationId, only the branch's top record is popped, and only when its kind matches.

    • clearStack

      public void clearStack()
    • getCurrentSpanAndParent

      public com.google.adk.plugins.agentanalytics.TraceManager.SpanIds getCurrentSpanAndParent(InvocationContext context)
    • getCurrentSpanId

      public Optional<String> getCurrentSpanId(InvocationContext context)
    • recordFirstToken

      public void recordFirstToken(String spanId)
    • getStartTime

      public Optional<Instant> getStartTime(String spanId)
    • getFirstTokenTime

      public Optional<Instant> getFirstTokenTime(String spanId)