Skip to content
Monitoring
Skill

/maple-agent-tracing-google-adk

Trace Google ADK (Agent Development Kit) agents with Maple, in Python (google-adk) and TypeScript (@google/adk): register an OTLP tracer provider, get the transcript and tool calls into the GenAI attributes Maple reads (env switches + a plugin in Python, a span processor in

BOOST
From plugin
maple
1.8k37 skills
Install
$ npx -y skills add mapletechlabs/maple --skill maple-agent-tracing-google-adk --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/maple-agent-tracing-google-adk

Context preview

The summary Claude sees to decide when to auto-load this skill.

Trace Google ADK (Agent Development Kit) agents with Maple, in Python (google-adk) and TypeScript (@google/adk): register an OTLP tracer provider, get the transcript and tool calls into the GenAI attributes Maple reads (env switches + a plugin in Python, a span processor in

SKILL.md

maple-agent-tracing-google-adk.SKILL.md
name: maple-agent-tracing-google-adk
description: "Trace Google ADK (Agent Development Kit) agents with Maple, in Python (google-adk) and TypeScript (@google/adk): register an OTLP tracer provider, get the transcript and tool calls into the GenAI attributes Maple reads (env switches + a plugin in Python, a span processor in TypeScript), and keep one session per ADK session id. Triggers on 'trace my ADK agent', 'add Maple to Google ADK', 'add Maple to @google/adk', 'agent sessions for Google ADK', 'OpenTelemetry for google-adk'."

Maple agent tracing: Google ADK (Python and TypeScript)

Goal: one conversation = one ADK session id = one Maple Agent Session, with the transcript (user, assistant, tool calls and results), model calls, tool calls with arguments/results, failures, and tokens.

ADK emits its own OTel spans (scope `gcp.vertex.agent`): `invocation` > `invoke_agent {agent}` > `call_llm` > `generate_content {model}`, plus `execute_tool {tool}`. No instrumentation package is needed. You add: a tracer provider (Runner apps only), the env vars below, one plugin, one span processor.

**TypeScript (`@google/adk` in `package.json`): follow [references/typescript.md](references/typescript.md) instead of Steps 0-7 below.** Step 1 (key and region) applies to both. ADK for TypeScript records content differently (Gemini-shaped JSON on `gcp.vertex.agent.*` attributes, no `generate_content` span), so the Python env switches and plugin do not apply there.

Step 0: Detect versions and existing setup

  • Read `pyproject.toml` / `requirements*.txt` / `uv.lock`. Require `google-adk>=2.10`; upgrade if lower (before 2.7, `gen_ai.system` is always `gemini` and failed tools are not marked ERROR).
  • ADK caps `opentelemetry-sdk<=1.42.1`. Never pin a newer OTel package; let the resolver choose.
  • Find how ADK runs:
  • `adk web` / `adk api_server` (CLI): ADK builds the tracer provider from `OTEL_EXPORTER_OTLP_*` env. Do NOT register another provider.
  • `Runner(...)` in the app's own code (FastAPI, worker, script, notebook): nothing is exported unless the app registers a provider. You must add one.
  • Grep for an existing OTel setup: `set_tracer_provider`, `TracerProvider(`, `logfire.configure`, `sentry_sdk.init`, `maybe_set_otel_providers`, `opentelemetry-instrument`. If one exists, add the Maple processor to that provider instead of creating a second one.
  • Grep for double instrumentation and remove it if it only exists for tracing: `litellm.callbacks` containing `"otel"`, `openinference-instrumentation-google-adk` / `GoogleADKInstrumentor`, `openinference-instrumentation-litellm`, `openinference-instrumentation-openai`, `opentelemetry-instrumentation-openai-v2`. Ask the user before removing something another backend relies on.

Step 1: Key and region

  • US: `https://ingest.maple.dev`. EU: `https://ingest.eu.maple.dev`.
  • Header: `Authorization=Bearer <key>`.
  • Key given in the prompt: use it. No key: use the literal `MAPLE_TEST` (ingest accepts and discards it) and tell the user to replace it with a key from Settings → Ingestion.
  • Never put a private `maple_sk_` key in browser code.
  • Follow the repo's secret/env convention (`.env`, settings module, deployment env). If there is none, inline values are acceptable: ingest keys are write-only.
  • Key read from env in code: when it is unset, log one warning (`MAPLE_INGEST_KEY is not set; Maple telemetry export is disabled`) and skip the Maple exporter so the app runs normally. Never raise or exit over the key; no bare `KeyError` on import, no header without a key.

Step 2: Install and initialize

pip install "google-adk>=2.10" opentelemetry-exporter-otlp-proto-http

Add `litellm` only if the app uses `google.adk.models.lite_llm.LiteLlm`. Use the repo's package manager (`uv add`, `poetry add`).

Env vars (all runtimes, including `adk web`/`api_server`):

OTEL_SERVICE_NAME=<service-name>
OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.maple.dev
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer <key>"
OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=SPAN_ONLY
ADK_CAPTURE_MESSAGE_CONTENT_IN_SPANS=false
  • `OTEL_EXPORTER_OTLP_ENDPOINT` gets `/v1/traces` appended. If you use `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` instead, give the full `https://ingest.maple.dev/v1/traces`.
  • The env vars must be in the process environment when `telemetry.py` builds the exporter. Otherwise it silently targets `localhost:4318` with no key.

For Runner apps, create `telemetry.py` next to the entry point:

# telemetry.py
import json

from google.adk.plugins.base_plugin import BasePlugin
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor


class SkipDuplicateToolSpans(BatchSpanProcessor):
    """Drops two ADK tool spans that would count a call twice: the
    `execute_tool (merged)` summary of parallel calls, and the span of a call
    paused for confirmation (it runs again, in its own span, once approved)."""

    def on_end(self, span):
        if span.name != "execute_tool (merged)" and not span.attributes.get("adk.awaiting_confirmation"):
            super().on_end(span)


class ToolCallAttributes(BasePlugin):
    """Records each tool call's arguments and result on its `execute_tool` span,
    and marks the span of a call that is waiting for confirmation."""

    def __init__(self):
        super().__init__(name="tool_call_attributes")

    async def before_tool_callback(self, *, tool, tool_args, tool_context):
        trace.get_current_span().set_attribute("gen_ai.tool.call.arguments", json.dumps(tool_args, default=str))

    async def after_tool_callback(self, *, tool, tool_args, tool_context, result):
        span = trace.get_current_span()
        if tool_cont
Read more
Ships withmaple

OpenTelemetry observability platform

Get the whole plugin

Other skills on maple.