diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a35e342df..e61760b102 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Breaking Changes + +- `opentelemetry-util-http` Don't normalize headers with "hyphen -> underscore" + ([#3104](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3104)) + ### Added - `opentelemetry-instrumentation-confluent-kafka` Add support for confluent-kafka <=2.7.0 @@ -49,7 +54,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `opentelemetry-instrumentation-dbapi` including sqlcomment in `db.statement` span attribute value is now opt-in ([#3115](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3115)) - ## Version 1.29.0/0.50b0 (2024-12-11) ### Added diff --git a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py index b060095160..76f1b51230 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/src/opentelemetry/instrumentation/asgi/__init__.py @@ -128,11 +128,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=".*" The name of the added span attribute will follow the format ``http.request.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -list containing the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a list containing the header values. For example: -``http.request.header.custom_request_header = ["", ""]`` +``http.request.header.custom-request-header = ["", ""]`` Response headers **************** @@ -162,11 +161,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=".*" The name of the added span attribute will follow the format ``http.response.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -list containing the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a list containing the header values. For example: -``http.response.header.custom_response_header = ["", ""]`` +``http.response.header.custom-response-header = ["", ""]`` Sanitizing headers ****************** diff --git a/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_custom_headers.py b/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_custom_headers.py index 1b191e30e7..ae8c9cfba1 100644 --- a/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_custom_headers.py +++ b/instrumentation/opentelemetry-instrumentation-asgi/tests/test_asgi_custom_headers.py @@ -153,19 +153,19 @@ async def test_http_custom_request_headers_in_span_attributes(self): await self.get_all_output() span_list = self.exporter.get_finished_spans() expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.non_utf8_header": ("Moto Z²",), - "http.request.header.moto_z²_non_utf8_header_key": ("Moto Z²",), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.non-utf8-header": ("Moto Z²",), + "http.request.header.moto-z²-non-utf8-header-key": ("Moto Z²",), + "http.request.header.my-secret-header": ("[REDACTED]",), } for span in span_list: if span.kind == SpanKind.SERVER: @@ -183,7 +183,7 @@ async def test_http_repeat_request_headers_in_span_attributes(self): await self.get_all_output() span_list = self.exporter.get_finished_spans() expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", "test-header-value-2", ), @@ -202,12 +202,12 @@ async def test_http_custom_request_headers_not_in_span_attributes(self): await self.get_all_output() span_list = self.exporter.get_finished_spans() expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), } not_expected = { - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), } @@ -228,21 +228,21 @@ async def test_http_custom_response_headers_in_span_attributes(self): await self.get_all_output() span_list = self.exporter.get_finished_spans() expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", ), - "http.response.header.custom_test_header_2": ( + "http.response.header.custom-test-header-2": ( "test-header-value-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), - "http.response.header.non_utf8_header": ("Moto Z²",), - "http.response.header.moto_z²_non_utf8_header_key": ("Moto Z²",), + "http.response.header.my-secret-header": ("[REDACTED]",), + "http.response.header.non-utf8-header": ("Moto Z²",), + "http.response.header.moto-z²-non-utf8-header-key": ("Moto Z²",), } for span in span_list: if span.kind == SpanKind.SERVER: @@ -259,7 +259,7 @@ async def test_http_repeat_response_headers_in_span_attributes(self): await self.get_all_output() span_list = self.exporter.get_finished_spans() expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", "test-header-value-2", ), @@ -278,7 +278,7 @@ async def test_http_custom_response_headers_not_in_span_attributes(self): await self.get_all_output() span_list = self.exporter.get_finished_spans() not_expected = { - "http.response.header.custom_test_header_3": ( + "http.response.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -312,17 +312,17 @@ async def test_websocket_custom_request_headers_in_span_attributes(self): await self.get_all_output() span_list = self.exporter.get_finished_spans() expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } for span in span_list: if span.kind == SpanKind.SERVER: @@ -352,7 +352,7 @@ async def test_websocket_custom_request_headers_not_in_span_attributes( await self.get_all_output() span_list = self.exporter.get_finished_spans() not_expected = { - "http.request.header.custom_test_header_3": ( + "http.request.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -384,19 +384,19 @@ async def test_websocket_custom_response_headers_in_span_attributes(self): await self.get_all_output() span_list = self.exporter.get_finished_spans() expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", ), - "http.response.header.custom_test_header_2": ( + "http.response.header.custom-test-header-2": ( "test-header-value-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } for span in span_list: if span.kind == SpanKind.SERVER: @@ -427,7 +427,7 @@ async def test_websocket_custom_response_headers_not_in_span_attributes( await self.get_all_output() span_list = self.exporter.get_finished_spans() not_expected = { - "http.response.header.custom_test_header_3": ( + "http.response.header.custom-test-header-3": ( "test-header-value-3", ), } diff --git a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py index e5851a17c2..e5fe2a0a42 100644 --- a/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-django/src/opentelemetry/instrumentation/django/__init__.py @@ -173,11 +173,10 @@ def response_hook(span, request, response): export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=".*" The name of the added span attribute will follow the format ``http.request.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -single item list containing all the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing all the header values. For example: -``http.request.header.custom_request_header = [","]`` +``http.request.header.custom-request-header = [","]`` Response headers **************** @@ -207,11 +206,11 @@ def response_hook(span, request, response): export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=".*" The name of the added span attribute will follow the format ``http.response.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing all the header values. For example: -``http.response.header.custom_response_header = [","]`` +``http.response.header.custom-response-header = [","]`` Sanitizing headers ****************** diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py index 1c85935892..aec7616075 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware.py @@ -1007,17 +1007,17 @@ def tearDownClass(cls): def test_http_custom_request_headers_in_span_attributes(self): expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } Client( HTTP_CUSTOM_TEST_HEADER_1="test-header-value-1", @@ -1036,7 +1036,7 @@ def test_http_custom_request_headers_in_span_attributes(self): def test_http_custom_request_headers_not_in_span_attributes(self): not_expected = { - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), } @@ -1052,19 +1052,19 @@ def test_http_custom_request_headers_not_in_span_attributes(self): def test_http_custom_response_headers_in_span_attributes(self): expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", ), - "http.response.header.custom_test_header_2": ( + "http.response.header.custom-test-header-2": ( "test-header-value-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } Client().get("/traced_custom_header/") spans = self.exporter.get_finished_spans() @@ -1077,7 +1077,7 @@ def test_http_custom_response_headers_in_span_attributes(self): def test_http_custom_response_headers_not_in_span_attributes(self): not_expected = { - "http.response.header.custom_test_header_3": ( + "http.response.header.custom-test-header-3": ( "test-header-value-3", ), } diff --git a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py index d06c9c635c..460aa24f3e 100644 --- a/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py +++ b/instrumentation/opentelemetry-instrumentation-django/tests/test_middleware_asgi.py @@ -735,17 +735,17 @@ def tearDownClass(cls): async def test_http_custom_request_headers_in_span_attributes(self): expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } await self.async_client.get( "/traced/", @@ -767,7 +767,7 @@ async def test_http_custom_request_headers_in_span_attributes(self): async def test_http_custom_request_headers_not_in_span_attributes(self): not_expected = { - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), } @@ -788,19 +788,19 @@ async def test_http_custom_request_headers_not_in_span_attributes(self): async def test_http_custom_response_headers_in_span_attributes(self): expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", ), - "http.response.header.custom_test_header_2": ( + "http.response.header.custom-test-header-2": ( "test-header-value-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } await self.async_client.get("/traced_custom_header/") spans = self.exporter.get_finished_spans() @@ -813,7 +813,7 @@ async def test_http_custom_response_headers_in_span_attributes(self): async def test_http_custom_response_headers_not_in_span_attributes(self): not_expected = { - "http.response.header.custom_test_header_3": ( + "http.response.header.custom-test-header-3": ( "test-header-value-3", ), } diff --git a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py index 1037f98f5f..53e8c01c96 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/src/opentelemetry/instrumentation/falcon/__init__.py @@ -121,11 +121,10 @@ def response_hook(span, req, resp): export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=".*" The name of the added span attribute will follow the format ``http.request.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -single item list containing all the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing all the header values. For example: -``http.request.header.custom_request_header = [","]`` +``http.request.header.custom-request-header = [","]`` Response headers **************** @@ -155,11 +154,10 @@ def response_hook(span, req, resp): export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=".*" The name of the added span attribute will follow the format ``http.response.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -single item list containing all the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing all the header values. For example: -``http.response.header.custom_response_header = [","]`` +``http.response.header.custom-response-header = [","]`` Sanitizing headers ****************** diff --git a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py index f940deb34e..d3425464f5 100644 --- a/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py +++ b/instrumentation/opentelemetry-instrumentation-falcon/tests/test_falcon.py @@ -489,18 +489,18 @@ def test_custom_request_header_added_in_server_span(self): assert span.status.is_ok expected = { - "http.request.header.custom_test_header_1": ("Test Value 1",), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-1": ("Test Value 1",), + "http.request.header.custom-test-header-2": ( "TestValue2,TestValue3", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } not_expected = { - "http.request.header.custom_test_header_3": ("TestValue4",), + "http.request.header.custom-test-header-3": ("TestValue4",), } self.assertEqual(span.kind, trace.SpanKind.SERVER) @@ -524,17 +524,17 @@ def test_custom_request_header_not_added_in_internal_span(self): span = self.memory_exporter.get_finished_spans()[0] assert span.status.is_ok not_expected = { - "http.request.header.custom_test_header_1": ("Test Value 1",), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-1": ("Test Value 1",), + "http.request.header.custom-test-header-2": ( "TestValue2,TestValue3", ), - "http.request.header.regex_test_header_1": ( + "http.request.header.regex-test-header-1": ( "Regex Test Value 1", ), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } self.assertEqual(span.kind, trace.SpanKind.INTERNAL) for key, _ in not_expected.items(): @@ -551,23 +551,23 @@ def test_custom_response_header_added_in_server_span(self): span = self.memory_exporter.get_finished_spans()[0] assert span.status.is_ok expected = { - "http.response.header.content_type": ( + "http.response.header.content-type": ( "text/plain; charset=utf-8", ), - "http.response.header.content_length": ("0",), - "http.response.header.my_custom_header": ( + "http.response.header.content-length": ("0",), + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-header-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } not_expected = { - "http.response.header.dont_capture_me": ("test-value",) + "http.response.header.dont-capture-me": ("test-value",) } self.assertEqual(span.kind, trace.SpanKind.SERVER) self.assertSpanHasAttributes(span, expected) @@ -587,20 +587,20 @@ def test_custom_response_header_not_added_in_internal_span(self): span = self.memory_exporter.get_finished_spans()[0] assert span.status.is_ok not_expected = { - "http.response.header.content_type": ( + "http.response.header.content-type": ( "text/plain; charset=utf-8", ), - "http.response.header.content_length": ("0",), + "http.response.header.content-length": ("0",), "http.response.header.my_custom_header": ( "my-custom-value-1,my-custom-header-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } self.assertEqual(span.kind, trace.SpanKind.INTERNAL) for key, _ in not_expected.items(): diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py index a19480b234..734afb12e6 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/src/opentelemetry/instrumentation/fastapi/__init__.py @@ -112,11 +112,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=".*" The name of the added span attribute will follow the format ``http.request.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -single item list containing all the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing all the header values. For example: -``http.request.header.custom_request_header = ["", ""]`` +``http.request.header.custom-request-header = ["", ""]`` Response headers **************** @@ -147,11 +146,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=".*" The name of the added span attribute will follow the format ``http.response.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -list containing the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a list containing the header values. For example: -``http.response.header.custom_response_header = ["", ""]`` +``http.response.header.custom-response-header = ["", ""]`` Sanitizing headers ****************** diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py b/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py index fdbad4effb..3ce9463280 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation.py @@ -1403,17 +1403,17 @@ async def _(): def test_http_custom_request_headers_in_span_attributes(self): expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } resp = self.client.get( "/foobar", @@ -1437,7 +1437,7 @@ def test_http_custom_request_headers_in_span_attributes(self): def test_http_custom_request_headers_not_in_span_attributes(self): not_expected = { - "http.request.header.custom_test_header_3": ( + "http.request.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -1464,19 +1464,19 @@ def test_http_custom_request_headers_not_in_span_attributes(self): def test_http_custom_response_headers_in_span_attributes(self): expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", ), - "http.response.header.custom_test_header_2": ( + "http.response.header.custom-test-header-2": ( "test-header-value-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } resp = self.client.get("/foobar") self.assertEqual(200, resp.status_code) @@ -1490,7 +1490,7 @@ def test_http_custom_response_headers_in_span_attributes(self): def test_http_custom_response_headers_not_in_span_attributes(self): not_expected = { - "http.response.header.custom_test_header_3": ( + "http.response.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -1569,7 +1569,7 @@ def test_http_custom_request_headers_in_span_attributes_app(self): "http.request.header.apple": ("red",), # same with banana because it starts with b, # redacted because it contains "secret" - "http.request.header.banana_secret": ("[REDACTED]",), + "http.request.header.banana-secret": ("[REDACTED]",), } self.assertSpanHasAttributes(server_span, expected) self.assertNotIn("http.request.header.fig", server_span.attributes) @@ -1599,7 +1599,7 @@ def test_http_custom_request_headers_in_span_attributes_instr(self): "http.request.header.apple": ("red",), # same with banana because it starts with b, # redacted because it contains "secret" - "http.request.header.banana_secret": ("[REDACTED]",), + "http.request.header.banana-secret": ("[REDACTED]",), } self.assertSpanHasAttributes(server_span, expected) self.assertNotIn("http.request.header.fig", server_span.attributes) @@ -1618,7 +1618,7 @@ def test_http_custom_response_headers_in_span_attributes_app(self): expected = { "http.response.header.carrot": ("bar",), - "http.response.header.date_secret": ("[REDACTED]",), + "http.response.header.date-secret": ("[REDACTED]",), } self.assertSpanHasAttributes(server_span, expected) self.assertNotIn("http.response.header.egg", server_span.attributes) @@ -1638,7 +1638,7 @@ def test_http_custom_response_headers_in_span_attributes_inst(self): expected = { "http.response.header.carrot": ("bar",), - "http.response.header.date_secret": ("[REDACTED]",), + "http.response.header.date-secret": ("[REDACTED]",), } self.assertSpanHasAttributes(server_span, expected) self.assertNotIn("http.response.header.egg", server_span.attributes) @@ -1696,10 +1696,10 @@ async def _(websocket: fastapi.WebSocket): def test_web_socket_custom_request_headers_in_span_attributes(self): expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), } @@ -1732,7 +1732,7 @@ def test_web_socket_custom_request_headers_in_span_attributes(self): ) def test_web_socket_custom_request_headers_not_in_span_attributes(self): not_expected = { - "http.request.header.custom_test_header_3": ( + "http.request.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -1759,10 +1759,10 @@ def test_web_socket_custom_request_headers_not_in_span_attributes(self): def test_web_socket_custom_response_headers_in_span_attributes(self): expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", ), - "http.response.header.custom_test_header_2": ( + "http.response.header.custom-test-header-2": ( "test-header-value-2", ), } @@ -1782,7 +1782,7 @@ def test_web_socket_custom_response_headers_in_span_attributes(self): def test_web_socket_custom_response_headers_not_in_span_attributes(self): not_expected = { - "http.response.header.custom_test_header_3": ( + "http.response.header.custom-test-header-3": ( "test-header-value-3", ), } diff --git a/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation_custom_headers.py b/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation_custom_headers.py index 0a1b20155e..070a987284 100644 --- a/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation_custom_headers.py +++ b/instrumentation/opentelemetry-instrumentation-fastapi/tests/test_fastapi_instrumentation_custom_headers.py @@ -76,17 +76,17 @@ async def _(): def test_http_custom_request_headers_in_span_attributes(self): expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } resp = self.client.get( "/foobar", @@ -110,7 +110,7 @@ def test_http_custom_request_headers_in_span_attributes(self): def test_http_custom_request_headers_not_in_span_attributes(self): not_expected = { - "http.request.header.custom_test_header_3": ( + "http.request.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -137,21 +137,21 @@ def test_http_custom_request_headers_not_in_span_attributes(self): def test_http_custom_response_headers_in_span_attributes(self): expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", ), - "http.response.header.custom_test_header_2": ( + "http.response.header.custom-test-header-2": ( "test-header-value-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1", "my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3", "my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } resp = self.client.get("/foobar") self.assertEqual(200, resp.status_code) @@ -165,7 +165,7 @@ def test_http_custom_response_headers_in_span_attributes(self): def test_http_custom_response_headers_not_in_span_attributes(self): not_expected = { - "http.response.header.custom_test_header_3": ( + "http.response.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -234,10 +234,10 @@ async def _(websocket: fastapi.WebSocket): def test_web_socket_custom_request_headers_in_span_attributes(self): expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), } @@ -270,7 +270,7 @@ def test_web_socket_custom_request_headers_in_span_attributes(self): ) def test_web_socket_custom_request_headers_not_in_span_attributes(self): not_expected = { - "http.request.header.custom_test_header_3": ( + "http.request.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -297,10 +297,10 @@ def test_web_socket_custom_request_headers_not_in_span_attributes(self): def test_web_socket_custom_response_headers_in_span_attributes(self): expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", ), - "http.response.header.custom_test_header_2": ( + "http.response.header.custom-test-header-2": ( "test-header-value-2", ), } @@ -320,7 +320,7 @@ def test_web_socket_custom_response_headers_in_span_attributes(self): def test_web_socket_custom_response_headers_not_in_span_attributes(self): not_expected = { - "http.response.header.custom_test_header_3": ( + "http.response.header.custom-test-header-3": ( "test-header-value-3", ), } diff --git a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py index 9691f884ab..29e2a0ad3c 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-flask/src/opentelemetry/instrumentation/flask/__init__.py @@ -178,11 +178,10 @@ def response_hook(span: Span, status: str, response_headers: List): export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=".*" The name of the added span attribute will follow the format ``http.request.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -single item list containing all the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing all the header values. For example: -``http.request.header.custom_request_header = [","]`` +``http.request.header.custom-request-header = [","]`` Response headers **************** @@ -212,11 +211,10 @@ def response_hook(span: Span, status: str, response_headers: List): export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=".*" The name of the added span attribute will follow the format ``http.response.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -single item list containing all the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing all the header values. For example: -``http.response.header.custom_response_header = [","]`` +``http.response.header.custom-response-header = [","]`` Sanitizing headers ****************** diff --git a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py index e6bc8202df..e34b1237a9 100644 --- a/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py +++ b/instrumentation/opentelemetry-instrumentation-flask/tests/test_programmatic.py @@ -916,15 +916,15 @@ def test_custom_request_header_added_in_server_span(self): self.assertEqual(200, resp.status_code) span = self.memory_exporter.get_finished_spans()[0] expected = { - "http.request.header.custom_test_header_1": ("Test Value 1",), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-1": ("Test Value 1",), + "http.request.header.custom-test-header-2": ( "TestValue2,TestValue3", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } self.assertEqual(span.kind, trace.SpanKind.SERVER) self.assertSpanHasAttributes(span, expected) @@ -938,7 +938,7 @@ def test_repeat_custom_request_header_added_in_server_span(self): self.assertEqual(200, resp.status_code) span = self.memory_exporter.get_finished_spans()[0] expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "Test Value 1, Test Value 2", ), } @@ -959,17 +959,17 @@ def test_custom_request_header_not_added_in_internal_span(self): self.assertEqual(200, resp.status_code) span = self.memory_exporter.get_finished_spans()[0] not_expected = { - "http.request.header.custom_test_header_1": ("Test Value 1",), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-1": ("Test Value 1",), + "http.request.header.custom-test-header-2": ( "TestValue2,TestValue3", ), - "http.request.header.regex_test_header_1": ( + "http.request.header.regex-test-header-1": ( "Regex Test Value 1", ), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } self.assertEqual(span.kind, trace.SpanKind.INTERNAL) for key, _ in not_expected.items(): @@ -980,20 +980,20 @@ def test_custom_response_header_added_in_server_span(self): self.assertEqual(resp.status_code, 200) span = self.memory_exporter.get_finished_spans()[0] expected = { - "http.response.header.content_type": ( + "http.response.header.content-type": ( "text/plain; charset=utf-8", ), - "http.response.header.content_length": ("13",), - "http.response.header.my_custom_header": ( + "http.response.header.content-length": ("13",), + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-header-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } self.assertEqual(span.kind, trace.SpanKind.SERVER) self.assertSpanHasAttributes(span, expected) @@ -1003,10 +1003,10 @@ def test_repeat_custom_response_header_added_in_server_span(self): self.assertEqual(resp.status_code, 200) span = self.memory_exporter.get_finished_spans()[0] expected = { - "http.response.header.content_type": ( + "http.response.header.content-type": ( "text/plain; charset=utf-8", ), - "http.response.header.my_custom_header": ( + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-header-2", ), } @@ -1020,20 +1020,20 @@ def test_custom_response_header_not_added_in_internal_span(self): self.assertEqual(resp.status_code, 200) span = self.memory_exporter.get_finished_spans()[0] not_expected = { - "http.response.header.content_type": ( + "http.response.header.content-type": ( "text/plain; charset=utf-8", ), - "http.response.header.content_length": ("13",), - "http.response.header.my_custom_header": ( + "http.response.header.content-length": ("13",), + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-header-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } self.assertEqual(span.kind, trace.SpanKind.INTERNAL) for key, _ in not_expected.items(): diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/__init__.py b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/__init__.py index 6136d55558..7dd6ad16d6 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/src/opentelemetry/instrumentation/pyramid/__init__.py @@ -124,11 +124,10 @@ export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=".*" The name of the added span attribute will follow the format ``http.request.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -single item list containing all the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing all the header values. For example: -``http.request.header.custom_request_header = [","]`` +``http.request.header.custom-request-header = [","]`` Response headers **************** @@ -158,11 +157,10 @@ export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=".*" The name of the added span attribute will follow the format ``http.response.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -single item list containing all the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing all the header values. For example: -``http.response.header.custom_response_header = [","]`` +``http.response.header.custom-response-header = [","]`` Sanitizing headers ****************** diff --git a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py index b40cf3355a..29573673bc 100644 --- a/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py +++ b/instrumentation/opentelemetry-instrumentation-pyramid/tests/test_automatic.py @@ -323,18 +323,18 @@ def test_custom_request_header_added_in_server_span(self): self.assertEqual(200, resp.status_code) span = self.memory_exporter.get_finished_spans()[0] expected = { - "http.request.header.custom_test_header_1": ("Test Value 1",), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-1": ("Test Value 1",), + "http.request.header.custom-test-header-2": ( "TestValue2,TestValue3", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } not_expected = { - "http.request.header.custom_test_header_3": ("TestValue4",), + "http.request.header.custom-test-header-3": ("TestValue4",), } self.assertEqual(span.kind, SpanKind.SERVER) self.assertSpanHasAttributes(span, expected) @@ -352,8 +352,8 @@ def test_custom_request_header_not_added_in_internal_span(self): self.assertEqual(200, resp.status_code) span = self.memory_exporter.get_finished_spans()[0] not_expected = { - "http.request.header.custom_test_header_1": ("Test Value 1",), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-1": ("Test Value 1",), + "http.request.header.custom-test-header-2": ( "TestValue2,TestValue3", ), } @@ -366,23 +366,23 @@ def test_custom_response_header_added_in_server_span(self): self.assertEqual(200, resp.status_code) span = self.memory_exporter.get_finished_spans()[0] expected = { - "http.response.header.content_type": ( + "http.response.header.content-type": ( "text/plain; charset=utf-8", ), - "http.response.header.content_length": ("7",), - "http.response.header.my_custom_header": ( + "http.response.header.content-length": ("7",), + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-header-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } not_expected = { - "http.response.header.dont_capture_me": ("test-value",) + "http.response.header.dont-capture-me": ("test-value",) } self.assertEqual(span.kind, SpanKind.SERVER) self.assertSpanHasAttributes(span, expected) @@ -396,11 +396,11 @@ def test_custom_response_header_not_added_in_internal_span(self): self.assertEqual(200, resp.status_code) span = self.memory_exporter.get_finished_spans()[0] not_expected = { - "http.response.header.content_type": ( + "http.response.header.content-type": ( "text/plain; charset=utf-8", ), - "http.response.header.content_length": ("7",), - "http.response.header.my_custom_header": ( + "http.response.header.content-length": ("7",), + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-header-2", ), } diff --git a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py index 5007bda50a..a19731a9e3 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-starlette/src/opentelemetry/instrumentation/starlette/__init__.py @@ -109,11 +109,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST="all" The name of the added span attribute will follow the format ``http.request.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -list containing the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a list containing the header values. For example: -``http.request.header.custom_request_header = ["", ""]`` +``http.request.header.custom-request-header = ["", ""]`` Response headers **************** @@ -143,11 +142,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE="all" The name of the added span attribute will follow the format ``http.response.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -list containing the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a list containing the header values. For example: -``http.response.header.custom_response_header = ["", ""]`` +``http.response.header.custom-response-header = ["", ""]`` Sanitizing headers ****************** @@ -283,7 +281,7 @@ def _instrument(self, **kwargs: Unpack[InstrumentKwargs]): applications.Starlette = _InstrumentedStarlette def _uninstrument(self, **kwargs: Any): - """uninstrumenting all created apps by user""" + """Uninstrument all applications created by the user.""" for instance in _InstrumentedStarlette._instrumented_starlette_apps: self.uninstrument_app(instance) _InstrumentedStarlette._instrumented_starlette_apps.clear() diff --git a/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py b/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py index 3f9f1c7b0f..9adab63d1f 100644 --- a/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-starlette/tests/test_starlette_instrumentation.py @@ -680,17 +680,17 @@ def setUp(self) -> None: def test_custom_request_headers_in_span_attributes(self): expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } resp = self._client.get( "/foobar", @@ -721,7 +721,7 @@ def test_custom_request_headers_in_span_attributes(self): ) def test_custom_request_headers_not_in_span_attributes(self): not_expected = { - "http.request.header.custom_test_header_3": ( + "http.request.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -748,19 +748,19 @@ def test_custom_request_headers_not_in_span_attributes(self): def test_custom_response_headers_in_span_attributes(self): expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", ), - "http.response.header.custom_test_header_2": ( + "http.response.header.custom-test-header-2": ( "test-header-value-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } resp = self._client.get("/foobar") self.assertEqual(200, resp.status_code) @@ -775,7 +775,7 @@ def test_custom_response_headers_in_span_attributes(self): def test_custom_response_headers_not_in_span_attributes(self): not_expected = { - "http.response.header.custom_test_header_3": ( + "http.response.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -806,17 +806,17 @@ def setUp(self) -> None: def test_custom_request_headers_in_span_attributes(self): expected = { - "http.request.header.custom_test_header_1": ( + "http.request.header.custom-test-header-1": ( "test-header-value-1", ), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-2": ( "test-header-value-2", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } with self._client.websocket_connect( "/foobar_web", @@ -841,7 +841,7 @@ def test_custom_request_headers_in_span_attributes(self): def test_custom_request_headers_not_in_span_attributes(self): not_expected = { - "http.request.header.custom_test_header_3": ( + "http.request.header.custom-test-header-3": ( "test-header-value-3", ), } @@ -870,19 +870,19 @@ def test_custom_request_headers_not_in_span_attributes(self): def test_custom_response_headers_in_span_attributes(self): expected = { - "http.response.header.custom_test_header_1": ( + "http.response.header.custom-test-header-1": ( "test-header-value-1", ), - "http.response.header.custom_test_header_2": ( + "http.response.header.custom-test-header-2": ( "test-header-value-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } with self._client.websocket_connect("/foobar_web") as websocket: data = websocket.receive_json() @@ -899,7 +899,7 @@ def test_custom_response_headers_in_span_attributes(self): def test_custom_response_headers_not_in_span_attributes(self): not_expected = { - "http.response.header.custom_test_header_3": ( + "http.response.header.custom-test-header-3": ( "test-header-value-3", ), } diff --git a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py index 3a19450433..583ff1ceb2 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/src/opentelemetry/instrumentation/tornado/__init__.py @@ -117,11 +117,11 @@ def client_response_hook(span, future): It is recommended that you should give the correct names of the headers to be captured in the environment variable. Request header names in tornado are case insensitive. So, giving header name as ``CUStomHeader`` in environment variable will be able capture header with name ``customheader``. -The name of the added span attribute will follow the format ``http.request.header.`` where ```` being the normalized HTTP header name (lowercase, with - characters replaced by _ ). +The name of the added span attribute will follow the format ``http.request.header.`` where ```` being the normalized HTTP header name (lowercase). The value of the attribute will be single item list containing all the header values. Example of the added span attribute, -``http.request.header.custom_request_header = [","]`` +``http.request.header.custom-request-header = [","]`` Response headers **************** @@ -139,11 +139,11 @@ def client_response_hook(span, future): It is recommended that you should give the correct names of the headers to be captured in the environment variable. Response header names captured in tornado are case insensitive. So, giving header name as ``CUStomHeader`` in environment variable will be able capture header with name ``customheader``. -The name of the added span attribute will follow the format ``http.response.header.`` where ```` being the normalized HTTP header name (lowercase, with - characters replaced by _ ). +The name of the added span attribute will follow the format ``http.response.header.`` where ```` being the normalized HTTP header name (lowercase). The value of the attribute will be single item list containing all the header values. Example of the added span attribute, -``http.response.header.custom_response_header = [","]`` +``http.response.header.custom-response-header = [","]`` Note: Environment variable names to capture http headers are still experimental, and thus are subject to change. diff --git a/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py b/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py index daf2ddd846..a686035961 100644 --- a/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py +++ b/instrumentation/opentelemetry-instrumentation-tornado/tests/test_instrumentation.py @@ -715,8 +715,8 @@ def test_custom_request_headers_added_in_server_span(self): self.memory_exporter.get_finished_spans() ) expected = { - "http.request.header.custom_test_header_1": ("Test Value 1",), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-1": ("Test Value 1",), + "http.request.header.custom-test-header-2": ( "TestValue2,TestValue3", ), } @@ -736,11 +736,11 @@ def test_custom_response_headers_added_in_server_span(self): self.memory_exporter.get_finished_spans() ) expected = { - "http.response.header.content_type": ( + "http.response.header.content-type": ( "text/plain; charset=utf-8", ), - "http.response.header.content_length": ("0",), - "http.response.header.my_custom_header": ( + "http.response.header.content-length": ("0",), + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-header-2", ), } @@ -781,8 +781,8 @@ def test_custom_request_headers_not_added_in_internal_span(self): self.memory_exporter.get_finished_spans() ) not_expected = { - "http.request.header.custom_test_header_1": ("Test Value 1",), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-1": ("Test Value 1",), + "http.request.header.custom-test-header-2": ( "TestValue2,TestValue3", ), } @@ -803,11 +803,11 @@ def test_custom_response_headers_not_added_in_internal_span(self): self.memory_exporter.get_finished_spans() ) not_expected = { - "http.response.header.content_type": ( + "http.response.header.content-type": ( "text/plain; charset=utf-8", ), - "http.response.header.content_length": ("0",), - "http.response.header.my_custom_header": ( + "http.response.header.content-length": ("0",), + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-header-2", ), } diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py index bd3b2d18db..da2e82e47b 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/src/opentelemetry/instrumentation/wsgi/__init__.py @@ -140,11 +140,10 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST=".*" The name of the added span attribute will follow the format ``http.request.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -single item list containing all the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing all the header values. For example: -``http.request.header.custom_request_header = [","]`` +``http.request.header.custom-request-header = [","]`` Response headers **************** @@ -174,11 +173,11 @@ def response_hook(span: Span, environ: WSGIEnvironment, status: str, response_he export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE=".*" The name of the added span attribute will follow the format ``http.response.header.`` where ```` -is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a -single item list containing all the header values. +is the normalized HTTP header name (lowercase). The value of the attribute will be a single item list containing +all the header values. For example: -``http.response.header.custom_response_header = [","]`` +``http.response.header.custom-response-header = [","]`` Sanitizing headers ****************** diff --git a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py index 9d7d1240a7..8cb179ee13 100644 --- a/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py +++ b/instrumentation/opentelemetry-instrumentation-wsgi/tests/test_wsgi_middleware.py @@ -948,15 +948,15 @@ def test_custom_request_headers_added_in_server_span(self): self.iterate_response(response) span = self.memory_exporter.get_finished_spans()[0] expected = { - "http.request.header.custom_test_header_1": ("Test Value 1",), - "http.request.header.custom_test_header_2": ( + "http.request.header.custom-test-header-1": ("Test Value 1",), + "http.request.header.custom-test-header-2": ( "TestValue2,TestValue3", ), - "http.request.header.regex_test_header_1": ("Regex Test Value 1",), - "http.request.header.regex_test_header_2": ( + "http.request.header.regex-test-header-1": ("Regex Test Value 1",), + "http.request.header.regex-test-header-2": ( "RegexTestValue2,RegexTestValue3", ), - "http.request.header.my_secret_header": ("[REDACTED]",), + "http.request.header.my-secret-header": ("[REDACTED]",), } self.assertSpanHasAttributes(span, expected) @@ -981,7 +981,7 @@ def test_custom_request_headers_not_added_in_internal_span(self): self.iterate_response(response) span = self.memory_exporter.get_finished_spans()[0] not_expected = { - "http.request.header.custom_test_header_1": ("Test Value 1",), + "http.request.header.custom-test-header-1": ("Test Value 1",), } for key, _ in not_expected.items(): self.assertNotIn(key, span.attributes) @@ -1001,20 +1001,20 @@ def test_custom_response_headers_added_in_server_span(self): self.iterate_response(response) span = self.memory_exporter.get_finished_spans()[0] expected = { - "http.response.header.content_type": ( + "http.response.header.content-type": ( "text/plain; charset=utf-8", ), - "http.response.header.content_length": ("100",), - "http.response.header.my_custom_header": ( + "http.response.header.content-length": ("100",), + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-header-2", ), - "http.response.header.my_custom_regex_header_1": ( + "http.response.header.my-custom-regex-header-1": ( "my-custom-regex-value-1,my-custom-regex-value-2", ), - "http.response.header.my_custom_regex_header_2": ( + "http.response.header.my-custom-regex-header-2": ( "my-custom-regex-value-3,my-custom-regex-value-4", ), - "http.response.header.my_secret_header": ("[REDACTED]",), + "http.response.header.my-secret-header": ("[REDACTED]",), } self.assertSpanHasAttributes(span, expected) @@ -1035,7 +1035,7 @@ def test_custom_response_headers_not_added_in_internal_span(self): self.iterate_response(response) span = self.memory_exporter.get_finished_spans()[0] not_expected = { - "http.response.header.my_custom_header": ( + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-header-2", ), } @@ -1056,7 +1056,7 @@ def test_repeat_custom_response_headers_added_in_server_span(self): self.iterate_response(response) span = self.memory_exporter.get_finished_spans()[0] expected = { - "http.response.header.my_custom_header": ( + "http.response.header.my-custom-header": ( "my-custom-value-1,my-custom-value-2", ), } diff --git a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py index c7dd9f7b06..8e6acf4d23 100644 --- a/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py +++ b/util/opentelemetry-util-http/src/opentelemetry/util/http/__init__.py @@ -182,12 +182,12 @@ def remove_url_credentials(url: str) -> str: def normalise_request_header_name(header: str) -> str: - key = header.lower().replace("-", "_") + key = header.lower() return f"http.request.header.{key}" def normalise_response_header_name(header: str) -> str: - key = header.lower().replace("-", "_") + key = header.lower() return f"http.response.header.{key}" diff --git a/util/opentelemetry-util-http/tests/test_capture_custom_headers.py b/util/opentelemetry-util-http/tests/test_capture_custom_headers.py index 24f0ee0ada..a77aea1380 100644 --- a/util/opentelemetry-util-http/tests/test_capture_custom_headers.py +++ b/util/opentelemetry-util-http/tests/test_capture_custom_headers.py @@ -104,8 +104,8 @@ def test_sanitize(self): def test_normalise_request_header_name(self): key = normalise_request_header_name("Test-Header") - self.assertEqual(key, "http.request.header.test_header") + self.assertEqual(key, "http.request.header.test-header") def test_normalise_response_header_name(self): key = normalise_response_header_name("Test-Header") - self.assertEqual(key, "http.response.header.test_header") + self.assertEqual(key, "http.response.header.test-header")