62
62
63
63
# FIXME: fix the importing of this private attribute when the location of the _SUPPRESS_HTTP_INSTRUMENTATION_KEY is defined.
64
64
from opentelemetry .context import _SUPPRESS_HTTP_INSTRUMENTATION_KEY
65
+ from opentelemetry .instrumentation ._semconv import (
66
+ _METRIC_ATTRIBUTES_CLIENT_DURATION_NAME ,
67
+ _SPAN_ATTRIBUTES_ERROR_TYPE ,
68
+ _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS ,
69
+ _SPAN_ATTRIBUTES_NETWORK_PEER_PORT ,
70
+ _filter_duration_attrs ,
71
+ _get_schema_url ,
72
+ _OpenTelemetrySemanticConventionStability ,
73
+ _OpenTelemetryStabilityMode ,
74
+ _OpenTelemetryStabilitySignalType ,
75
+ _report_new ,
76
+ _report_old ,
77
+ _set_http_hostname ,
78
+ _set_http_method ,
79
+ _set_http_net_peer_name ,
80
+ _set_http_network_protocol_version ,
81
+ _set_http_port ,
82
+ _set_http_scheme ,
83
+ _set_http_status_code ,
84
+ _set_http_url ,
85
+ )
65
86
from opentelemetry .instrumentation .instrumentor import BaseInstrumentor
66
87
from opentelemetry .instrumentation .requests .package import _instruments
67
88
from opentelemetry .instrumentation .requests .version import __version__
72
93
from opentelemetry .metrics import Histogram , get_meter
73
94
from opentelemetry .propagate import inject
74
95
from opentelemetry .semconv .metrics import MetricInstruments
75
- from opentelemetry .semconv .trace import SpanAttributes
76
96
from opentelemetry .trace import SpanKind , Tracer , get_tracer
77
97
from opentelemetry .trace .span import Span
78
- from opentelemetry .trace .status import Status
98
+ from opentelemetry .trace .status import StatusCode
79
99
from opentelemetry .util .http import (
80
100
ExcludeList ,
81
101
get_excluded_urls ,
82
102
parse_excluded_urls ,
83
103
remove_url_credentials ,
104
+ sanitize_method ,
84
105
)
85
106
from opentelemetry .util .http .httplib import set_ip_on_next_http_connection
86
107
94
115
# pylint: disable=R0915
95
116
def _instrument (
96
117
tracer : Tracer ,
97
- duration_histogram : Histogram ,
118
+ duration_histogram_old : Histogram ,
119
+ duration_histogram_new : Histogram ,
98
120
request_hook : _RequestHookT = None ,
99
121
response_hook : _ResponseHookT = None ,
100
122
excluded_urls : ExcludeList = None ,
123
+ sem_conv_opt_in_mode : _OpenTelemetryStabilityMode = _OpenTelemetryStabilityMode .DEFAULT ,
101
124
):
102
125
"""Enables tracing of all requests calls that go through
103
126
:code:`requests.session.Session.request` (this includes
@@ -132,31 +155,58 @@ def get_or_create_headers():
132
155
return wrapped_send (self , request , ** kwargs )
133
156
134
157
# See
135
- # https://github.com/open-telemetry/opentelemetry-specification /blob/main/specification/trace/semantic_conventions/ http.md#http-client
136
- method = request .method . upper ()
158
+ # https://github.com/open-telemetry/semantic-conventions /blob/main/docs/http/ http-spans .md#http-client
159
+ method = request .method
137
160
span_name = get_default_span_name (method )
138
161
139
162
url = remove_url_credentials (request .url )
140
163
141
- span_attributes = {
142
- SpanAttributes .HTTP_METHOD : method ,
143
- SpanAttributes .HTTP_URL : url ,
144
- }
164
+ span_attributes = {}
165
+ _set_http_method (
166
+ span_attributes , method , span_name , sem_conv_opt_in_mode
167
+ )
168
+ _set_http_url (span_attributes , url , sem_conv_opt_in_mode )
145
169
146
- metric_labels = {
147
- SpanAttributes .HTTP_METHOD : method ,
148
- }
170
+ metric_labels = {}
171
+ _set_http_method (
172
+ metric_labels , method , span_name , sem_conv_opt_in_mode
173
+ )
149
174
150
175
try :
151
176
parsed_url = urlparse (url )
152
- metric_labels [SpanAttributes .HTTP_SCHEME ] = parsed_url .scheme
177
+ if parsed_url .scheme :
178
+ _set_http_scheme (
179
+ metric_labels , parsed_url .scheme , sem_conv_opt_in_mode
180
+ )
153
181
if parsed_url .hostname :
154
- metric_labels [SpanAttributes .HTTP_HOST ] = parsed_url .hostname
155
- metric_labels [
156
- SpanAttributes .NET_PEER_NAME
157
- ] = parsed_url .hostname
182
+ _set_http_hostname (
183
+ metric_labels , parsed_url .hostname , sem_conv_opt_in_mode
184
+ )
185
+ _set_http_net_peer_name (
186
+ metric_labels , parsed_url .hostname , sem_conv_opt_in_mode
187
+ )
188
+ if _report_new (sem_conv_opt_in_mode ):
189
+ _set_http_hostname (
190
+ span_attributes ,
191
+ parsed_url .hostname ,
192
+ sem_conv_opt_in_mode ,
193
+ )
194
+ # Use semconv library when available
195
+ span_attributes [
196
+ _SPAN_ATTRIBUTES_NETWORK_PEER_ADDRESS
197
+ ] = parsed_url .hostname
158
198
if parsed_url .port :
159
- metric_labels [SpanAttributes .NET_PEER_PORT ] = parsed_url .port
199
+ _set_http_port (
200
+ metric_labels , parsed_url .port , sem_conv_opt_in_mode
201
+ )
202
+ if _report_new (sem_conv_opt_in_mode ):
203
+ _set_http_port (
204
+ span_attributes , parsed_url .port , sem_conv_opt_in_mode
205
+ )
206
+ # Use semconv library when available
207
+ span_attributes [
208
+ _SPAN_ATTRIBUTES_NETWORK_PEER_PORT
209
+ ] = parsed_url .port
160
210
except ValueError :
161
211
pass
162
212
@@ -182,35 +232,78 @@ def get_or_create_headers():
182
232
exception = exc
183
233
result = getattr (exc , "response" , None )
184
234
finally :
185
- elapsed_time = max (
186
- round ((default_timer () - start_time ) * 1000 ), 0
187
- )
235
+ elapsed_time = max (default_timer () - start_time , 0 )
188
236
context .detach (token )
189
237
190
238
if isinstance (result , Response ):
239
+ span_attributes = {}
191
240
if span .is_recording ():
192
- span .set_attribute (
193
- SpanAttributes .HTTP_STATUS_CODE , result .status_code
241
+ _set_http_status_code (
242
+ span_attributes ,
243
+ result .status_code ,
244
+ sem_conv_opt_in_mode ,
194
245
)
195
- span . set_status (
196
- Status ( http_status_to_status_code ( result .status_code ))
246
+ _set_http_status_code (
247
+ metric_labels , result .status_code , sem_conv_opt_in_mode
197
248
)
198
-
199
- metric_labels [
200
- SpanAttributes .HTTP_STATUS_CODE
201
- ] = result .status_code
249
+ status_code = http_status_to_status_code (
250
+ result .status_code
251
+ )
252
+ span .set_status (status_code )
253
+ if (
254
+ _report_new (sem_conv_opt_in_mode )
255
+ and status_code is StatusCode .ERROR
256
+ ):
257
+ span_attributes [_SPAN_ATTRIBUTES_ERROR_TYPE ] = str (
258
+ result .status_code
259
+ )
260
+ metric_labels [_SPAN_ATTRIBUTES_ERROR_TYPE ] = str (
261
+ result .status_code
262
+ )
202
263
203
264
if result .raw is not None :
204
265
version = getattr (result .raw , "version" , None )
205
266
if version :
206
- metric_labels [SpanAttributes .HTTP_FLAVOR ] = (
207
- "1.1" if version == 11 else "1.0"
267
+ # Only HTTP/1 is supported by requests
268
+ version_text = "1.1" if version == 11 else "1.0"
269
+ _set_http_network_protocol_version (
270
+ metric_labels , version_text , sem_conv_opt_in_mode
208
271
)
272
+ if _report_new (sem_conv_opt_in_mode ):
273
+ _set_http_network_protocol_version (
274
+ span_attributes ,
275
+ version_text ,
276
+ sem_conv_opt_in_mode ,
277
+ )
278
+ for key , val in span_attributes .items ():
279
+ span .set_attribute (key , val )
209
280
210
281
if callable (response_hook ):
211
282
response_hook (span , request , result )
212
283
213
- duration_histogram .record (elapsed_time , attributes = metric_labels )
284
+ if exception is not None and _report_new (sem_conv_opt_in_mode ):
285
+ span .set_attribute (
286
+ _SPAN_ATTRIBUTES_ERROR_TYPE , type (exception ).__qualname__
287
+ )
288
+ metric_labels [_SPAN_ATTRIBUTES_ERROR_TYPE ] = type (
289
+ exception
290
+ ).__qualname__
291
+
292
+ if duration_histogram_old is not None :
293
+ duration_attrs_old = _filter_duration_attrs (
294
+ metric_labels , _OpenTelemetryStabilityMode .DEFAULT
295
+ )
296
+ duration_histogram_old .record (
297
+ max (round (elapsed_time * 1000 ), 0 ),
298
+ attributes = duration_attrs_old ,
299
+ )
300
+ if duration_histogram_new is not None :
301
+ duration_attrs_new = _filter_duration_attrs (
302
+ metric_labels , _OpenTelemetryStabilityMode .HTTP
303
+ )
304
+ duration_histogram_new .record (
305
+ elapsed_time , attributes = duration_attrs_new
306
+ )
214
307
215
308
if exception is not None :
216
309
raise exception .with_traceback (exception .__traceback__ )
@@ -254,7 +347,7 @@ def get_default_span_name(method):
254
347
Returns:
255
348
span name
256
349
"""
257
- return method .strip ()
350
+ return sanitize_method ( method .upper (). strip () )
258
351
259
352
260
353
class RequestsInstrumentor (BaseInstrumentor ):
@@ -276,34 +369,49 @@ def _instrument(self, **kwargs):
276
369
``excluded_urls``: A string containing a comma-delimited
277
370
list of regexes used to exclude URLs from tracking
278
371
"""
372
+ semconv_opt_in_mode = _OpenTelemetrySemanticConventionStability ._get_opentelemetry_stability_opt_in_mode (
373
+ _OpenTelemetryStabilitySignalType .HTTP ,
374
+ )
375
+ schema_url = _get_schema_url (semconv_opt_in_mode )
279
376
tracer_provider = kwargs .get ("tracer_provider" )
280
377
tracer = get_tracer (
281
378
__name__ ,
282
379
__version__ ,
283
380
tracer_provider ,
284
- schema_url = "https://opentelemetry.io/schemas/1.11.0" ,
381
+ schema_url = schema_url ,
285
382
)
286
383
excluded_urls = kwargs .get ("excluded_urls" )
287
384
meter_provider = kwargs .get ("meter_provider" )
288
385
meter = get_meter (
289
386
__name__ ,
290
387
__version__ ,
291
388
meter_provider ,
292
- schema_url = "https://opentelemetry.io/schemas/1.11.0" ,
293
- )
294
- duration_histogram = meter .create_histogram (
295
- name = MetricInstruments .HTTP_CLIENT_DURATION ,
296
- unit = "ms" ,
297
- description = "measures the duration of the outbound HTTP request" ,
389
+ schema_url = schema_url ,
298
390
)
391
+ duration_histogram_old = None
392
+ if _report_old (semconv_opt_in_mode ):
393
+ duration_histogram_old = meter .create_histogram (
394
+ name = MetricInstruments .HTTP_CLIENT_DURATION ,
395
+ unit = "ms" ,
396
+ description = "measures the duration of the outbound HTTP request" ,
397
+ )
398
+ duration_histogram_new = None
399
+ if _report_new (semconv_opt_in_mode ):
400
+ duration_histogram_new = meter .create_histogram (
401
+ name = _METRIC_ATTRIBUTES_CLIENT_DURATION_NAME ,
402
+ unit = "s" ,
403
+ description = "Duration of HTTP client requests." ,
404
+ )
299
405
_instrument (
300
406
tracer ,
301
- duration_histogram ,
407
+ duration_histogram_old ,
408
+ duration_histogram_new ,
302
409
request_hook = kwargs .get ("request_hook" ),
303
410
response_hook = kwargs .get ("response_hook" ),
304
411
excluded_urls = _excluded_urls_from_env
305
412
if excluded_urls is None
306
413
else parse_excluded_urls (excluded_urls ),
414
+ sem_conv_opt_in_mode = semconv_opt_in_mode ,
307
415
)
308
416
309
417
def _uninstrument (self , ** kwargs ):
0 commit comments