Skip to content

[issue-5374] [P SDK] Fix ADK OTel tracer re-patching on deep copy#5381

Closed
ollieagent[bot] wants to merge 8 commits intomainfrom
ollie/issue-5374-remove-otel-span-patching-941773
Closed

[issue-5374] [P SDK] Fix ADK OTel tracer re-patching on deep copy#5381
ollieagent[bot] wants to merge 8 commits intomainfrom
ollie/issue-5374-remove-otel-span-patching-941773

Conversation

@ollieagent
Copy link
Copy Markdown
Contributor

@ollieagent ollieagent Bot commented Feb 24, 2026

Details

The Opik ADK integration was re-applying its OpenTelemetry tracer patch on every deserialization of OpikTracer, which occurs whenever an agent is deep-copied (e.g., model_copy(deep=True) per request in frameworks like ag-ui-adk). This caused the Opik tracer to be re-installed over the ADK module-level tracers on every request, making it impossible to work around.

Two bugs were fixed:

1. No idempotency guard on _patch_adk_opentelemetry_tracers

Unlike _patch_adk_lite_llm() which checks hasattr(old_function, "opik_patched") before patching, _patch_adk_opentelemetry_tracers unconditionally replaced the ADK module-level tracer methods on every call. A module-level boolean flag _adk_opentelemetry_tracers_patched is now set on first application and checked at entry, making the function idempotent.

2. __setstate__ triggered patch_adk() on every deserialization

__setstate__ called _init_internal_attributes(), which in turn called patchers.patch_adk(). This re-applied the OTel tracer patch on every pickle.loads or deepcopy of an OpikTracer instance, undoing any workarounds applied at startup.

__setstate__ now directly reinitializes only the runtime state that needs restoring after deserialization (_opik_client, _last_model_output, _ttft_tracking), without triggering any patching.

Note: OpikADKOtelTracer still returns INVALID_SPAN to OTel by design — it is the mechanism by which Opik creates its own traces and spans from ADK's span lifecycle events. The OTel patching is necessary for Opik's tracing to function; removing it entirely would cause before_agent_callback and related callbacks to fail silently (they update existing spans but do not create them).

Change checklist

  • User facing
  • Documentation update

Issues

Testing

Run existing ADK integration tests:

cd sdks/python
python -m pytest tests/library_integration/adk/test_adk_sync.py::test_adk__track_adk_agent_recursive__idempotent_calls_make_no_duplicated_callbacks tests/library_integration/adk/test_adk_sync.py::test_adk__opik_tracer__unpickled_object_works_as_expected -v

Verify the idempotency guard manually:

from opik.integrations.adk.patchers import patchers
assert patchers._adk_opentelemetry_tracers_patched == False

from opik.integrations.adk import OpikTracer
tracer = OpikTracer()
assert patchers._adk_opentelemetry_tracers_patched == True

# Deep copy no longer re-patches
import copy
tracer2 = copy.deepcopy(tracer)
# tracer2 is functional and the patch was not reapplied

Documentation

No documentation updates required.

…zation

Add idempotency guard to _patch_adk_opentelemetry_tracers using a
module-level flag to prevent re-patching when OpikTracer is deep-copied
per request. Fix __setstate__ to reinitialize only non-patching state
(client, tracking dicts) instead of calling _init_internal_attributes()
which unconditionally re-invoked patchers.patch_adk().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added python Pull requests that update Python code Python SDK labels Feb 24, 2026
Douglas Blank and others added 2 commits February 24, 2026 09:45
Update _patch_adk_opentelemetry_tracers to refresh opik_client reference
when called after initial patching. The global flag prevents re-patching
the ADK tracers (correct), but the stale opik_client in OpikADKOtelTracer
caused failures when the client was ended and recreated between tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Douglas Blank and others added 3 commits February 24, 2026 10:26
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add pytestmark = pytest.mark.usefixtures("ensure_vertexai_configured") to
ADK test files that make real Google AI API calls. This matches the pattern
used by genai, crewai, langchain_vertexai, anthropic, and bedrock test suites.

Without this fixture, the ensure_vertexai_configured session fixture is never
called, so GCP_CREDENTIALS_JSON is never written to a file and
GOOGLE_APPLICATION_CREDENTIALS is never set. The Google client then fails to
find credentials and falls back to requiring GOOGLE_API_KEY, which is absent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added the tests Including test files, or tests related like configuration. label Feb 24, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 13, 2026

Python SDK Unit Tests Results (Python 3.10)

2 195 tests  ±0   2 195 ✅ ±0   51s ⏱️ +5s
    1 suites ±0       0 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit a70c4af. ± Comparison against base commit d2e999a.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 13, 2026

Python SDK Unit Tests Results (Python 3.13)

2 195 tests  ±0   2 195 ✅ ±0   46s ⏱️ ±0s
    1 suites ±0       0 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit a70c4af. ± Comparison against base commit d2e999a.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 13, 2026

