Skip to content

Commit 6c65c4a

Browse files
committed
Merge branch 'main' of github.com:open-telemetry/opentelemetry-python-contrib into middleware-always-set-status-code-on-duration-attrs
2 parents 49ed834 + 3d758a9 commit 6c65c4a

File tree

17 files changed

+118
-65
lines changed

17 files changed

+118
-65
lines changed

CHANGELOG.md

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

1010
- `opentelemetry-instrumentation-aws-lambda` Bugfix: AWS Lambda event source key incorrect for SNS in instrumentation library.
1111
([#2612](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2612))
12+
- `opentelemetry-instrumentation-system-metrics` Permit to use psutil 6.0+.
13+
([#2630](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2630))
1214
- `opentelemetry-instrumentation-asgi` Bugfix: Middleware did not set status code attribute on duration metrics for non-recording spans.
1315
([#2627](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2627))
1416

17+
1518
### Added
1619

1720
- `opentelemetry-instrumentation-pyramid` Record exceptions raised when serving a request
1821
([#2622](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2622))
1922
- `opentelemetry-sdk-extension-aws` Add AwsXrayLambdaPropagator
2023
([#2573](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2573))
24+
- `opentelemetry-instrumentation-confluent-kafka` Add support for version 2.4.0 of confluent_kafka
25+
([#2616](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2616))
2126

2227
### Breaking changes
2328

@@ -44,13 +49,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4449
([#2300](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2300))
4550
- Rename AwsLambdaInstrumentor span attributes `faas.id` to `cloud.resource_id`, `faas.execution` to `faas.invocation_id`
4651
([#2372](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2372))
47-
- Drop support for instrumenting elasticsearch client < 6`
52+
- Drop support for instrumenting elasticsearch client < 6
4853
([#2422](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2422))
4954
- `opentelemetry-instrumentation-wsgi` Add `http.method` to `span.name`
5055
([#2425](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2425))
5156
- `opentelemetry-instrumentation-flask` Add `http.method` to `span.name`
5257
([#2454](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2454))
53-
- ASGI, FastAPI, Starlette: provide both send and receive hooks with `scope` and `message` for internal spans ([#2546](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2546))
58+
- Record repeated HTTP headers in lists, rather than a comma separate strings for ASGI based web frameworks
59+
([#2361](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2361))
60+
- ASGI, FastAPI, Starlette: provide both send and receive hooks with `scope` and `message` for internal spans
61+
- ([#2546](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2546))
5462

5563
### Added
5664

docs-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ botocore~=1.0
2727
boto3~=1.0
2828
cassandra-driver~=3.25
2929
celery>=4.0
30-
confluent-kafka>= 1.8.2,<= 2.3.0
30+
confluent-kafka>= 1.8.2,<= 2.4.0
3131
elasticsearch>=6.0,<9.0
3232
flask~=2.0
3333
falcon~=2.0

instrumentation/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
| [opentelemetry-instrumentation-botocore](./opentelemetry-instrumentation-botocore) | botocore ~= 1.0 | No | experimental
1515
| [opentelemetry-instrumentation-cassandra](./opentelemetry-instrumentation-cassandra) | cassandra-driver ~= 3.25,scylla-driver ~= 3.25 | No | experimental
1616
| [opentelemetry-instrumentation-celery](./opentelemetry-instrumentation-celery) | celery >= 4.0, < 6.0 | No | experimental
17-
| [opentelemetry-instrumentation-confluent-kafka](./opentelemetry-instrumentation-confluent-kafka) | confluent-kafka >= 1.8.2, <= 2.3.0 | No | experimental
17+
| [opentelemetry-instrumentation-confluent-kafka](./opentelemetry-instrumentation-confluent-kafka) | confluent-kafka >= 1.8.2, <= 2.4.0 | No | experimental
1818
| [opentelemetry-instrumentation-dbapi](./opentelemetry-instrumentation-dbapi) | dbapi | No | experimental
1919
| [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | Yes | experimental
2020
| [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 6.0 | No | experimental

instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A
129129
130130
The name of the added span attribute will follow the format ``http.request.header.<header_name>`` where ``<header_name>``
131131
is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a
132-
single item list containing all the header values.
132+
list containing the header values.
133133
134134
For example:
135-
``http.request.header.custom_request_header = ["<value1>,<value2>"]``
135+
``http.request.header.custom_request_header = ["<value1>", "<value2>"]``
136136
137137
Response headers
138138
****************
@@ -163,10 +163,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A
163163
164164
The name of the added span attribute will follow the format ``http.response.header.<header_name>`` where ``<header_name>``
165165
is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a
166-
single item list containing all the header values.
166+
list containing the header values.
167167
168168
For example:
169-
``http.response.header.custom_response_header = ["<value1>,<value2>"]``
169+
``http.response.header.custom_response_header = ["<value1>", "<value2>"]``
170170
171171
Sanitizing headers
172172
******************
@@ -193,9 +193,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A
193193

194194
import typing
195195
import urllib
196+
from collections import defaultdict
196197
from functools import wraps
197198
from timeit import default_timer
198-
from typing import Any, Awaitable, Callable, Tuple
199+
from typing import Any, Awaitable, Callable, DefaultDict, Tuple
199200

200201
from asgiref.compatibility import guarantee_single_callable
201202

@@ -340,24 +341,19 @@ def collect_custom_headers_attributes(
340341
sanitize: SanitizeValue,
341342
header_regexes: list[str],
342343
normalize_names: Callable[[str], str],
343-
) -> dict[str, str]:
344+
) -> dict[str, list[str]]:
344345
"""
345346
Returns custom HTTP request or response headers to be added into SERVER span as span attributes.
346347
347348
Refer specifications:
348349
- https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/http.md#http-request-and-response-headers
349350
"""
350-
# Decode headers before processing.
351-
headers: dict[str, str] = {}
351+
headers: DefaultDict[str, list[str]] = defaultdict(list)
352352
raw_headers = scope_or_response_message.get("headers")
353353
if raw_headers:
354-
for _key, _value in raw_headers:
355-
key = _key.decode().lower()
356-
value = _value.decode()
357-
if key in headers:
358-
headers[key] += f",{value}"
359-
else:
360-
headers[key] = value
354+
for key, value in raw_headers:
355+
# Decode headers before processing.
356+
headers[key.decode()].append(value.decode())
361357

362358
return sanitize.sanitize_header_values(
363359
headers,
@@ -707,7 +703,9 @@ async def otel_send(message: dict[str, Any]):
707703
elif message["type"] == "websocket.send":
708704
status_code = 200
709705
if status_code:
710-
duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = status_code
706+
duration_attrs[SpanAttributes.HTTP_STATUS_CODE] = (
707+
status_code
708+
)
711709

712710
if send_span.is_recording():
713711
if message["type"] == "http.response.start":

instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_custom_headers.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ def test_http_repeat_request_headers_in_span_attributes(self):
152152
span_list = self.exporter.get_finished_spans()
153153
expected = {
154154
"http.request.header.custom_test_header_1": (
155-
"test-header-value-1,test-header-value-2",
155+
"test-header-value-1",
156+
"test-header-value-2",
156157
),
157158
}
158159
span = next(span for span in span_list if span.kind == SpanKind.SERVER)
@@ -225,7 +226,8 @@ def test_http_repeat_response_headers_in_span_attributes(self):
225226
span_list = self.exporter.get_finished_spans()
226227
expected = {
227228
"http.response.header.custom_test_header_1": (
228-
"test-header-value-1,test-header-value-2",
229+
"test-header-value-1",
230+
"test-header-value-2",
229231
),
230232
}
231233
span = next(span for span in span_list if span.kind == SpanKind.SERVER)

instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_middleware.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,9 @@ def test_asgi_not_recording(self):
327327
mock_span = mock.Mock()
328328
mock_span.is_recording.return_value = False
329329
mock_tracer.start_as_current_span.return_value = mock_span
330-
mock_tracer.start_as_current_span.return_value.__enter__ = mock.Mock(return_value=mock_span)
330+
mock_tracer.start_as_current_span.return_value.__enter__ = mock.Mock(
331+
return_value=mock_span
332+
)
331333
mock_tracer.start_as_current_span.return_value.__exit__ = mock_span
332334
with mock.patch("opentelemetry.trace.get_tracer") as tracer:
333335
tracer.return_value = mock_tracer
@@ -804,7 +806,9 @@ def test_basic_metric_success_nonrecording_span(self):
804806
mock_span = mock.Mock()
805807
mock_span.is_recording.return_value = False
806808
mock_tracer.start_as_current_span.return_value = mock_span
807-
mock_tracer.start_as_current_span.return_value.__enter__ = mock.Mock(return_value=mock_span)
809+
mock_tracer.start_as_current_span.return_value.__enter__ = mock.Mock(
810+
return_value=mock_span
811+
)
808812
mock_tracer.start_as_current_span.return_value.__exit__ = mock_span
809813
with mock.patch("opentelemetry.trace.get_tracer") as tracer:
810814
tracer.return_value = mock_tracer
@@ -843,7 +847,9 @@ def test_basic_metric_success_nonrecording_span(self):
843847
self.assertAlmostEqual(
844848
duration, point.sum, delta=5
845849
)
846-
elif metric.name == "http.server.response.size":
850+
elif (
851+
metric.name == "http.server.response.size"
852+
):
847853
self.assertEqual(1024, point.sum)
848854
elif metric.name == "http.server.request.size":
849855
self.assertEqual(128, point.sum)

instrumentation/opentelemetry-instrumentation-confluent-kafka/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ dependencies = [
3232

3333
[project.optional-dependencies]
3434
instruments = [
35-
"confluent-kafka >= 1.8.2, <= 2.3.0",
35+
"confluent-kafka >= 1.8.2, <= 2.4.0",
3636
]
3737

3838
[project.entry-points.opentelemetry_instrumentor]

instrumentation/opentelemetry-instrumentation-confluent-kafka/src/opentelemetry/instrumentation/confluent_kafka/package.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# limitations under the License.
1414

1515

16-
_instruments = ("confluent-kafka >= 1.8.2, <= 2.3.0",)
16+
_instruments = ("confluent-kafka >= 1.8.2, <= 2.4.0",)

instrumentation/opentelemetry-instrumentation-confluent-kafka/test-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
asgiref==3.7.2
2-
confluent-kafka==2.3.0
2+
confluent-kafka==2.4.0
33
Deprecated==1.2.14
44
importlib-metadata==6.11.0
55
iniconfig==2.0.0

instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A
115115
single item list containing all the header values.
116116
117117
For example:
118-
``http.request.header.custom_request_header = ["<value1>,<value2>"]``
118+
``http.request.header.custom_request_header = ["<value1>", "<value2>"]``
119119
120120
Response headers
121121
****************
@@ -146,10 +146,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A
146146
147147
The name of the added span attribute will follow the format ``http.response.header.<header_name>`` where ``<header_name>``
148148
is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a
149-
single item list containing all the header values.
149+
list containing the header values.
150150
151151
For example:
152-
``http.response.header.custom_response_header = ["<value1>,<value2>"]``
152+
``http.response.header.custom_response_header = ["<value1>", "<value2>"]``
153153
154154
Sanitizing headers
155155
******************

0 commit comments

Comments
 (0)