[google-genai] uninstrument() raises AssertionError because __init__ resets the method snapshot on the singleton instrumentor; calls stay traced
Maintainers usually reply within 1 day
A pull request for this has already been merged.
- #853 by @VimalN2005 — merged
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 74/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- python
- Domain
- observability-sre
Research direction
Start with GoogleGenAiSdkInstrumentor.init and follow the snapshot lifecycle through _instrument() and _uninstrument(). Reproduce the issue with the supplied script, including constructing the singleton after instrumenting. Done means uninstrument() returns normally, later generate_content calls produce zero spans, and is_instrumented_by_opentelemetry is False.
Written by the indexing model from the issue text.
Description
Describe your environment
- opentelemetry-instrumentation-google-genai 1.2b0
- google-genai 2.28.0
- Python 3.x, Linux
What happened?
GoogleGenAiSdkInstrumentor().uninstrument() raises AssertionError and does not remove the instrumentation. Later generate_content calls are still traced, and is_instrumented_by_opentelemetry stays True, so the instrumentor cannot be re-instrumented either.
BaseInstrumentor is a singleton (__new__ returns the existing instance), but Python still runs __init__ on every GoogleGenAiSdkInstrumentor() call. GoogleGenAiSdkInstrumentor.__init__ sets self._generate_content_snapshot = None (and the interactions/embeddings snapshots). Any later construction therefore wipes the snapshots saved by _instrument(), and _uninstrument() then hits assert isinstance(snapshot, _MethodsSnapshot) in uninstrument_generate_content.
This also breaks code that keeps the original instance: constructing GoogleGenAiSdkInstrumentor() anywhere after instrument() (for example to check is_instrumented_by_opentelemetry) wipes the snapshot, so inst.uninstrument() fails too:
inst = GoogleGenAiSdkInstrumentor()
inst.instrument()
GoogleGenAiSdkInstrumentor() # same object, __init__ resets the snapshot
inst.uninstrument() # AssertionError
Steps to Reproduce
import logging, traceback
logging.disable(logging.WARNING)
import httpx
from google import genai
from google.genai import types
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
from opentelemetry.instrumentation.google_genai import GoogleGenAiSdkInstrumentor
BODY = {"candidates": [{"content": {"role": "model", "parts": [{"text": "hello"}]},
"finishReason": "STOP"}]}
client = genai.Client(api_key="x", http_options=types.HttpOptions(
base_url="http://mock",
httpx_client=httpx.Client(transport=httpx.MockTransport(lambda r: httpx.Response(200, json=BODY)))))
exporter = InMemorySpanExporter()
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(exporter))
def call(label):
exporter.clear()
client.models.generate_content(model="m", contents="hi")
print(f"{label:45s} spans: {len(exporter.get_finished_spans())}")
GoogleGenAiSdkInstrumentor().instrument(tracer_provider=provider)
call("after instrument()")
try:
GoogleGenAiSdkInstrumentor().uninstrument()
print("uninstrument() returned normally")
except Exception:
tb = traceback.format_exc().strip().splitlines()
print("uninstrument() raised:", tb[-1], "|", tb[-3].strip())
call("after uninstrument() (expected 0)")
print("is_instrumented_by_opentelemetry:", GoogleGenAiSdkInstrumentor().is_instrumented_by_opentelemetry)
Expected Result
uninstrument() returns normally, the call after it produces 0 spans, and is_instrumented_by_opentelemetry is False.
Actual Result
after instrument() spans: 1
uninstrument() raised: AssertionError | assert isinstance(snapshot, _MethodsSnapshot)
after uninstrument() (expected 0) spans: 1
is_instrumented_by_opentelemetry: True
Additional context
Possible fix: do not reset the snapshots in __init__ when they already exist (e.g. only initialize them if the attribute is missing), or store them at module or class level. Other instrumentors in this repo that keep state in __init__ may be affected in the same way.
- Dominant language
- Python
- Stars
- 48
- Forks
- 105
- Avg merge
- 2d 2h
- Merged PRs (30d)
- 109
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from open-telemetry/opentelemetry-python-genai
-
[genai-llama-index] Instrumentor imports llama_index at module load, crashes auto-instrumentation on Python 3.15Possibly taken @haneric00 claimed this 3 days ago. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
open-telemetry/opentelemetry-python-genai#1036 · 1 comment ·
Maintainers usually reply within 1 day
-
`opentelemetry-instrumentation-openai-v2` instrumentor entry point fails to loadPossibly taken @lmolkova claimed this 9 days ago. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
open-telemetry/opentelemetry-python-genai#997 · 2 comments ·
Maintainers usually reply within 1 day
-
Support disabling OpenAI Agents native trace export through an environment variablePossibly taken @123liuziming claimed this 18 days ago. Openenhancement
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
open-telemetry/opentelemetry-python-genai#922 · 3 comments ·
Maintainers usually reply within 1 day
-
[genai-bedrock] invoke_model body passed as a file-like object: no request parameters or input messages are recordedPossibly taken @SyedTashfin claimed this 28 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
open-telemetry/opentelemetry-python-genai#848 ·
Maintainers usually reply within 1 day
-
util-genai: ToolInvocation._apply_finish never calls the completion hook, so tool arguments/results bypass redaction hooksPossibly taken @akshat-lakhera claimed this 16 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
open-telemetry/opentelemetry-python-genai#678 · 2 comments ·
Maintainers usually reply within 1 day
All issues in open-telemetry/opentelemetry-python-genai
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
aws-samples/sample-per-model-bedrock#795 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 1 day
-
Pretalx reports older version to be the latest release than what is actually installed and availableOpen
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
micropython/micropython#19906 ·
Maintainers usually reply within 1 day