Python SDK Unit Tests Results (Python 3.14)

2 195 tests  ±0   2 195 ✅ ±0   38s ⏱️ +4s
    1 suites ±0       0 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit a70c4af. ± Comparison against base commit d2e999a.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 13, 2026

Python SDK Unit Tests Results (Python 3.12)

2 195 tests  ±0   2 195 ✅ ±0   47s ⏱️ ±0s
    1 suites ±0       0 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit a70c4af. ± Comparison against base commit d2e999a.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 13, 2026

Python SDK Unit Tests Results (Python 3.11)

2 195 tests  ±0   2 195 ✅ ±0   46s ⏱️ -1s
    1 suites ±0       0 💤 ±0 
    1 files   ±0       0 ❌ ±0 

Results for commit a70c4af. ± Comparison against base commit d2e999a.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 13, 2026

Python SDK E2E Tests Results (Python 3.11)

243 tests  ±0   241 ✅ ±0   8m 15s ⏱️ +14s
  1 suites ±0     2 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit a70c4af. ± Comparison against base commit d2e999a.

This pull request removes 1 and adds 1 tests. Note that renamed tests count towards both.
tests.e2e.test_tracing ‑ test_opik_client__update_trace__happy_flow[None-None-None-None-019ce782-0779-74be-a9b9-17e78f82dd92]
tests.e2e.test_tracing ‑ test_opik_client__update_trace__happy_flow[None-None-None-None-019ce7a9-0b29-7e95-8c9a-4843ea0ba1da]

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 13, 2026

Python SDK E2E Tests Results (Python 3.13)

243 tests  ±0   241 ✅ ±0   7m 59s ⏱️ -8s
  1 suites ±0     2 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit a70c4af. ± Comparison against base commit d2e999a.

This pull request removes 1 and adds 1 tests. Note that renamed tests count towards both.
tests.e2e.test_tracing ‑ test_opik_client__update_trace__happy_flow[None-None-None-None-019ce781-b1ab-75e8-9a75-cd96f2e35396]
tests.e2e.test_tracing ‑ test_opik_client__update_trace__happy_flow[None-None-None-None-019ce7ae-d990-7fbe-862d-a2993a1f8548]

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 13, 2026

Python SDK E2E Tests Results (Python 3.14)

243 tests  ±0   241 ✅ ±0   8m 36s ⏱️ +17s
  1 suites ±0     2 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit a70c4af. ± Comparison against base commit d2e999a.

This pull request removes 1 and adds 1 tests. Note that renamed tests count towards both.
tests.e2e.test_tracing ‑ test_opik_client__update_trace__happy_flow[None-None-None-None-019ce782-5798-70f9-9791-0a0df984a4a6]
tests.e2e.test_tracing ‑ test_opik_client__update_trace__happy_flow[None-None-None-None-019ce7b0-3573-7988-a1f5-df6bd72c0669]

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 13, 2026

Python SDK E2E Tests Results (Python 3.10)

243 tests  ±0   241 ✅ ±0   8m 7s ⏱️ -8s
  1 suites ±0     2 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit a70c4af. ± Comparison against base commit d2e999a.

This pull request removes 1 and adds 1 tests. Note that renamed tests count towards both.
tests.e2e.test_tracing ‑ test_opik_client__update_trace__happy_flow[None-None-None-None-019ce781-f16b-7001-91c2-1eace6dc44b6]
tests.e2e.test_tracing ‑ test_opik_client__update_trace__happy_flow[None-None-None-None-019ce7a9-cb2a-77ac-af8d-f90b333f354f]

♻️ This comment has been updated with latest results.

…y patched

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

Python SDK E2E Tests Results (Python 3.12)

243 tests  ±0   241 ✅ ±0   7m 29s ⏱️ -27s
  1 suites ±0     2 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit a70c4af. ± Comparison against base commit d2e999a.

This pull request removes 1 and adds 1 tests. Note that renamed tests count towards both.
tests.e2e.test_tracing ‑ test_opik_client__update_trace__happy_flow[None-None-None-None-019ce781-730e-722e-b630-db72e0d9c373]
tests.e2e.test_tracing ‑ test_opik_client__update_trace__happy_flow[None-None-None-None-019ce7aa-4864-7617-a48c-a80b9e499d3c]

@andrescrz
Copy link
Copy Markdown
Member

Hi! Thanks for your contribution 🙌

We’re going to close this PR for now since it has merge conflicts and appears to be inactive. That said, feel free to reopen it anytime if you’d like to continue working on it—we’d be happy to take another look.

Thanks again!

@andrescrz andrescrz closed this Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Made by Ollie 🦉 Python SDK python Pull requests that update Python code tests Including test files, or tests related like configuration.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ADK integration: OpikADKOtelTracer kills all OpenTelemetry spans and re-patches on every request via __setstate__

2 participants