4
4
import json
5
5
import logging
6
6
from time import time_ns
7
- from typing import Any , Dict , List , Sequence
7
+ from typing import no_type_check , Any , Dict , List , Sequence
8
8
from urllib .parse import urlparse
9
9
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
+ )
10
15
from opentelemetry .semconv .trace import DbSystemValues , SpanAttributes
11
16
from opentelemetry .semconv ._incubating .attributes import gen_ai_attributes
12
17
from opentelemetry .sdk .resources import Resource
65
70
"code." ,
66
71
]
67
72
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
+
68
95
_STANDARD_AZURE_MONITOR_ATTRIBUTES = [
69
96
_SAMPLE_RATE_KEY ,
70
97
]
@@ -141,7 +168,7 @@ def _get_otel_resource_envelope(self, resource: Resource) -> TelemetryItem:
141
168
def _span_to_envelope (self , span : ReadableSpan ) -> TelemetryItem :
142
169
envelope = _convert_span_to_envelope (span )
143
170
envelope .instrumentation_key = self ._instrumentation_key
144
- return envelope
171
+ return envelope # type: ignore
145
172
146
173
def _span_events_to_envelopes (self , span : ReadableSpan ) -> Sequence [TelemetryItem ]:
147
174
if not span or len (span .events ) == 0 :
@@ -179,6 +206,7 @@ def from_connection_string(cls, conn_str: str, **kwargs: Any) -> "AzureMonitorTr
179
206
# pylint: disable=too-many-branches
180
207
# pylint: disable=protected-access
181
208
# mypy: disable-error-code="assignment,attr-defined,index,operator,union-attr"
209
+ @no_type_check
182
210
def _convert_span_to_envelope (span : ReadableSpan ) -> TelemetryItem :
183
211
# Update instrumentation bitmap if span was generated from instrumentation
184
212
_check_instrumentation_span (span )
@@ -208,8 +236,9 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
208
236
)
209
237
envelope .data = MonitorBase (base_data = data , base_type = "RequestData" )
210
238
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
213
242
if _AZURE_SDK_NAMESPACE_NAME in span .attributes : # Azure specific resources
214
243
# Currently only eventhub and servicebus are supported (kind CONSUMER)
215
244
data .source = trace_utils ._get_azure_sdk_target_source (span .attributes )
@@ -222,21 +251,19 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
222
251
difference = (start_time / 1000000 ) - enqueued_time
223
252
total += difference
224
253
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
226
255
path = ""
227
- if SpanAttributes .HTTP_USER_AGENT in span .attributes :
256
+ user_agent = trace_utils ._get_user_agent (span .attributes )
257
+ if user_agent :
228
258
# 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
233
260
# url
234
261
url = trace_utils ._get_url_for_http_request (span .attributes )
235
262
data .url = url
236
263
# Http specific logic for ai.operation.name
237
264
if SpanAttributes .HTTP_ROUTE in span .attributes :
238
265
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 ) ,
240
267
span .attributes [SpanAttributes .HTTP_ROUTE ],
241
268
)
242
269
elif url :
@@ -246,12 +273,13 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
246
273
if not path :
247
274
path = "/"
248
275
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 ) ,
250
277
path ,
251
278
)
252
279
except Exception : # pylint: disable=broad-except
253
280
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 )
255
283
if status_code :
256
284
try :
257
285
status_code = int (status_code ) # type: ignore
@@ -263,12 +291,10 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
263
291
# Success criteria for server spans depends on span.success and the actual status code
264
292
data .success = span .status .is_ok and status_code and status_code not in range (400 , 500 )
265
293
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 ]
268
294
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 ):
270
296
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 ),
272
298
span .attributes .get (SpanAttributes .MESSAGING_DESTINATION ),
273
299
)
274
300
elif span .attributes .get (SpanAttributes .NET_PEER_IP ):
@@ -515,7 +541,8 @@ def _is_standard_attribute(key: str) -> bool:
515
541
for prefix in _STANDARD_OPENTELEMETRY_ATTRIBUTE_PREFIXES :
516
542
if key .startswith (prefix ):
517
543
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
519
546
520
547
521
548
def _get_trace_export_result (result : ExportResult ) -> SpanExportResult :
0 commit comments