Skip to content

Commit de799bf

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

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,
@@ -708,6 +709,11 @@ def instrumented_generate_content(
708709
config: Optional[GenerateContentConfigOrDict] = None,
709710
**kwargs: Any,
710711
) -> GenerateContentResponse:
712+
if not is_instrumentation_enabled():
713+
return wrapped_func(
714+
self, model=model, contents=contents, config=config, **kwargs
715+
)
716+
711717
candidates = []
712718
helper = _GenerateContentInstrumentationHelper(
713719
self,
@@ -783,6 +789,13 @@ def instrumented_generate_content_stream(
783789
config: Optional[GenerateContentConfigOrDict] = None,
784790
**kwargs: Any,
785791
) -> Iterator[GenerateContentResponse]:
792+
if not is_instrumentation_enabled():
793+
for resp in wrapped_func(
794+
self, model=model, contents=contents, config=config, **kwargs
795+
):
796+
yield resp
797+
return
798+
786799
candidates: list[Candidate] = []
787800
helper = _GenerateContentInstrumentationHelper(
788801
self,
@@ -858,6 +871,10 @@ async def instrumented_generate_content(
858871
config: Optional[GenerateContentConfigOrDict] = None,
859872
**kwargs: Any,
860873
) -> GenerateContentResponse:
874+
if not is_instrumentation_enabled():
875+
return await wrapped_func(
876+
self, model=model, contents=contents, config=config, **kwargs
877+
)
861878
helper = _GenerateContentInstrumentationHelper(
862879
self,
863880
otel_wrapper,
@@ -933,6 +950,11 @@ async def instrumented_generate_content_stream(
933950
config: Optional[GenerateContentConfigOrDict] = None,
934951
**kwargs: Any,
935952
) -> Awaitable[AsyncIterator[GenerateContentResponse]]: # type: ignore
953+
if not is_instrumentation_enabled():
954+
return await wrapped_func(
955+
self, model=model, contents=contents, config=config, **kwargs
956+
)
957+
936958
helper = _GenerateContentInstrumentationHelper(
937959
self,
938960
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
2121
from pydantic import BaseModel, Field
2222

23+
from opentelemetry.instrumentation import utils
2324
from opentelemetry.instrumentation._semconv import (
2425
_OpenTelemetrySemanticConventionStability,
2526
_OpenTelemetryStabilitySignalType,
@@ -448,3 +449,14 @@ def test_records_metrics_data(self):
448449
self.otel.assert_has_metrics_data_named(
449450
"gen_ai.client.operation.duration"
450451
)
452+
453+
def test_suppress_instrumentation(self):
454+
self.configure_valid_response(text="Yep, it works!")
455+
with utils.suppress_instrumentation():
456+
response = self.generate_content(
457+
model="gemini-2.0-flash", contents="Does this work?"
458+
)
459+
self.assertEqual(response.text, "Yep, it works!")
460+
self.otel.assert_does_not_have_span_named(
461+
"generate_content gemini-2.0-flash"
462+
)

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)