44import json
55import logging
66from time import time_ns
7- from typing import Any , Dict , List , Sequence
7+ from typing import no_type_check , Any , Dict , List , Sequence
88from urllib .parse import urlparse
99
10+ from opentelemetry .semconv .attributes .client_attributes import CLIENT_ADDRESS
11+ from opentelemetry .semconv .attributes .http_attributes import (
12+ HTTP_REQUEST_METHOD ,
13+ HTTP_RESPONSE_STATUS_CODE ,
14+ )
1015from opentelemetry .semconv .trace import DbSystemValues , SpanAttributes
1116from opentelemetry .semconv ._incubating .attributes import gen_ai_attributes
1217from opentelemetry .sdk .resources import Resource
6570 "code." ,
6671]
6772
73+ _STANDARD_OPENTELEMETRY_HTTP_ATTRIBUTES = [
74+ "client.address" ,
75+ "client.port" ,
76+ "server.address" ,
77+ "server.port" ,
78+ "url.full" ,
79+ "url.path" ,
80+ "url.query" ,
81+ "url.scheme" ,
82+ "url.template" ,
83+ "error.type" ,
84+ "network.local.address" ,
85+ "network.local.port" ,
86+ "network.protocol.name" ,
87+ "network.peer.address" ,
88+ "network.peer.port" ,
89+ "network.protocol.version" ,
90+ "network.transport" ,
91+ "user_agent.original" ,
92+ "user_agent.synthetic.type" ,
93+ ]
94+
6895_STANDARD_AZURE_MONITOR_ATTRIBUTES = [
6996 _SAMPLE_RATE_KEY ,
7097]
@@ -141,7 +168,7 @@ def _get_otel_resource_envelope(self, resource: Resource) -> TelemetryItem:
141168 def _span_to_envelope (self , span : ReadableSpan ) -> TelemetryItem :
142169 envelope = _convert_span_to_envelope (span )
143170 envelope .instrumentation_key = self ._instrumentation_key
144- return envelope
171+ return envelope # type: ignore
145172
146173 def _span_events_to_envelopes (self , span : ReadableSpan ) -> Sequence [TelemetryItem ]:
147174 if not span or len (span .events ) == 0 :
@@ -179,6 +206,7 @@ def from_connection_string(cls, conn_str: str, **kwargs: Any) -> "AzureMonitorTr
179206# pylint: disable=too-many-branches
180207# pylint: disable=protected-access
181208# mypy: disable-error-code="assignment,attr-defined,index,operator,union-attr"
209+ @no_type_check
182210def _convert_span_to_envelope (span : ReadableSpan ) -> TelemetryItem :
183211 # Update instrumentation bitmap if span was generated from instrumentation
184212 _check_instrumentation_span (span )
@@ -208,8 +236,9 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
208236 )
209237 envelope .data = MonitorBase (base_data = data , base_type = "RequestData" )
210238 envelope .tags [ContextTagKeys .AI_OPERATION_NAME ] = span .name
211- if SpanAttributes .NET_PEER_IP in span .attributes :
212- envelope .tags [ContextTagKeys .AI_LOCATION_IP ] = span .attributes [SpanAttributes .NET_PEER_IP ]
239+ location_ip = trace_utils ._get_location_ip (span .attributes )
240+ if location_ip :
241+ envelope .tags [ContextTagKeys .AI_LOCATION_IP ] = location_ip
213242 if _AZURE_SDK_NAMESPACE_NAME in span .attributes : # Azure specific resources
214243 # Currently only eventhub and servicebus are supported (kind CONSUMER)
215244 data .source = trace_utils ._get_azure_sdk_target_source (span .attributes )
@@ -222,21 +251,19 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
222251 difference = (start_time / 1000000 ) - enqueued_time
223252 total += difference
224253 data .measurements ["timeSinceEnqueued" ] = max (0 , total / len (span .links ))
225- elif SpanAttributes .HTTP_METHOD in span .attributes : # HTTP
254+ elif HTTP_REQUEST_METHOD in span . attributes or SpanAttributes .HTTP_METHOD in span .attributes : # HTTP
226255 path = ""
227- if SpanAttributes .HTTP_USER_AGENT in span .attributes :
256+ user_agent = trace_utils ._get_user_agent (span .attributes )
257+ if user_agent :
228258 # TODO: Not exposed in Swagger, need to update def
229- envelope .tags ["ai.user.userAgent" ] = span .attributes [SpanAttributes .HTTP_USER_AGENT ]
230- # http specific logic for ai.location.ip
231- if SpanAttributes .HTTP_CLIENT_IP in span .attributes :
232- envelope .tags [ContextTagKeys .AI_LOCATION_IP ] = span .attributes [SpanAttributes .HTTP_CLIENT_IP ]
259+ envelope .tags ["ai.user.userAgent" ] = user_agent
233260 # url
234261 url = trace_utils ._get_url_for_http_request (span .attributes )
235262 data .url = url
236263 # Http specific logic for ai.operation.name
237264 if SpanAttributes .HTTP_ROUTE in span .attributes :
238265 envelope .tags [ContextTagKeys .AI_OPERATION_NAME ] = "{} {}" .format (
239- span .attributes [ SpanAttributes .HTTP_METHOD ] ,
266+ span .attributes . get ( HTTP_REQUEST_METHOD ) or span . attributes . get ( SpanAttributes .HTTP_METHOD ) ,
240267 span .attributes [SpanAttributes .HTTP_ROUTE ],
241268 )
242269 elif url :
@@ -246,12 +273,13 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
246273 if not path :
247274 path = "/"
248275 envelope .tags [ContextTagKeys .AI_OPERATION_NAME ] = "{} {}" .format (
249- span .attributes [ SpanAttributes .HTTP_METHOD ] ,
276+ span .attributes . get ( HTTP_REQUEST_METHOD ) or span . attributes . get ( SpanAttributes .HTTP_METHOD ) ,
250277 path ,
251278 )
252279 except Exception : # pylint: disable=broad-except
253280 pass
254- status_code = span .attributes .get (SpanAttributes .HTTP_STATUS_CODE )
281+ status_code = span .attributes .get (HTTP_RESPONSE_STATUS_CODE ) \
282+ or span .attributes .get (SpanAttributes .HTTP_STATUS_CODE )
255283 if status_code :
256284 try :
257285 status_code = int (status_code ) # type: ignore
@@ -263,12 +291,10 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
263291 # Success criteria for server spans depends on span.success and the actual status code
264292 data .success = span .status .is_ok and status_code and status_code not in range (400 , 500 )
265293 elif SpanAttributes .MESSAGING_SYSTEM in span .attributes : # Messaging
266- if SpanAttributes .NET_PEER_IP in span .attributes :
267- envelope .tags [ContextTagKeys .AI_LOCATION_IP ] = span .attributes [SpanAttributes .NET_PEER_IP ]
268294 if span .attributes .get (SpanAttributes .MESSAGING_DESTINATION ):
269- if span .attributes .get (SpanAttributes .NET_PEER_NAME ):
295+ if span .attributes .get (CLIENT_ADDRESS ) or span . attributes . get ( SpanAttributes .NET_PEER_NAME ):
270296 data .source = "{}/{}" .format (
271- span .attributes .get (SpanAttributes .NET_PEER_NAME ),
297+ span .attributes .get (CLIENT_ADDRESS ) or span . attributes . get ( SpanAttributes .NET_PEER_NAME ),
272298 span .attributes .get (SpanAttributes .MESSAGING_DESTINATION ),
273299 )
274300 elif span .attributes .get (SpanAttributes .NET_PEER_IP ):
@@ -515,7 +541,8 @@ def _is_standard_attribute(key: str) -> bool:
515541 for prefix in _STANDARD_OPENTELEMETRY_ATTRIBUTE_PREFIXES :
516542 if key .startswith (prefix ):
517543 return True
518- return key in _STANDARD_AZURE_MONITOR_ATTRIBUTES
544+ return key in _STANDARD_AZURE_MONITOR_ATTRIBUTES or \
545+ key in _STANDARD_OPENTELEMETRY_HTTP_ATTRIBUTES
519546
520547
521548def _get_trace_export_result (result : ExportResult ) -> SpanExportResult :
0 commit comments