From 478c32a7dba5ae10b325e434c5259e1a49d6c695 Mon Sep 17 00:00:00 2001 From: Haiyuan Cao Date: Sat, 18 Jul 2026 04:25:27 -0700 Subject: [PATCH 1/3] docs(bqaa): document ADK Java preview-readiness fixes (July 2026) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Covers google/adk-java@c685ece46b (redaction, table bootstrap, drop stats) and google/adk-java@2027a4b53d (tracing, lifecycle, redaction, HITL/TOOL_PAUSED pairing), rebuilt on current main and gated as post-v1.6.0 until the next adk-java release is tagged: - Top note gating the new Java behavior, with a TODO(publish) marker. - ADK 2.0 section: Java emits TOOL_PAUSED and the pause/resume pairing keys at the top level of attributes (no attributes.adk envelope), without AGENT_TRANSFER / AGENT_STATE_CHECKPOINT / EVENT_COMPACTION; Java variant of the base-table pairing query; HITL completions carry the same top-level pair keys for direct base-table joins. - Views footnote: Java creates v_tool_paused and the pause columns on v_tool_completed only; the three workflow views are Python-only. - Dropped-event observability: Java getDropStats() with all eight drop reasons (queue_full, append_error, serialization_error, after_close, shutdown_timeout, writer_permit_exhausted, writer_create_error, late_after_finalize). - Built-in redaction: Java redacts the six sensitive keys plus temp: (not secret:); contentFormatter contract (thread-safe, non-blocking, no mutation) and fail-closed behavior. - Tracing: Java ID-only span tracking; trace_id wording no longer claims 32-hex absolutely — Java falls back to the ADK invocation ID. - Public methods (Java): getDropStats() and the JVM shutdown-hook drain. Co-Authored-By: Claude Fable 5 --- docs/integrations/bigquery-agent-analytics.md | 145 +++++++++++++++--- 1 file changed, 122 insertions(+), 23 deletions(-) diff --git a/docs/integrations/bigquery-agent-analytics.md b/docs/integrations/bigquery-agent-analytics.md index 875114efd1..863d551400 100644 --- a/docs/integrations/bigquery-agent-analytics.md +++ b/docs/integrations/bigquery-agent-analytics.md @@ -11,6 +11,20 @@ catalog_tags: ["observability", "google"] Supported in ADKPython v1.21.0Java v1.5.0 +!!! important "ADK Java version requirement" + + The Java-specific behavior called out in this document — `TOOL_PAUSED` + pause/resume pairing, `getDropStats()`, built-in redaction, cross-region + write routing, and the JVM shutdown-hook drain — requires a newer build of + the Java plugin. As of this writing that support is present on + `google/adk-java` `main` but is **not yet in a published release** (it is + not in `v1.6.0`, the latest release). + + The BigQuery Agent Analytics Plugin significantly enhances Agent Development Kit (ADK) by providing a robust solution for in-depth agent behavior analysis. Using the ADK Plugin architecture and the **BigQuery Storage Write API**, it captures @@ -29,10 +43,13 @@ transfers, state checkpoints, event compaction, and long-running tools. It adds four new event types — `AGENT_TRANSFER`, `AGENT_STATE_CHECKPOINT`, `EVENT_COMPACTION`, and `TOOL_PAUSED` — and stamps an `attributes.adk` envelope on every row so you can reconstruct the agent execution graph and join a paused -tool to the row that resumes it. See [Agent workflow and pause/resume events +tool to the row that resumes it. In **Java**, this support currently covers the +`TOOL_PAUSED` event and its pause/resume pairing keys only (without the +`attributes.adk` envelope). See [Agent workflow and pause/resume events (ADK 2.0)](#adk-2-events) for details. -The plugin includes three reliability and observability fixes: +The plugin includes three reliability and observability fixes (in Java these +land in the first release after `v1.6.0`): - **Cross-region Storage Write API routing.** Writes to BigQuery datasets outside the `US` multi-region (for example `EU` or `northamerica-northeast1`) @@ -40,10 +57,10 @@ The plugin includes three reliability and observability fixes: fail with a "session not found" / stream-not-found error and silently drop every row. - **Dropped-event observability.** Dropped rows are tracked per drop reason - (`queue_full`, `arrow_prep_failed`, `retry_exhausted`, `non_retryable`, - `unexpected_error`) and exposed via - `BigQueryAgentAnalyticsPlugin.get_drop_stats()` so a host can poll and export - the counts to its own monitoring. + and exposed via `BigQueryAgentAnalyticsPlugin.get_drop_stats()` (Python) or + `getDropStats()` (Java) so a host can poll and export the counts to its own + monitoring. The reason keys differ per language — see [Dropped-event + observability](#dropped-event-observability). - **No duplicate spans in Cloud Trace.** When Agent Engine telemetry (`GOOGLE_CLOUD_AGENT_ENGINE_ENABLE_TELEMETRY=true`) or any other Cloud Trace exporter is wired to the global tracer provider, the plugin no longer @@ -723,7 +740,7 @@ provides a comprehensive reference with example values. | **session_id** | `STRING` | `NULLABLE` | A persistent identifier for the entire conversation thread. Stays constant across multiple turns and sub-agent calls. | `04275a01-1649-4a30-b6a7-5b443c69a7bc` | | **invocation_id** | `STRING` | `NULLABLE` | The unique identifier for a single execution turn or request cycle. Corresponds to `trace_id` in many contexts. | `e-b55b2000-68c6-4e8b-b3b3-ffb454a92e40` | | **user_id** | `STRING` | `NULLABLE` | The identifier of the user (human or system) initiating the session. Extracted from the `User` object or metadata. | `test_user` | -| **trace_id** | `STRING` | `NULLABLE` | 32-character hex Trace ID. Inherited from the ambient OpenTelemetry span when one is active (e.g. Agent Engine's invocation span or the ADK Runner span) so BigQuery rows join cleanly to your existing Cloud Trace traces; otherwise generated by the plugin per invocation. Links all operations within a single distributed request lifecycle. | `a2c7f13d3a3f0bbb8793692f76a6012a` | +| **trace_id** | `STRING` | `NULLABLE` | Trace identifier. It is a 32-character hex OpenTelemetry trace ID when inherited from an ambient span (e.g. Agent Engine's invocation span or the ADK Runner span), so BigQuery rows join cleanly to your existing Cloud Trace traces. Without an ambient span, Python also generates that format as its per-invocation fallback, while Java falls back to the ADK invocation ID. Links all operations within a single distributed request lifecycle. | `a2c7f13d3a3f0bbb8793692f76a6012a` | | **span_id** | `STRING` | `NULLABLE` | 16-character hex Span ID identifying this specific atomic operation. **Tracked on the plugin's internal stack, not exported as an OTel span** — the plugin does not call `tracer.start_span` against your configured OpenTelemetry provider. The root invocation span reuses the ambient OTel span's id when one is active; child spans are generated internally (see [Tracing and observability](#tracing-and-observability)). | `3916f5762bcd4d42` | | **parent_span_id** | `STRING` | `NULLABLE` | 16-character hex Span ID of the immediate caller. Used to reconstruct the parent-child execution tree (DAG). | `4c4a42bfdeb84934` | | **content** | `JSON` | `NULLABLE` | The primary event payload. Structure is polymorphic based on `event_type`. | `{"system_prompt": "You are...", "prompt": [{"role": "user", "content": "hello"}], "response": "Hi", "usage": {"total": 15}}` | @@ -848,7 +865,11 @@ columns: The four workflow views (`v_agent_transfer`, `v_agent_state_checkpoint`, `v_event_compaction`, `v_tool_paused`) and the `pause_kind` / `function_call_id` columns on `v_tool_completed` come with the [ADK 2.0 workflow event -support](#adk-2-events). +support](#adk-2-events). In **Java** (builds newer than `v1.6.0`), only +`v_tool_paused` and the `pause_kind` / `function_call_id` columns on +`v_tool_completed` are created; `v_agent_transfer`, `v_agent_state_checkpoint`, +and `v_event_compaction` are Python-only (the Java plugin does not emit those +events). ## Event types and payloads {#event-types} @@ -1037,8 +1058,8 @@ updated by tools). !!! note "Built-in redaction" State keys prefixed with `temp:` or `secret:` are automatically redacted to - `[REDACTED]` in the logged `state_delta`. See [Built-in - redaction](#built-in-redaction) for details. + `[REDACTED]` in the logged `state_delta` (Java: `temp:` only). See + [Built-in redaction](#built-in-redaction) for details. ```json { @@ -1144,6 +1165,15 @@ Logged when an A2A remote agent call completes. Supported in ADKPython v2.3.0 +!!! note "Java support" + + The **Java** plugin supports a subset of this section: builds newer than + `v1.6.0` emit `TOOL_PAUSED` and the pause/resume pairing described below, + but do **not** emit `AGENT_TRANSFER`, `AGENT_STATE_CHECKPOINT`, or + `EVENT_COMPACTION`, and do not write the `attributes.adk` envelope — the + Java plugin stores `pause_kind` and `function_call_id` at the **top level** + of `attributes` instead (see the query note below). + ADK 2.0 introduced multi-agent workflows (agents that transfer control, checkpoint their state, and compact long histories) and long-running tools that pause and resume across turns. The plugin makes these flows observable with four @@ -1152,7 +1182,8 @@ rows back to the ADK event that produced them. #### The `attributes.adk` envelope -Every row now carries an `attributes.adk` object. `schema_version` and +The envelope is written by the **Python** plugin only. Every row now carries an +`attributes.adk` object. `schema_version` and `app_name` are always present; the remaining fields are added only for rows that originate from an ADK event (lifecycle and workflow events), so on a callback-only row they are simply absent (and resolve to SQL `NULL` when queried). @@ -1254,6 +1285,20 @@ see the note below.) } ``` +!!! note "Java attribute location" + + The Java plugin writes the pair keys at the top level of `attributes` — + `"attributes": {"pause_kind": "tool", "function_call_id": "call-789"}` — + with no `adk` wrapper. In the base-table query below, replace + `'$.adk.pause_kind'` / `'$.adk.function_call_id'` with `'$.pause_kind'` / + `'$.function_call_id'`. The view-based query works unchanged for both + languages, because the views expose the keys as flat columns. + + Java also stamps the same top-level pair keys on `HITL_*_REQUEST_COMPLETED` + rows, so a HITL `TOOL_PAUSED` row can be joined directly to its completion + on `function_call_id` in the base table (there is no dedicated view for + HITL completions). + !!! note "Relationship to HITL events" A HITL request (`adk_request_confirmation`, etc.) still emits its dedicated @@ -1924,6 +1969,21 @@ by credential services) is never persisted in BigQuery. on raw content, so use it to add masking for secrets that may appear in free-form payloads. +!!! note "Built-in redaction in Java" + + The Java plugin includes built-in redaction in builds newer than `v1.6.0`. + It redacts the same six key names (case-insensitive) recursively across the + assembled `attributes` tree — including session state and state deltas — + and any key prefixed with **`temp:`**. Unlike Python, the Java plugin does + **not** redact keys prefixed `secret:`; keep secrets out of non-`temp:` + state scopes or mask them with a custom `contentFormatter`. + + A custom Java `contentFormatter` must be **thread-safe** (it is called + concurrently across invocations) and **fast/non-blocking** (it runs on the + event-processing path), and it must return a **new object** rather than + mutating the content it receives. If it throws, the Java plugin drops the + row's content (fail-closed) rather than logging the unformatted payload. + ### Use `content_formatter` to redact additional secrets Provide a custom `content_formatter` function in `BigQueryLoggerConfig` to strip @@ -2119,7 +2179,10 @@ call) reconstructs cleanly from BigQuery. `TracerProvider`, so its instrumentation never reaches your configured exporter — this is what prevents duplicate spans in Cloud Trace when Agent Engine telemetry is enabled (`GOOGLE_CLOUD_AGENT_ENGINE_ENABLE_TELEMETRY=true`) - or when you wire any other Cloud Trace exporter into the host process. + or when you wire any other Cloud Trace exporter into the host process. The + same internal, ID-only span tracking applies to the Java plugin in builds + newer than `v1.6.0`; earlier Java builds created plugin-owned OpenTelemetry + spans that could surface as duplicates next to framework spans. - **`trace_id` inherited from the ambient OTel span when present.** If the surrounding runtime has already started an OTel span — Agent Engine's invocation span, the ADK `Runner` invocation span, or any span you opened @@ -2128,7 +2191,8 @@ call) reconstructs cleanly from BigQuery. Cloud Trace traces via a shared `trace_id`. - **Fallback when no ambient span is present.** If no ambient OTel span is active (e.g. a non-Agent-Engine deployment with no host-side tracer - configured), the plugin generates a per-invocation 32-hex `trace_id` so the + configured), the plugin generates a per-invocation 32-hex `trace_id` (the + Java plugin falls back to the ADK invocation ID as the `trace_id`) so the parent-child hierarchy is always preserved in BigQuery, even without any external tracer setup. - **No `TracerProvider` is required.** Configuring an OpenTelemetry @@ -2181,6 +2245,14 @@ call) reconstructs cleanly from BigQuery. - **`plugin.close()`**: Gracefully shuts down the plugin, flushing pending events and releasing resources (including the BigQuery write client and executors). - **Automatic Closure**: If you are using `InMemoryRunner`, calling `runner.close()` will automatically close all registered plugins, including the BigQuery Agent Analytics plugin. + - **`plugin.getDropStats()`** (builds newer than `v1.6.0`): Returns an + `ImmutableMap` of dropped-event counts per drop reason. See + [Dropped-event observability](#dropped-event-observability). + - **JVM shutdown hook** (builds newer than `v1.6.0`): The plugin registers + a shutdown hook at construction, so pending events are drained + (best-effort, bounded by `shutdownTimeout`) at JVM exit even if `close()` + is never called. An explicit `close()` deregisters the hook. Still prefer + calling `close()` for a deterministic flush. ```java // Manual shutdown @@ -2194,7 +2266,7 @@ queue overflows or when a write ultimately fails. The plugin tracks dropped rows per `drop_reason` and exposes a polling API so a host can detect, alert on, and ship the counts to its own monitoring. -**Drop reasons:** +**Drop reasons (Python):** | Reason | Cause | |---|---| @@ -2204,15 +2276,42 @@ on, and ship the counts to its own monitoring. | `non_retryable` | Storage Write API returned a non-retryable error (permissions, quota, schema rejection). Usually requires operator intervention. | | `unexpected_error` | Any other exception caught while preparing or writing the batch. | +**Drop reasons (Java, builds newer than `v1.6.0`):** + +| Reason | Cause | +|---|---| +| `queue_full` | The in-memory batch queue overflowed. Increase `queueMaxSize` on `BigQueryLoggerConfig`, raise `batchSize`, or scale the consumer side. | +| `append_error` | The Storage Write API append ultimately failed — retries exhausted or a non-retryable error (permissions, quota, schema rejection). | +| `serialization_error` | A row could not be serialized for the write stream (typically a schema/type mismatch). Inspect logs for the offending field. | +| `after_close` | A row reached an already-closed per-invocation processor. | +| `shutdown_timeout` | Queued rows remained when the bounded final drain expired. | +| `writer_permit_exhausted` | The live-writer safety cap was exhausted — normally during a Storage Write outage or delayed cleanup. | +| `writer_create_error` | `StreamWriter` construction or processor startup failed. | +| `late_after_finalize` | Async work completed after its invocation was finalized or while the plugin was closing. | + **Reading the counts:** -```python -# Snapshot of {drop_reason: count} since plugin start. -stats = plugin.get_drop_stats() -# Example: {"queue_full": 12, "retry_exhausted": 0, ...} +=== "Python" -total_dropped = sum(stats.values()) -``` + ```python + # Snapshot of {drop_reason: count} since plugin start. + stats = plugin.get_drop_stats() + # Example: {"queue_full": 12, "retry_exhausted": 0, ...} + + total_dropped = sum(stats.values()) + ``` + +=== "Java" + + ```java + // Snapshot of {drop_reason: count} since plugin start. + ImmutableMap stats = plugin.getDropStats(); + // Example: {queue_full=12, append_error=0, serialization_error=0, + // after_close=0, shutdown_timeout=0, writer_permit_exhausted=0, + // writer_create_error=0, late_after_finalize=0} + + long totalDropped = stats.values().stream().mapToLong(Long::longValue).sum(); + ``` **Exporting to your monitoring system** — poll periodically and ship the deltas: @@ -2237,9 +2336,9 @@ async def export_loop(plugin): await asyncio.sleep(60) ``` -A non-zero `queue_full` or `retry_exhausted` count on a sustained basis is the -clearest signal that BQAA is at risk of data loss — surface it on a dashboard or -alert. +A non-zero `queue_full` or `retry_exhausted` (Java: `append_error`) count on a +sustained basis is the clearest signal that BQAA is at risk of data loss — +surface it on a dashboard or alert. ### Multiprocessing and fork safety From fe5adffc4ecbfde5a1790b4f29f77f4f99e6252d Mon Sep 17 00:00:00 2001 From: Haiyuan Cao Date: Sun, 19 Jul 2026 08:03:46 -0700 Subject: [PATCH 2/3] =?UTF-8?q?docs(bqaa):=20address=20second=20review=20?= =?UTF-8?q?=E2=80=94=20drop-stat=20semantics=20and=20publish=20plan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Closing guidance: any non-zero drop counter is actual loss, not risk; alert on every reason, with queue_full / write-error counts called out as throughput or Storage Write health signals. - Java append_error: broaden the definition to match BatchProcessor — any batch-preparation or append failure other than AppendSerializationError (timeouts, exhausted or non-retryable writes, unexpected conversion failures). - TODO(publish) marker: on release, delete the preview admonition and convert gated sections to section-level language-support-tag Java chips per PR #1942, instead of keeping prose version callouts. Co-Authored-By: Claude Fable 5 --- docs/integrations/bigquery-agent-analytics.md | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/integrations/bigquery-agent-analytics.md b/docs/integrations/bigquery-agent-analytics.md index 863d551400..82d7f521ce 100644 --- a/docs/integrations/bigquery-agent-analytics.md +++ b/docs/integrations/bigquery-agent-analytics.md @@ -19,11 +19,15 @@ catalog_tags: ["observability", "google"] the Java plugin. As of this writing that support is present on `google/adk-java` `main` but is **not yet in a published release** (it is not in `v1.6.0`, the latest release). - + The BigQuery Agent Analytics Plugin significantly enhances Agent Development Kit (ADK) by providing a robust solution for in-depth agent behavior analysis. Using @@ -2281,7 +2285,7 @@ on, and ship the counts to its own monitoring. | Reason | Cause | |---|---| | `queue_full` | The in-memory batch queue overflowed. Increase `queueMaxSize` on `BigQueryLoggerConfig`, raise `batchSize`, or scale the consumer side. | -| `append_error` | The Storage Write API append ultimately failed — retries exhausted or a non-retryable error (permissions, quota, schema rejection). | +| `append_error` | Batch preparation or append failed for a cause other than `AppendSerializationError` — including timeouts, exhausted or non-retryable writes, and unexpected conversion failures. | | `serialization_error` | A row could not be serialized for the write stream (typically a schema/type mismatch). Inspect logs for the offending field. | | `after_close` | A row reached an already-closed per-invocation processor. | | `shutdown_timeout` | Queued rows remained when the bounded final drain expired. | @@ -2336,9 +2340,10 @@ async def export_loop(plugin): await asyncio.sleep(60) ``` -A non-zero `queue_full` or `retry_exhausted` (Java: `append_error`) count on a -sustained basis is the clearest signal that BQAA is at risk of data loss — -surface it on a dashboard or alert. +Any non-zero count means analytics rows were dropped before reaching BigQuery. +Alert on every reason; sustained `queue_full` or write-error counts +(`retry_exhausted` / `non_retryable` in Python, `append_error` in Java) +generally indicate throughput or Storage Write health problems. ### Multiprocessing and fork safety From ba107cf0b17b09d13c680bfac03adb1c462caacf Mon Sep 17 00:00:00 2001 From: Haiyuan Cao Date: Tue, 21 Jul 2026 16:14:07 -0700 Subject: [PATCH 3/3] docs(bqaa): ungate Java features for released adk-java v1.7.0 adk-java v1.7.0 (2026-07-20) ships the July preview-readiness fixes; verified no agentanalytics changes between the reviewed commit ba23601c and the v1.7.0 tag. Per the publish checklist: - Delete the preview 'ADK Java version requirement' admonition and its TODO(publish) marker. - Add the 'Java v1.7.0' language-support chip to the ADK 2.0 workflow section (PR #1942 convention). - Convert the inline 'builds newer than v1.6.0' callouts to v1.7.0 version references throughout. Co-Authored-By: Claude Fable 5 --- docs/integrations/bigquery-agent-analytics.md | 46 ++++++------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/docs/integrations/bigquery-agent-analytics.md b/docs/integrations/bigquery-agent-analytics.md index 82d7f521ce..28bf857884 100644 --- a/docs/integrations/bigquery-agent-analytics.md +++ b/docs/integrations/bigquery-agent-analytics.md @@ -11,24 +11,6 @@ catalog_tags: ["observability", "google"] Supported in ADKPython v1.21.0Java v1.5.0 -!!! important "ADK Java version requirement" - - The Java-specific behavior called out in this document — `TOOL_PAUSED` - pause/resume pairing, `getDropStats()`, built-in redaction, cross-region - write routing, and the JVM shutdown-hook drain — requires a newer build of - the Java plugin. As of this writing that support is present on - `google/adk-java` `main` but is **not yet in a published release** (it is - not in `v1.6.0`, the latest release). - - The BigQuery Agent Analytics Plugin significantly enhances Agent Development Kit (ADK) by providing a robust solution for in-depth agent behavior analysis. Using the ADK Plugin architecture and the **BigQuery Storage Write API**, it captures @@ -52,8 +34,8 @@ tool to the row that resumes it. In **Java**, this support currently covers the `attributes.adk` envelope). See [Agent workflow and pause/resume events (ADK 2.0)](#adk-2-events) for details. -The plugin includes three reliability and observability fixes (in Java these -land in the first release after `v1.6.0`): +The plugin includes three reliability and observability fixes (Java: v1.7.0 or +later): - **Cross-region Storage Write API routing.** Writes to BigQuery datasets outside the `US` multi-region (for example `EU` or `northamerica-northeast1`) @@ -869,7 +851,7 @@ columns: The four workflow views (`v_agent_transfer`, `v_agent_state_checkpoint`, `v_event_compaction`, `v_tool_paused`) and the `pause_kind` / `function_call_id` columns on `v_tool_completed` come with the [ADK 2.0 workflow event -support](#adk-2-events). In **Java** (builds newer than `v1.6.0`), only +support](#adk-2-events). In **Java** (v1.7.0+), only `v_tool_paused` and the `pause_kind` / `function_call_id` columns on `v_tool_completed` are created; `v_agent_transfer`, `v_agent_state_checkpoint`, and `v_event_compaction` are Python-only (the Java plugin does not emit those @@ -1166,15 +1148,15 @@ Logged when an A2A remote agent call completes. ### Agent workflow and pause/resume events (ADK 2.0) {#adk-2-events}
- Supported in ADKPython v2.3.0 + Supported in ADKPython v2.3.0Java v1.7.0
!!! note "Java support" - The **Java** plugin supports a subset of this section: builds newer than - `v1.6.0` emit `TOOL_PAUSED` and the pause/resume pairing described below, - but do **not** emit `AGENT_TRANSFER`, `AGENT_STATE_CHECKPOINT`, or - `EVENT_COMPACTION`, and do not write the `attributes.adk` envelope — the + The **Java** plugin supports a subset of this section: it emits + `TOOL_PAUSED` and the pause/resume pairing described below, + but does **not** emit `AGENT_TRANSFER`, `AGENT_STATE_CHECKPOINT`, or + `EVENT_COMPACTION`, and does not write the `attributes.adk` envelope — the Java plugin stores `pause_kind` and `function_call_id` at the **top level** of `attributes` instead (see the query note below). @@ -1975,7 +1957,7 @@ by credential services) is never persisted in BigQuery. !!! note "Built-in redaction in Java" - The Java plugin includes built-in redaction in builds newer than `v1.6.0`. + The Java plugin includes built-in redaction in v1.7.0 and later. It redacts the same six key names (case-insensitive) recursively across the assembled `attributes` tree — including session state and state deltas — and any key prefixed with **`temp:`**. Unlike Python, the Java plugin does @@ -2184,8 +2166,8 @@ call) reconstructs cleanly from BigQuery. exporter — this is what prevents duplicate spans in Cloud Trace when Agent Engine telemetry is enabled (`GOOGLE_CLOUD_AGENT_ENGINE_ENABLE_TELEMETRY=true`) or when you wire any other Cloud Trace exporter into the host process. The - same internal, ID-only span tracking applies to the Java plugin in builds - newer than `v1.6.0`; earlier Java builds created plugin-owned OpenTelemetry + same internal, ID-only span tracking applies to the Java plugin in v1.7.0 + and later; earlier Java builds created plugin-owned OpenTelemetry spans that could surface as duplicates next to framework spans. - **`trace_id` inherited from the ambient OTel span when present.** If the surrounding runtime has already started an OTel span — Agent Engine's @@ -2249,10 +2231,10 @@ call) reconstructs cleanly from BigQuery. - **`plugin.close()`**: Gracefully shuts down the plugin, flushing pending events and releasing resources (including the BigQuery write client and executors). - **Automatic Closure**: If you are using `InMemoryRunner`, calling `runner.close()` will automatically close all registered plugins, including the BigQuery Agent Analytics plugin. - - **`plugin.getDropStats()`** (builds newer than `v1.6.0`): Returns an + - **`plugin.getDropStats()`** (v1.7.0+): Returns an `ImmutableMap` of dropped-event counts per drop reason. See [Dropped-event observability](#dropped-event-observability). - - **JVM shutdown hook** (builds newer than `v1.6.0`): The plugin registers + - **JVM shutdown hook** (v1.7.0+): The plugin registers a shutdown hook at construction, so pending events are drained (best-effort, bounded by `shutdownTimeout`) at JVM exit even if `close()` is never called. An explicit `close()` deregisters the hook. Still prefer @@ -2280,7 +2262,7 @@ on, and ship the counts to its own monitoring. | `non_retryable` | Storage Write API returned a non-retryable error (permissions, quota, schema rejection). Usually requires operator intervention. | | `unexpected_error` | Any other exception caught while preparing or writing the batch. | -**Drop reasons (Java, builds newer than `v1.6.0`):** +**Drop reasons (Java, v1.7.0+):** | Reason | Cause | |---|---|