44import json
55import logging
66from time import time_ns
7- from typing import Dict , List , Optional , Sequence , Any
7+ from typing import Any , Dict , List , Sequence
88from urllib .parse import urlparse
99
10- from opentelemetry .util .types import Attributes
1110from opentelemetry .semconv .trace import DbSystemValues , SpanAttributes
1211from opentelemetry .sdk .resources import Resource
1312from opentelemetry .sdk .trace import ReadableSpan
4342 BaseExporter ,
4443 ExportResult ,
4544)
45+ from . import _utils as trace_utils
46+
4647
4748_logger = logging .getLogger (__name__ )
4849
@@ -211,7 +212,7 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
211212 envelope .tags [ContextTagKeys .AI_LOCATION_IP ] = span .attributes [SpanAttributes .NET_PEER_IP ]
212213 if _AZURE_SDK_NAMESPACE_NAME in span .attributes : # Azure specific resources
213214 # Currently only eventhub and servicebus are supported (kind CONSUMER)
214- data .source = _get_azure_sdk_target_source (span .attributes )
215+ data .source = trace_utils . _get_azure_sdk_target_source (span .attributes )
215216 if span .links :
216217 total = 0
217218 for link in span .links :
@@ -345,91 +346,39 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
345346 port = span .attributes [SpanAttributes .NET_PEER_PORT ]
346347 # TODO: check default port for rpc
347348 # This logic assumes default ports never conflict across dependency types
348- # type: ignore
349- if port != _get_default_port_http (str (span .attributes .get (SpanAttributes .HTTP_SCHEME ))) and \
350- port != _get_default_port_db (str (span .attributes .get (SpanAttributes .DB_SYSTEM ))):
349+ # type: ignore
350+ if port != trace_utils ._get_default_port_http (
351+ str (span .attributes .get (SpanAttributes .HTTP_SCHEME ))) and \
352+ port != trace_utils ._get_default_port_db (str (span .attributes .get (SpanAttributes .DB_SYSTEM ))):
351353 target = "{}:{}" .format (target , port )
352354 if span .kind is SpanKind .CLIENT :
353355 if _AZURE_SDK_NAMESPACE_NAME in span .attributes : # Azure specific resources
354356 # Currently only eventhub and servicebus are supported
355357 # https://github.com/Azure/azure-sdk-for-python/issues/9256
356358 data .type = span .attributes [_AZURE_SDK_NAMESPACE_NAME ]
357- data .target = _get_azure_sdk_target_source (span .attributes )
359+ data .target = trace_utils . _get_azure_sdk_target_source (span .attributes )
358360 elif SpanAttributes .HTTP_METHOD in span .attributes : # HTTP
359361 data .type = "HTTP"
360362 if SpanAttributes .HTTP_USER_AGENT in span .attributes :
361363 # TODO: Not exposed in Swagger, need to update def
362364 envelope .tags ["ai.user.userAgent" ] = span .attributes [SpanAttributes .HTTP_USER_AGENT ]
363- scheme = span .attributes .get (SpanAttributes .HTTP_SCHEME )
364- # url
365- url = None
366- if SpanAttributes .HTTP_URL in span .attributes :
367- url = span .attributes [SpanAttributes .HTTP_URL ]
368- elif scheme and SpanAttributes .HTTP_TARGET in span .attributes :
369- http_target = span .attributes [SpanAttributes .HTTP_TARGET ]
370- if SpanAttributes .HTTP_HOST in span .attributes :
371- url = "{}://{}{}" .format (
372- str (scheme ),
373- span .attributes [SpanAttributes .HTTP_HOST ],
374- http_target ,
375- )
376- elif SpanAttributes .NET_PEER_PORT in span .attributes :
377- peer_port = span .attributes [SpanAttributes .NET_PEER_PORT ]
378- if SpanAttributes .NET_PEER_NAME in span .attributes :
379- peer_name = span .attributes [SpanAttributes .NET_PEER_NAME ]
380- url = "{}://{}:{}{}" .format (
381- scheme ,
382- peer_name ,
383- peer_port ,
384- http_target ,
385- )
386- elif SpanAttributes .NET_PEER_IP in span .attributes :
387- peer_ip = span .attributes [SpanAttributes .NET_PEER_IP ]
388- url = "{}://{}:{}{}" .format (
389- scheme ,
390- peer_ip ,
391- peer_port ,
392- http_target ,
393- )
394- target_from_url = None
395- path = ""
365+ scheme = trace_utils ._get_scheme_for_http_dependency (span .attributes )
366+ url = trace_utils ._get_url_for_http_dependency (scheme , span .attributes )
367+ # data
396368 if url :
397- try :
398- parse_url = urlparse (url )
399- path = parse_url .path
400- if not path :
401- path = "/"
402- if parse_url .port and parse_url .port == _get_default_port_http (str (scheme )):
403- target_from_url = parse_url .hostname
404- else :
405- target_from_url = parse_url .netloc
406- except Exception : # pylint: disable=broad-except
407- pass
369+ data .data = url
370+ target , path = trace_utils ._get_target_and_path_for_http_dependency (
371+ target , # type: ignore
372+ url ,
373+ scheme ,
374+ span .attributes ,
375+ )
408376 # http specific logic for name
409377 if path :
410378 data .name = "{} {}" .format (
411379 span .attributes [SpanAttributes .HTTP_METHOD ],
412380 path ,
413381 )
414- # http specific logic for target
415- if SpanAttributes .PEER_SERVICE not in span .attributes :
416- if SpanAttributes .HTTP_HOST in span .attributes :
417- host = span .attributes [SpanAttributes .HTTP_HOST ]
418- try :
419- # urlparse insists on absolute URLs starting with "//"
420- # This logic assumes host does not include a "//"
421- host_name = urlparse ("//" + str (host ))
422- if host_name .port == _get_default_port_http (str (scheme )):
423- target = host_name .hostname
424- else :
425- target = host
426- except Exception : # pylint: disable=broad-except
427- _logger .warning ("Error while parsing hostname." )
428- elif target_from_url :
429- target = target_from_url
430- # data is url
431- if url :
432- data .data = url
433382 status_code = span .attributes .get (SpanAttributes .HTTP_STATUS_CODE )
434383 if status_code :
435384 try :
@@ -449,7 +398,7 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
449398 data .type = "mongodb"
450399 elif db_system == DbSystemValues .REDIS .value :
451400 data .type = "redis"
452- elif _is_sql_db (str (db_system )):
401+ elif trace_utils . _is_sql_db (str (db_system )):
453402 data .type = "SQL"
454403 else :
455404 data .type = db_system
@@ -459,42 +408,39 @@ def _convert_span_to_envelope(span: ReadableSpan) -> TelemetryItem:
459408 elif SpanAttributes .DB_OPERATION in span .attributes :
460409 data .data = span .attributes [SpanAttributes .DB_OPERATION ]
461410 # db specific logic for target
462- if SpanAttributes .DB_NAME in span .attributes :
463- db_name = span .attributes [SpanAttributes .DB_NAME ]
464- if target is None :
465- target = db_name
466- else :
467- target = "{}|{}" .format (target , db_name )
468- if target is None :
469- target = db_system
411+ target = trace_utils ._get_target_for_db_dependency (
412+ target , # type: ignore
413+ db_system , # type: ignore
414+ span .attributes ,
415+ )
470416 elif SpanAttributes .MESSAGING_SYSTEM in span .attributes : # Messaging
471417 data .type = span .attributes [SpanAttributes .MESSAGING_SYSTEM ]
472- if target is None :
473- if SpanAttributes .MESSAGING_DESTINATION in span .attributes :
474- target = span .attributes [SpanAttributes .MESSAGING_DESTINATION ]
475- else :
476- target = span .attributes [SpanAttributes .MESSAGING_SYSTEM ]
418+ target = trace_utils ._get_target_for_messaging_dependency (
419+ target , # type: ignore
420+ span .attributes ,
421+ )
477422 elif SpanAttributes .RPC_SYSTEM in span .attributes : # Rpc
478423 data .type = SpanAttributes .RPC_SYSTEM
479- if target is None :
480- target = span .attributes [SpanAttributes .RPC_SYSTEM ]
424+ target = trace_utils ._get_target_for_rpc_dependency (
425+ target , # type: ignore
426+ span .attributes ,
427+ )
481428 else :
482429 data .type = "N/A"
483430 elif span .kind is SpanKind .PRODUCER : # Messaging
484431 # Currently only eventhub and servicebus are supported that produce PRODUCER spans
485432 if _AZURE_SDK_NAMESPACE_NAME in span .attributes :
486433 data .type = "Queue Message | {}" .format (span .attributes [_AZURE_SDK_NAMESPACE_NAME ])
487- data . target = _get_azure_sdk_target_source (span .attributes )
434+ target = trace_utils . _get_azure_sdk_target_source (span .attributes )
488435 else :
489436 data .type = "Queue Message"
490437 msg_system = span .attributes .get (SpanAttributes .MESSAGING_SYSTEM )
491438 if msg_system :
492439 data .type += " | {}" .format (msg_system )
493- if target is None :
494- if SpanAttributes .MESSAGING_DESTINATION in span .attributes :
495- target = span .attributes [SpanAttributes .MESSAGING_DESTINATION ]
496- else :
497- target = msg_system
440+ target = trace_utils ._get_target_for_messaging_dependency (
441+ target , # type: ignore
442+ span .attributes ,
443+ )
498444 else : # SpanKind.INTERNAL
499445 data .type = "InProc"
500446 if _AZURE_SDK_NAMESPACE_NAME in span .attributes :
@@ -596,54 +542,6 @@ def _convert_span_events_to_envelopes(span: ReadableSpan) -> Sequence[TelemetryI
596542
597543 return envelopes
598544
599- # pylint:disable=too-many-return-statements
600- def _get_default_port_db (db_system : str ) -> int :
601- if db_system == DbSystemValues .POSTGRESQL .value :
602- return 5432
603- if db_system == DbSystemValues .CASSANDRA .value :
604- return 9042
605- if db_system in (DbSystemValues .MARIADB .value , DbSystemValues .MYSQL .value ):
606- return 3306
607- if db_system == DbSystemValues .MSSQL .value :
608- return 1433
609- # TODO: Add in memcached
610- if db_system == "memcached" :
611- return 11211
612- if db_system == DbSystemValues .DB2 .value :
613- return 50000
614- if db_system == DbSystemValues .ORACLE .value :
615- return 1521
616- if db_system == DbSystemValues .H2 .value :
617- return 8082
618- if db_system == DbSystemValues .DERBY .value :
619- return 1527
620- if db_system == DbSystemValues .REDIS .value :
621- return 6379
622- return 0
623-
624-
625- def _get_default_port_http (scheme : str ) -> int :
626- if scheme == "http" :
627- return 80
628- if scheme == "https" :
629- return 443
630- return 0
631-
632-
633- def _is_sql_db (db_system : str ) -> bool :
634- return db_system in (
635- DbSystemValues .DB2 .value ,
636- DbSystemValues .DERBY .value ,
637- DbSystemValues .MARIADB .value ,
638- DbSystemValues .MSSQL .value ,
639- DbSystemValues .ORACLE .value ,
640- DbSystemValues .SQLITE .value ,
641- DbSystemValues .OTHER_SQL .value ,
642- # spell-checker:ignore HSQLDB
643- DbSystemValues .HSQLDB .value ,
644- DbSystemValues .H2 .value ,
645- )
646-
647545
648546def _check_instrumentation_span (span : ReadableSpan ) -> None :
649547 # Special use-case for spans generated from azure-sdk services
@@ -669,16 +567,6 @@ def _is_standard_attribute(key: str) -> bool:
669567 return key in _STANDARD_AZURE_MONITOR_ATTRIBUTES
670568
671569
672- def _get_azure_sdk_target_source (attributes : Attributes ) -> Optional [str ]:
673- # Currently logic only works for ServiceBus and EventHub
674- if attributes :
675- peer_address = attributes .get ("peer.address" )
676- destination = attributes .get ("message_bus.destination" )
677- if peer_address and destination :
678- return str (peer_address ) + "/" + str (destination )
679- return None
680-
681-
682570def _get_trace_export_result (result : ExportResult ) -> SpanExportResult :
683571 if result == ExportResult .SUCCESS :
684572 return SpanExportResult .SUCCESS
0 commit comments