diff --git a/sdk/core/azure-core-tracing-opentelemetry/tests/test_storage_live.py b/sdk/core/azure-core-tracing-opentelemetry/tests/test_storage_live.py index edd8d59e4f80..917c4998f495 100644 --- a/sdk/core/azure-core-tracing-opentelemetry/tests/test_storage_live.py +++ b/sdk/core/azure-core-tracing-opentelemetry/tests/test_storage_live.py @@ -23,7 +23,7 @@ def test_blob_service_client_tracing(self, config, tracing_helper): # We expect 3 spans, one for the root span, one for the method call, and one for the HTTP request. assert len(spans) == 3 span_names_list = [span.name for span in spans] - assert span_names_list == ["/", "BlobServiceClient.get_service_properties", "root"] + assert span_names_list == ["GET", "BlobServiceClient.get_service_properties", "root"] http_span: ReadableSpan = spans[0] assert http_span.kind == SpanKind.CLIENT diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index 671f763f22c6..5918f5ad5bf5 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -22,6 +22,10 @@ ### Breaking Changes - Removed automatic tracing enablement for the OpenTelemetry plugin if `opentelemetry` was imported. To enable tracing with the plugin, please import `azure.core.settings.settings` and set `settings.tracing_implementation` to `"opentelemetry"`. #39563 +- In `DistributedTracingPolicy`, the default span name is now just the HTTP method (e.g., "GET", "POST") and no longer includes the URL path. This change was made to converge with the OpenTelemetry HTTP semantic conventions. The full URL is still included in the span attributes. +- Renamed span attributes in `DistributedTracingPolicy`: + - "x-ms-client-request-id" is now "az.client_request_id" + - "x-ms-request-id" is now "az.service_request_id" ### Bugs Fixed diff --git a/sdk/core/azure-core/azure/core/pipeline/policies/_distributed_tracing.py b/sdk/core/azure-core/azure/core/pipeline/policies/_distributed_tracing.py index 3a30246e1d6e..426cd7f1aae8 100644 --- a/sdk/core/azure-core/azure/core/pipeline/policies/_distributed_tracing.py +++ b/sdk/core/azure-core/azure/core/pipeline/policies/_distributed_tracing.py @@ -61,10 +61,7 @@ def _default_network_span_namer(http_request: HTTPRequestType) -> str: :returns: The string to use as network span name :rtype: str """ - path = urllib.parse.urlparse(http_request.url).path - if not path: - path = "/" - return path + return http_request.method class DistributedTracingPolicy(SansIOHTTPPolicy[HTTPRequestType, HTTPResponseType]): @@ -93,7 +90,9 @@ class DistributedTracingPolicy(SansIOHTTPPolicy[HTTPRequestType, HTTPResponseTyp # Azure attributes _REQUEST_ID = "x-ms-client-request-id" + _REQUEST_ID_ATTR = "az.client_request_id" _RESPONSE_ID = "x-ms-request-id" + _RESPONSE_ID_ATTR = "az.service_request_id" def __init__(self, *, instrumentation_config: Optional[Mapping[str, Any]] = None, **kwargs: Any): self._network_span_namer = kwargs.get("network_span_namer", _default_network_span_namer) @@ -190,9 +189,9 @@ def end_span( if request.context.get("retry_count"): attributes[self._HTTP_RESEND_COUNT] = request.context["retry_count"] if http_request.headers.get(self._REQUEST_ID): - attributes[self._REQUEST_ID] = http_request.headers[self._REQUEST_ID] + attributes[self._REQUEST_ID_ATTR] = http_request.headers[self._REQUEST_ID] if response and self._RESPONSE_ID in response.headers: - attributes[self._RESPONSE_ID] = response.headers[self._RESPONSE_ID] + attributes[self._RESPONSE_ID_ATTR] = response.headers[self._RESPONSE_ID] # We'll determine if the span is from a plugin or the core tracing library based on the presence of the # `set_http_attributes` method. diff --git a/sdk/core/azure-core/tests/test_tracing_policy.py b/sdk/core/azure-core/tests/test_tracing_policy.py index eb4648096789..76355653c034 100644 --- a/sdk/core/azure-core/tests/test_tracing_policy.py +++ b/sdk/core/azure-core/tests/test_tracing_policy.py @@ -52,24 +52,24 @@ def test_distributed_tracing_policy_solo(self, tracing_implementation, http_requ # Check on_response network_span = root_span.children[0] - assert network_span.name == "/temp" + assert network_span.name == "GET" assert network_span.attributes.get(HttpSpanMixin._HTTP_METHOD) == "GET" assert network_span.attributes.get(HttpSpanMixin._HTTP_URL) == "http://localhost/temp?query=query" assert network_span.attributes.get(HttpSpanMixin._NET_PEER_NAME) == "localhost" assert network_span.attributes.get(HttpSpanMixin._HTTP_USER_AGENT) is None - assert network_span.attributes.get(policy._RESPONSE_ID) == "some request id" - assert network_span.attributes.get(policy._REQUEST_ID) == "some client request id" + assert network_span.attributes.get(policy._RESPONSE_ID_ATTR) == "some request id" + assert network_span.attributes.get(policy._REQUEST_ID_ATTR) == "some client request id" assert network_span.attributes.get(HttpSpanMixin._HTTP_STATUS_CODE) == 202 assert policy._ERROR_TYPE not in network_span.attributes # Check on_exception network_span = root_span.children[1] - assert network_span.name == "/temp" + assert network_span.name == "GET" assert network_span.attributes.get(HttpSpanMixin._HTTP_METHOD) == "GET" assert network_span.attributes.get(HttpSpanMixin._HTTP_URL) == "http://localhost/temp?query=query" - assert network_span.attributes.get(policy._REQUEST_ID) == "some client request id" + assert network_span.attributes.get(policy._REQUEST_ID_ATTR) == "some client request id" assert network_span.attributes.get(HttpSpanMixin._HTTP_USER_AGENT) is None - assert network_span.attributes.get(policy._RESPONSE_ID) == None + assert network_span.attributes.get(policy._RESPONSE_ID_ATTR) == None assert network_span.attributes.get(HttpSpanMixin._HTTP_STATUS_CODE) == 504 assert network_span.attributes.get(policy._ERROR_TYPE) @@ -90,7 +90,7 @@ def test_distributed_tracing_policy_error_response(self, tracing_implementation, policy.on_response(pipeline_request, PipelineResponse(request, response, PipelineContext(None))) network_span = root_span.children[0] - assert network_span.name == "/temp" + assert network_span.name == "GET" assert network_span.attributes.get(policy._ERROR_TYPE) == "403" @pytest.mark.parametrize("http_request,http_response", request_and_responses_product(HTTP_RESPONSES)) @@ -211,21 +211,21 @@ def test_distributed_tracing_policy_with_user_agent(self, tracing_implementation user_agent.on_response(pipeline_request, pipeline_response) network_span = root_span.children[0] - assert network_span.name == "/" + assert network_span.name == "GET" assert network_span.attributes.get(HttpSpanMixin._HTTP_METHOD) == "GET" assert network_span.attributes.get(HttpSpanMixin._HTTP_URL) == "http://localhost" assert network_span.attributes.get(HttpSpanMixin._HTTP_USER_AGENT).endswith("mytools") - assert network_span.attributes.get(policy._RESPONSE_ID) == "some request id" - assert network_span.attributes.get(policy._REQUEST_ID) == "some client request id" + assert network_span.attributes.get(policy._RESPONSE_ID_ATTR) == "some request id" + assert network_span.attributes.get(policy._REQUEST_ID_ATTR) == "some client request id" assert network_span.attributes.get(HttpSpanMixin._HTTP_STATUS_CODE) == 202 network_span = root_span.children[1] - assert network_span.name == "/" + assert network_span.name == "GET" assert network_span.attributes.get(HttpSpanMixin._HTTP_METHOD) == "GET" assert network_span.attributes.get(HttpSpanMixin._HTTP_URL) == "http://localhost" assert network_span.attributes.get(HttpSpanMixin._HTTP_USER_AGENT).endswith("mytools") - assert network_span.attributes.get(policy._REQUEST_ID) == "some client request id" - assert network_span.attributes.get(policy._RESPONSE_ID) is None + assert network_span.attributes.get(policy._REQUEST_ID_ATTR) == "some client request id" + assert network_span.attributes.get(policy._RESPONSE_ID_ATTR) is None assert network_span.attributes.get(HttpSpanMixin._HTTP_STATUS_CODE) == 504 # Exception should propagate status for Opencensus assert network_span.status == "Transport trouble" @@ -378,7 +378,7 @@ def test_distributed_tracing_policy(self, tracing_helper, http_request, http_res finished_spans = tracing_helper.exporter.get_finished_spans() assert len(finished_spans) == 2 - assert finished_spans[0].name == "/temp" + assert finished_spans[0].name == "GET" assert finished_spans[0].parent is root_span.get_span_context() assert finished_spans[0].attributes.get(policy._HTTP_REQUEST_METHOD) == "GET" @@ -405,7 +405,7 @@ def test_distributed_tracing_policy_error_response(self, tracing_helper, http_re policy.on_response(pipeline_request, PipelineResponse(request, response, PipelineContext(None))) finished_spans = tracing_helper.exporter.get_finished_spans() - assert finished_spans[0].name == "/temp" + assert finished_spans[0].name == "GET" assert finished_spans[0].attributes.get("error.type") == "403" @pytest.mark.parametrize("http_request,http_response", request_and_responses_product(HTTP_RESPONSES)) @@ -433,7 +433,7 @@ def test_distributed_tracing_policy_custom_instrumentation_config( policy.on_response(pipeline_request, PipelineResponse(request, response, PipelineContext(None))) finished_spans = tracing_helper.exporter.get_finished_spans() - assert finished_spans[0].name == "/temp" + assert finished_spans[0].name == "GET" assert finished_spans[0].attributes.get(policy._ERROR_TYPE) == "403" assert finished_spans[0].instrumentation_scope.name == "my-library" assert finished_spans[0].instrumentation_scope.version == "1.0.0" @@ -495,7 +495,7 @@ def test_distributed_tracing_policy_with_user_agent_policy(self, tracing_helper, finished_spans = tracing_helper.exporter.get_finished_spans() assert len(finished_spans) == 2 - assert finished_spans[0].name == "/temp" + assert finished_spans[0].name == "GET" assert finished_spans[0].parent is root_span.get_span_context() assert finished_spans[0].attributes.get(policy._HTTP_REQUEST_METHOD) == "GET" @@ -579,7 +579,7 @@ def test_distributed_tracing_policy_with_tracing_options(self, tracing_helper, h finished_spans = tracing_helper.exporter.get_finished_spans() assert len(finished_spans) == 2 - assert finished_spans[0].name == "/temp" + assert finished_spans[0].name == "GET" assert finished_spans[0].parent is root_span.get_span_context() assert finished_spans[0].attributes.get(policy._HTTP_REQUEST_METHOD) == "GET" @@ -655,5 +655,5 @@ def test_tracing_impl_takes_precedence(self, tracing_implementation, http_reques assert len(root_span.children) == 1 network_span = root_span.children[0] - assert network_span.name == "/temp" + assert network_span.name == "GET" assert network_span.kind == SpanKind.CLIENT