Skip to content

Commit d6f95e1

Browse files
committed
feat: support supress_instrumentation in opentelemetry-instrumentation-google-genai
1 parent d0d895d commit d6f95e1

File tree

5 files changed

+89
-0
lines changed

5 files changed

+89
-0
lines changed

instrumentation-genai/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/generate_content.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
_OpenTelemetryStabilitySignalType,
4545
_StabilityMode,
4646
)
47+
from opentelemetry.instrumentation.utils import is_instrumentation_enabled
4748
from opentelemetry.semconv._incubating.attributes import (
4849
code_attributes,
4950
gen_ai_attributes,
@@ -705,6 +706,11 @@ def instrumented_generate_content(
705706
config: Optional[GenerateContentConfigOrDict] = None,
706707
**kwargs: Any,
707708
) -> GenerateContentResponse:
709+
if not is_instrumentation_enabled():
710+
return wrapped_func(
711+
self, model=model, contents=contents, config=config, **kwargs
712+
)
713+
708714
candidates = []
709715
helper = _GenerateContentInstrumentationHelper(
710716
self,
@@ -778,6 +784,13 @@ def instrumented_generate_content_stream(
778784
config: Optional[GenerateContentConfigOrDict] = None,
779785
**kwargs: Any,
780786
) -> Iterator[GenerateContentResponse]:
787+
if not is_instrumentation_enabled():
788+
for resp in wrapped_func(
789+
self, model=model, contents=contents, config=config, **kwargs
790+
):
791+
yield resp
792+
return
793+
781794
candidates: list[Candidate] = []
782795
helper = _GenerateContentInstrumentationHelper(
783796
self,
@@ -851,6 +864,10 @@ async def instrumented_generate_content(
851864
config: Optional[GenerateContentConfigOrDict] = None,
852865
**kwargs: Any,
853866
) -> GenerateContentResponse:
867+
if not is_instrumentation_enabled():
868+
return await wrapped_func(
869+
self, model=model, contents=contents, config=config, **kwargs
870+
)
854871
helper = _GenerateContentInstrumentationHelper(
855872
self,
856873
otel_wrapper,
@@ -924,6 +941,11 @@ async def instrumented_generate_content_stream(
924941
config: Optional[GenerateContentConfigOrDict] = None,
925942
**kwargs: Any,
926943
) -> Awaitable[AsyncIterator[GenerateContentResponse]]: # type: ignore
944+
if not is_instrumentation_enabled():
945+
return await wrapped_func(
946+
self, model=model, contents=contents, config=config, **kwargs
947+
)
948+
927949
helper = _GenerateContentInstrumentationHelper(
928950
self,
929951
otel_wrapper,

instrumentation-genai/opentelemetry-instrumentation-google-genai/src/opentelemetry/instrumentation/google_genai/tool_call_wrapper.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
_OpenTelemetryStabilitySignalType,
3030
_StabilityMode,
3131
)
32+
from opentelemetry.instrumentation.utils import is_instrumentation_enabled
3233
from opentelemetry.semconv._incubating.attributes import (
3334
code_attributes,
3435
)
@@ -168,6 +169,9 @@ def _wrap_sync_tool_function(
168169
):
169170
@functools.wraps(tool_function)
170171
def wrapped_function(*args, **kwargs):
172+
if not is_instrumentation_enabled():
173+
return tool_function(*args, **kwargs)
174+
171175
span_name = _create_function_span_name(tool_function)
172176
attributes = _create_function_span_attributes(
173177
tool_function, args, kwargs, extra_span_attributes
@@ -193,6 +197,9 @@ def _wrap_async_tool_function(
193197
):
194198
@functools.wraps(tool_function)
195199
async def wrapped_function(*args, **kwargs):
200+
if not is_instrumentation_enabled():
201+
return await tool_function(*args, **kwargs)
202+
196203
span_name = _create_function_span_name(tool_function)
197204
attributes = _create_function_span_attributes(
198205
tool_function, args, kwargs, extra_span_attributes

instrumentation-genai/opentelemetry-instrumentation-google-genai/tests/generate_content/nonstreaming_base.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from google.genai.types import GenerateContentConfig, Part
2121
from pydantic import BaseModel, Field
2222

23+
from opentelemetry.instrumentation import utils
2324
from opentelemetry.instrumentation._semconv import (
2425
_OpenTelemetrySemanticConventionStability,
2526
_OpenTelemetryStabilitySignalType,
@@ -499,3 +500,14 @@ def test_records_metrics_data(self):
499500
self.otel.assert_has_metrics_data_named(
500501
"gen_ai.client.operation.duration"
501502
)
503+
504+
def test_suppress_instrumentation(self):
505+
self.configure_valid_response(text="Yep, it works!")
506+
with utils.suppress_instrumentation():
507+
response = self.generate_content(
508+
model="gemini-2.0-flash", contents="Does this work?"
509+
)
510+
self.assertEqual(response.text, "Yep, it works!")
511+
self.otel.assert_does_not_have_span_named(
512+
"generate_content gemini-2.0-flash"
513+
)

instrumentation-genai/opentelemetry-instrumentation-google-genai/tests/generate_content/streaming_base.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
import unittest
1616

17+
from opentelemetry.instrumentation import utils
18+
1719
from .base import TestCase
1820

1921

@@ -70,3 +72,16 @@ def test_includes_token_counts_in_span_aggregated_from_responses(self):
7072
span = self.otel.get_span_named("generate_content gemini-2.0-flash")
7173
self.assertEqual(span.attributes["gen_ai.usage.input_tokens"], 9)
7274
self.assertEqual(span.attributes["gen_ai.usage.output_tokens"], 12)
75+
76+
def test_suppress_instrumentation(self):
77+
self.configure_valid_response(text="Yep, it works!")
78+
with utils.suppress_instrumentation():
79+
responses = self.generate_content(
80+
model="gemini-2.0-flash", contents="Does this work?"
81+
)
82+
self.assertEqual(len(responses), 1)
83+
response = responses[0]
84+
self.assertEqual(response.text, "Yep, it works!")
85+
self.otel.assert_does_not_have_span_named(
86+
"generate_content gemini-2.0-flash"
87+
)

instrumentation-genai/opentelemetry-instrumentation-google-genai/tests/generate_content/test_tool_call_instrumentation.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import google.genai.types as genai_types
1818

19+
from opentelemetry.instrumentation import utils
1920
from opentelemetry.instrumentation._semconv import (
2021
_OpenTelemetrySemanticConventionStability,
2122
_OpenTelemetryStabilitySignalType,
@@ -440,3 +441,35 @@ def somefunction(x, y=2):
440441
generated_span.attributes,
441442
)
442443
self.tearDown()
444+
445+
def test_suppress_tool_call_instrumentation(self):
446+
calls = []
447+
448+
def handle(*args, **kwargs):
449+
calls.append((args, kwargs))
450+
return "some result"
451+
452+
def somefunction(somearg):
453+
print("somearg=%s", somearg)
454+
455+
self.mock_generate_content.side_effect = handle
456+
self.client.models.generate_content(
457+
model="some-model-name",
458+
contents="Some content",
459+
config={
460+
"tools": [somefunction],
461+
},
462+
)
463+
self.assertEqual(len(calls), 1)
464+
config = calls[0][1]["config"]
465+
tools = config.tools
466+
wrapped_somefunction = tools[0]
467+
468+
self.assertIsNone(
469+
self.otel.get_span_named("execute_tool somefunction")
470+
)
471+
472+
with utils.suppress_instrumentation():
473+
wrapped_somefunction("someparam")
474+
475+
self.otel.assert_does_not_have_span_named("execute_tool somefunction")

0 commit comments

Comments
 (0)