55
66import requests
77
8- import ddtrace
98from ddtrace import config
10- from ddtrace ._trace .pin import Pin
11- from ddtrace .constants import _SPAN_MEASURED_KEY
129from ddtrace .constants import SPAN_KIND
1310from ddtrace .contrib import trace_utils
1411from ddtrace .contrib .internal .trace_utils import _sanitized_url
1512from ddtrace .ext import SpanKind
1613from ddtrace .ext import SpanTypes
14+ from ddtrace .internal import core
1715from ddtrace .internal .constants import COMPONENT
1816from ddtrace .internal .constants import USER_AGENT_HEADER
1917from ddtrace .internal .logger import get_logger
2018from ddtrace .internal .opentelemetry .constants import OTLP_EXPORTER_HEADER_IDENTIFIER
2119from ddtrace .internal .schema import schematize_url_operation
2220from ddtrace .internal .schema .span_attribute_schema import SpanDirection
23- from ddtrace .internal .settings .asm import config as asm_config
2421from ddtrace .internal .utils import get_argument_value
25- from ddtrace .propagation .http import HTTPPropagator
2622
2723
2824log = get_logger (__name__ )
@@ -69,18 +65,9 @@ def _extract_query_string(uri):
6965 return uri [start :end ]
7066
7167
72- def _wrap_send (func , instance , args , kwargs ):
68+ @trace_utils .with_traced_module
69+ def _wrap_send (_requests_mod , pin , func , instance , args , kwargs ):
7370 """Trace the `Session.send` instance method"""
74- # TODO[manu]: we already offer a way to provide the Global Tracer
75- # and is ddtrace.tracer; it's used only inside our tests and can
76- # be easily changed by providing a TracingTestCase that sets common
77- # tracing functionalities.
78- tracer = getattr (instance , "datadog_tracer" , ddtrace .tracer )
79-
80- # skip if tracing is not enabled
81- if not tracer .enabled and not asm_config ._apm_opt_out :
82- return func (* args , ** kwargs )
83-
8471 request = get_argument_value (args , kwargs , 0 , "request" )
8572 if not request or is_otlp_export (request ):
8673 return func (* args , ** kwargs )
@@ -92,59 +79,55 @@ def _wrap_send(func, instance, args, kwargs):
9279 hostname , path = _extract_hostname_and_path (url )
9380 host_without_port = hostname .split (":" )[0 ] if hostname is not None else None
9481
95- cfg : Dict [str , Any ] = {}
96- pin = Pin .get_from (instance )
97- if pin :
98- cfg = pin ._config
82+ parsed_uri = parse .urlparse (url )
9983
100- service = None
101- if cfg ["split_by_domain" ] and hostname :
102- service = hostname
103- if service is None :
104- service = cfg .get ("service" , None )
105- if service is None :
106- service = cfg .get ("service_name" , None )
107- if service is None :
108- service = trace_utils .ext_service (None , config .requests )
84+ # Support legacy datadog_tracer attribute for backwards compatibility (used in tests)
85+ # If not set, use ddtrace.tracer to respect override_global_tracer
86+ tracer = getattr (instance , "datadog_tracer" , None )
87+ if tracer is None :
88+ import ddtrace
10989
110- operation_name = schematize_url_operation ("requests.request" , protocol = "http" , direction = SpanDirection .OUTBOUND )
111- with tracer .trace (operation_name , service = service , resource = f"{ method } { path } " , span_type = SpanTypes .HTTP ) as span :
112- span ._set_tag_str (COMPONENT , config .requests .integration_name )
90+ tracer = ddtrace .tracer
11391
114- # set span.kind to the type of operation being performed
115- span . _set_tag_str ( SPAN_KIND , SpanKind . CLIENT )
92+ # Check if tracing is disabled on the tracer (for APM opt-out tests)
93+ from ddtrace . internal . settings . asm import config as asm_config
11694
117- # PERF: avoid setting via Span.set_tag
118- span . set_metric ( _SPAN_MEASURED_KEY , 1 )
95+ if not tracer . enabled and not asm_config . _apm_opt_out :
96+ return func ( * args , ** kwargs )
11997
120- # propagate distributed tracing headers
121- if cfg .get ("distributed_tracing" ):
122- HTTPPropagator .inject (span .context , request .headers )
98+ # Use pin's config if available, otherwise fall back to global config
99+ integration_config = pin ._config if pin else config .requests
123100
124- response = response_headers = None
101+ # Determine service name (check pin config for "service" or "service_name")
102+ service = None
103+ if integration_config and isinstance (integration_config , dict ):
104+ service = integration_config .get ("service" ) or integration_config .get ("service_name" )
105+ if service is None :
106+ service = trace_utils .ext_service (pin , config .requests )
107+
108+ with core .context_with_data (
109+ "requests.send" ,
110+ span_name = schematize_url_operation ("requests.request" , protocol = "http" , direction = SpanDirection .OUTBOUND ),
111+ pin = pin ,
112+ tracer = tracer ,
113+ service = service ,
114+ resource = f"{ method } { path } " ,
115+ span_type = SpanTypes .HTTP ,
116+ integration_config = integration_config ,
117+ measured = True ,
118+ tags = {COMPONENT : config .requests .integration_name , SPAN_KIND : SpanKind .CLIENT },
119+ request = request ,
120+ request_url = url ,
121+ request_method = method ,
122+ request_headers = request .headers ,
123+ hostname = hostname ,
124+ path = path ,
125+ host_without_port = host_without_port ,
126+ parsed_uri = parsed_uri ,
127+ ) as ctx :
128+ response = None
125129 try :
126130 response = func (* args , ** kwargs )
127131 return response
128132 finally :
129- try :
130- status = None
131- if response is not None :
132- status = response .status_code
133- # Storing response headers in the span.
134- # Note that response.headers is not a dict, but an iterable
135- # requests custom structure, that we convert to a dict
136- response_headers = dict (getattr (response , "headers" , {}))
137-
138- trace_utils .set_http_meta (
139- span ,
140- config .requests ,
141- request_headers = request .headers ,
142- response_headers = response_headers ,
143- method = method ,
144- url = request .url ,
145- target_host = host_without_port ,
146- status_code = status ,
147- query = _extract_query_string (url ),
148- )
149- except Exception :
150- log .debug ("requests: error adding tags" , exc_info = True )
133+ ctx .set_item ("response" , response )
0 commit comments