Skip to content

Commit c416c5f

Browse files
committed
Address comments
1 parent 46ebc99 commit c416c5f

File tree

6 files changed

+35
-47
lines changed

6 files changed

+35
-47
lines changed

instrumentation-genai/opentelemetry-instrumentation-google-genai/CHANGELOG.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10-
- Minor change to check LRU cache in Completion Hook before acquiring semaphore/thread ([#3907](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3907)).
11-
12-
- Fixes bugs
10+
- Ensure log event is written and completion hook is called even when model call results in exception. Put new
11+
log event (` gen_ai.client.inference.operation.details`) behind the flag `OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental`.
12+
Ensure same sem conv attributes are on the log and span. Fix an issue where the instrumentation would crash when a pydantic.BaseModel class was passed as the response schema ([#3905](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3905)).
1313

1414
## Version 0.4b0 (2025-10-16)
1515

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

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def _to_dict(value: object):
170170
return json.loads(json.dumps(value))
171171

172172

173-
def create_request_attributes(
173+
def _create_request_attributes(
174174
config: Optional[GenerateContentConfigOrDict],
175175
is_experimental_mode: bool,
176176
allow_list: AllowList,
@@ -442,12 +442,14 @@ def _maybe_log_completion_details(
442442
self,
443443
request_attributes: dict[str, Any],
444444
final_attributes: dict[str, Any],
445-
is_experimental_mode: bool,
446445
request: Union[ContentListUnion, ContentListUnionDict],
447446
candidates: list[Candidate],
448447
config: Optional[GenerateContentConfigOrDict] = None,
449448
):
450-
if not is_experimental_mode:
449+
if (
450+
self.sem_conv_opt_in_mode
451+
!= _StabilityMode.GEN_AI_LATEST_EXPERIMENTAL
452+
):
451453
return
452454
system_instructions = []
453455
if system_content := _config_to_system_instruction(config):
@@ -716,7 +718,7 @@ def instrumented_generate_content(
716718
helper.sem_conv_opt_in_mode
717719
== _StabilityMode.GEN_AI_LATEST_EXPERIMENTAL
718720
)
719-
request_attributes = create_request_attributes(
721+
request_attributes = _create_request_attributes(
720722
config,
721723
is_experimental_mode,
722724
helper._generate_content_config_key_allowlist,
@@ -755,7 +757,6 @@ def instrumented_generate_content(
755757
helper._maybe_log_completion_details(
756758
request_attributes,
757759
final_attributes,
758-
is_experimental_mode,
759760
contents,
760761
candidates,
761762
config,
@@ -795,7 +796,7 @@ def instrumented_generate_content_stream(
795796
helper.sem_conv_opt_in_mode
796797
== _StabilityMode.GEN_AI_LATEST_EXPERIMENTAL
797798
)
798-
request_attributes = create_request_attributes(
799+
request_attributes = _create_request_attributes(
799800
config,
800801
is_experimental_mode,
801802
helper._generate_content_config_key_allowlist,
@@ -834,7 +835,6 @@ def instrumented_generate_content_stream(
834835
helper._maybe_log_completion_details(
835836
request_attributes,
836837
final_attributes,
837-
is_experimental_mode,
838838
contents,
839839
candidates,
840840
config,
@@ -873,7 +873,7 @@ async def instrumented_generate_content(
873873
helper.sem_conv_opt_in_mode
874874
== _StabilityMode.GEN_AI_LATEST_EXPERIMENTAL
875875
)
876-
request_attributes = create_request_attributes(
876+
request_attributes = _create_request_attributes(
877877
config,
878878
is_experimental_mode,
879879
helper._generate_content_config_key_allowlist,
@@ -912,7 +912,6 @@ async def instrumented_generate_content(
912912
helper._maybe_log_completion_details(
913913
request_attributes,
914914
final_attributes,
915-
is_experimental_mode,
916915
contents,
917916
candidates,
918917
config,
@@ -952,7 +951,7 @@ async def instrumented_generate_content_stream(
952951
helper.sem_conv_opt_in_mode
953952
== _StabilityMode.GEN_AI_LATEST_EXPERIMENTAL
954953
)
955-
request_attributes = create_request_attributes(
954+
request_attributes = _create_request_attributes(
956955
config,
957956
is_experimental_mode,
958957
helper._generate_content_config_key_allowlist,
@@ -984,7 +983,6 @@ async def instrumented_generate_content_stream(
984983
helper._maybe_log_completion_details(
985984
request_attributes,
986985
final_attributes,
987-
is_experimental_mode,
988986
contents,
989987
[],
990988
config,
@@ -1015,7 +1013,6 @@ async def _response_async_generator_wrapper():
10151013
helper._maybe_log_completion_details(
10161014
request_attributes,
10171015
final_attributes,
1018-
is_experimental_mode,
10191016
contents,
10201017
candidates,
10211018
config,

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

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,6 @@ def configure_valid_response(self, **kwargs):
9797
def configure_exception(self, e, **kwargs):
9898
self._create_and_install_mocks(e)
9999

100-
def _create_and_install_mocks_with(self):
101-
if self._generate_content_mock is not None:
102-
return
103-
self.reset_client()
104-
self.reset_instrumentation()
105-
self._generate_content_mock = self._create_nonstream_mock()
106-
self._generate_content_stream_mock = self._create_stream_mock()
107-
self._install_mocks()
108-
109100
def _create_and_install_mocks(self, e=None):
110101
if self._generate_content_mock is not None:
111102
return
@@ -126,10 +117,7 @@ def _default_impl(*args, **kwargs):
126117
self._response_index += 1
127118
return result
128119

129-
if not e:
130-
mock.side_effect = _default_impl
131-
else:
132-
mock.side_effect = e
120+
mock.side_effect = e or _default_impl
133121
return mock
134122

135123
def _create_stream_mock(self, e=None):

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

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import unittest
1717
from unittest.mock import patch
1818

19+
import pytest
1920
from google.genai.types import GenerateContentConfig
2021
from pydantic import BaseModel, Field
2122

@@ -111,28 +112,27 @@ def test_span_and_event_still_written_when_response_is_exception(self):
111112
with patched_environ:
112113
_OpenTelemetrySemanticConventionStability._initialized = False
113114
_OpenTelemetrySemanticConventionStability._initialize()
114-
try:
115+
with pytest.raises(ValueError):
115116
self.generate_content(
116117
model="gemini-2.0-flash", contents="Does this work?"
117118
)
118-
except ValueError:
119-
self.otel.assert_has_span_named(
120-
"generate_content gemini-2.0-flash"
121-
)
122-
span = self.otel.get_span_named(
123-
"generate_content gemini-2.0-flash"
124-
)
125-
self.otel.assert_has_event_named(
126-
"gen_ai.client.inference.operation.details"
127-
)
128-
event = self.otel.get_event_named(
129-
"gen_ai.client.inference.operation.details"
130-
)
131-
assert (
132-
span.attributes["error.type"]
133-
== event.attributes["error.type"]
134-
== "ValueError"
135-
)
119+
self.otel.assert_has_span_named(
120+
"generate_content gemini-2.0-flash"
121+
)
122+
span = self.otel.get_span_named(
123+
"generate_content gemini-2.0-flash"
124+
)
125+
self.otel.assert_has_event_named(
126+
"gen_ai.client.inference.operation.details"
127+
)
128+
event = self.otel.get_event_named(
129+
"gen_ai.client.inference.operation.details"
130+
)
131+
assert (
132+
span.attributes["error.type"]
133+
== event.attributes["error.type"]
134+
== "ValueError"
135+
)
136136

137137
def test_generated_span_has_correct_function_name(self):
138138
self.configure_valid_response(text="Yep, it works!")

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ pythonVersion = "3.9"
198198
reportPrivateUsage = false # Ignore private attributes added by instrumentation packages.
199199
# Add progressively instrumentation packages here.
200200
include = [
201+
"instrumentation-genai/opentelemetry-instrumentation-google-genai",
201202
"instrumentation/opentelemetry-instrumentation-aiokafka",
202203
"instrumentation/opentelemetry-instrumentation-asyncclick",
203204
"instrumentation/opentelemetry-instrumentation-threading",

util/opentelemetry-util-genai/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
- Minor change to check LRU cache in Completion Hook before acquiring semaphore/thread ([#3907](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3907)).
11+
1012
## Version 0.2b0 (2025-10-14)
1113

1214
- Add jsonlines support to fsspec uploader

0 commit comments

Comments
 (0)