Skip to content

Commit 48c26ef

Browse files
authored
Merge branch 'main' into openai-not-given
2 parents f7dea12 + a2ca6af commit 48c26ef

File tree

43 files changed

+1718
-262
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1718
-262
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111
1212
## Unreleased
1313

14+
- `opentelemetry-instrumentation-requests`, `opentelemetry-instrumentation-wsgi`, `opentelemetry-instrumentation-asgi` Detect synthetic sources on requests, ASGI, and WSGI.
15+
([#3674](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3674))
16+
1417
### Added
1518

1619
- `opentelemetry-instrumentation-aiohttp-client`: add support for url exclusions via `OTEL_PYTHON_EXCLUDED_URLS` / `OTEL_PYTHON_AIOHTTP_CLIENT_EXCLUDED_URLS`
@@ -27,6 +30,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2730
([#3884](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3884))
2831
- `opentelemetry-instrumentation-aiohttp-server`: add support for custom header captures via `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST` and `OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE`
2932
([#3916](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3916))
33+
- `opentelemetry-instrumentation-redis`: add support for `suppress_instrumentation` context manager for both sync and async Redis clients and pipelines
34+
- `opentelemetry-instrumentation-django`: improve docs for response_hook with examples of providing attributes from middlewares
35+
([#3923](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3923))
36+
- Update for Log SDK breaking changes. Rename InMemoryLogExporter to InMemoryLogRecordExporter in several tests
37+
([#3850](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3589))
3038

3139
### Fixed
3240

@@ -50,8 +58,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5058
([#3904](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3904))
5159
- build: bump ruff to 0.14.1
5260
([#3842](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3842))
61+
- `opentelemetry-instrumentation-redis`: Add default span name for pipeline operations
62+
([#3941](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3941))
5363
- `opentelemetry-instrumentation-pymongo`: Fix invalid mongodb collection attribute type
5464
([#3942](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3942))
65+
- `opentelemetry-instrumentation-aiohttp-client`: Fix metric attribute leakage
66+
([#3936](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3936))
67+
- `opentelemetry-instrumentation-aiohttp-client`: Update instrumentor to respect suppressing http instrumentation
68+
([#3957](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3957))
5569

5670
## Version 1.38.0/0.59b0 (2025-10-16)
5771

@@ -65,6 +79,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6579
([#3796](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3796))
6680
- `opentelemetry-instrumentation-fastapi`: Fix handling of APIRoute subclasses
6781
([#3681](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3681))
82+
- `opentelemetry-instrumentation-flask`: Fix exemplars generation for `http.server.request.duration` and `http.server.duration` metrics
83+
([#3912](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3912))
6884

6985
### Added
7086

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ For more information about the maintainer role, see the [community repository](h
124124
- [Dylan Russell](https://github.com/dylanrussell), Google
125125
- [Emídio Neto](https://github.com/emdneto), PicPay
126126
- [Jeremy Voss](https://github.com/jeremydvoss), Microsoft
127+
- [Liudmila Molkova](https://github.com/lmolkova), Grafana Labs
127128
- [Owais Lone](https://github.com/owais), Splunk
128129
- [Pablo Collins](https://github.com/pmcollins), Splunk
129130
- [Sanket Mehta](https://github.com/sanketmehta28), Cisco

instrumentation-genai/opentelemetry-instrumentation-google-genai/tests/common/otel_mocker.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,21 @@
2222
)
2323
from opentelemetry.metrics import get_meter_provider, set_meter_provider
2424
from opentelemetry.sdk._logs import LoggerProvider
25-
from opentelemetry.sdk._logs.export import (
26-
InMemoryLogExporter,
27-
SimpleLogRecordProcessor,
28-
)
25+
26+
# Backward compatibility for InMemoryLogExporter -> InMemoryLogRecordExporter rename
27+
try:
28+
from opentelemetry.sdk._logs.export import ( # pylint: disable=no-name-in-module
29+
InMemoryLogRecordExporter,
30+
SimpleLogRecordProcessor,
31+
)
32+
except ImportError:
33+
# Fallback to old name for compatibility with older SDK versions
34+
from opentelemetry.sdk._logs.export import (
35+
InMemoryLogExporter as InMemoryLogRecordExporter,
36+
)
37+
from opentelemetry.sdk._logs.export import (
38+
SimpleLogRecordProcessor,
39+
)
2940
from opentelemetry.sdk.metrics import MeterProvider
3041
from opentelemetry.sdk.metrics._internal.export import InMemoryMetricReader
3142
from opentelemetry.sdk.trace import TracerProvider
@@ -114,7 +125,7 @@ def data(self):
114125
class OTelMocker:
115126
def __init__(self):
116127
self._snapshot = None
117-
self._logs = InMemoryLogExporter()
128+
self._logs = InMemoryLogRecordExporter()
118129
self._traces = InMemorySpanExporter()
119130
self._metrics = InMemoryMetricReader()
120131
self._spans = []

instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md

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

88
## Unreleased
99

10+
- Fix service tier attribute names: use `GEN_AI_OPENAI_REQUEST_SERVICE_TIER` for request
11+
attributes and `GEN_AI_OPENAI_RESPONSE_SERVICE_TIER` for response attributes.
12+
([#3920](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/3920))
1013
- Added support for OpenAI embeddings instrumentation
1114
([#3461](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3461))
1215
- Record prompt and completion events regardless of span sampling decision.

instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/patch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ def _set_response_attributes(
370370
if getattr(result, "service_tier", None):
371371
set_span_attribute(
372372
span,
373-
GenAIAttributes.GEN_AI_OPENAI_REQUEST_SERVICE_TIER,
373+
GenAIAttributes.GEN_AI_OPENAI_RESPONSE_SERVICE_TIER,
374374
result.service_tier,
375375
)
376376

instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/utils.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,13 @@ def get_llm_request_attributes(
236236
GenAIAttributes.GEN_AI_OPENAI_REQUEST_RESPONSE_FORMAT
237237
] = response_format
238238

239+
# service_tier can be passed directly or in extra_body (in SDK 1.26.0 it's via extra_body)
239240
service_tier = kwargs.get("service_tier")
240-
attributes[GenAIAttributes.GEN_AI_OPENAI_RESPONSE_SERVICE_TIER] = (
241+
if service_tier is None:
242+
extra_body = kwargs.get("extra_body")
243+
if isinstance(extra_body, Mapping):
244+
service_tier = extra_body.get("service_tier")
245+
attributes[GenAIAttributes.GEN_AI_OPENAI_REQUEST_SERVICE_TIER] = (
241246
service_tier if service_tier != "auto" else None
242247
)
243248

instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/conftest.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,21 @@
1212
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT,
1313
)
1414
from opentelemetry.sdk._logs import LoggerProvider
15-
from opentelemetry.sdk._logs.export import (
16-
InMemoryLogExporter,
17-
SimpleLogRecordProcessor,
18-
)
15+
16+
# Backward compatibility for InMemoryLogExporter -> InMemoryLogRecordExporter rename
17+
try:
18+
from opentelemetry.sdk._logs.export import ( # pylint: disable=no-name-in-module
19+
InMemoryLogRecordExporter,
20+
SimpleLogRecordProcessor,
21+
)
22+
except ImportError:
23+
# Fallback to old name for compatibility with older SDK versions
24+
from opentelemetry.sdk._logs.export import (
25+
InMemoryLogExporter as InMemoryLogRecordExporter,
26+
)
27+
from opentelemetry.sdk._logs.export import (
28+
SimpleLogRecordProcessor,
29+
)
1930
from opentelemetry.sdk.metrics import (
2031
MeterProvider,
2132
)
@@ -38,7 +49,7 @@ def fixture_span_exporter():
3849

3950
@pytest.fixture(scope="function", name="log_exporter")
4051
def fixture_log_exporter():
41-
exporter = InMemoryLogExporter()
52+
exporter = InMemoryLogRecordExporter()
4253
yield exporter
4354

4455

instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_async_chat_completions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ async def test_async_chat_completion_extra_params(
183183
response.model,
184184
response.usage.prompt_tokens,
185185
response.usage.completion_tokens,
186+
request_service_tier="default",
187+
response_service_tier=getattr(response, "service_tier", None),
186188
)
187189
assert (
188190
spans[0].attributes[GenAIAttributes.GEN_AI_OPENAI_REQUEST_SEED] == 42

instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_chat_completions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ def test_chat_completion_extra_params(
269269
response.model,
270270
response.usage.prompt_tokens,
271271
response.usage.completion_tokens,
272+
request_service_tier="default",
273+
response_service_tier=getattr(response, "service_tier", None),
272274
)
273275
assert (
274276
spans[0].attributes[GenAIAttributes.GEN_AI_OPENAI_REQUEST_SEED] == 42

instrumentation-genai/opentelemetry-instrumentation-openai-v2/tests/test_utils.py

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
)
2626

2727

28+
def _assert_optional_attribute(span, attribute_name, expected_value):
29+
"""Helper to assert optional span attributes."""
30+
if expected_value is not None:
31+
assert expected_value == span.attributes[attribute_name]
32+
else:
33+
assert attribute_name not in span.attributes
34+
35+
2836
def assert_all_attributes(
2937
span: ReadableSpan,
3038
request_model: str,
@@ -35,6 +43,8 @@ def assert_all_attributes(
3543
operation_name: str = "chat",
3644
server_address: str = "api.openai.com",
3745
server_port: int = 443,
46+
request_service_tier: Optional[str] = None,
47+
response_service_tier: Optional[str] = None,
3848
):
3949
assert span.name == f"{operation_name} {request_model}"
4050
assert (
@@ -49,44 +59,35 @@ def assert_all_attributes(
4959
request_model == span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL]
5060
)
5161

52-
if response_model:
53-
assert (
54-
response_model
55-
== span.attributes[GenAIAttributes.GEN_AI_RESPONSE_MODEL]
56-
)
57-
else:
58-
assert GenAIAttributes.GEN_AI_RESPONSE_MODEL not in span.attributes
59-
60-
if response_id:
61-
assert (
62-
response_id == span.attributes[GenAIAttributes.GEN_AI_RESPONSE_ID]
63-
)
64-
else:
65-
assert GenAIAttributes.GEN_AI_RESPONSE_ID not in span.attributes
66-
67-
if input_tokens:
68-
assert (
69-
input_tokens
70-
== span.attributes[GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS]
71-
)
72-
else:
73-
assert GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS not in span.attributes
74-
75-
if output_tokens:
76-
assert (
77-
output_tokens
78-
== span.attributes[GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS]
79-
)
80-
else:
81-
assert (
82-
GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS not in span.attributes
83-
)
62+
_assert_optional_attribute(
63+
span, GenAIAttributes.GEN_AI_RESPONSE_MODEL, response_model
64+
)
65+
_assert_optional_attribute(
66+
span, GenAIAttributes.GEN_AI_RESPONSE_ID, response_id
67+
)
68+
_assert_optional_attribute(
69+
span, GenAIAttributes.GEN_AI_USAGE_INPUT_TOKENS, input_tokens
70+
)
71+
_assert_optional_attribute(
72+
span, GenAIAttributes.GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens
73+
)
8474

8575
assert server_address == span.attributes[ServerAttributes.SERVER_ADDRESS]
8676

8777
if server_port != 443 and server_port > 0:
8878
assert server_port == span.attributes[ServerAttributes.SERVER_PORT]
8979

80+
_assert_optional_attribute(
81+
span,
82+
GenAIAttributes.GEN_AI_OPENAI_REQUEST_SERVICE_TIER,
83+
request_service_tier,
84+
)
85+
_assert_optional_attribute(
86+
span,
87+
GenAIAttributes.GEN_AI_OPENAI_RESPONSE_SERVICE_TIER,
88+
response_service_tier,
89+
)
90+
9091

9192
def assert_log_parent(log, span):
9293
"""Assert that the log record has the correct parent span context"""

0 commit comments

Comments
 (0)