@@ -176,7 +176,13 @@ def response_hook(span, request, response):
176
176
from opentelemetry .trace import SpanKind , TracerProvider , get_tracer
177
177
from opentelemetry .trace .span import Span
178
178
from opentelemetry .trace .status import Status
179
+ from opentelemetry .utils .http import (
180
+ ExcludeList ,
181
+ get_excluded_urls ,
182
+ parse_excluded_urls ,
183
+ )
179
184
185
+ _excluded_urls_from_env = get_excluded_urls ("HTTPX" )
180
186
_logger = logging .getLogger (__name__ )
181
187
182
188
URL = typing .Tuple [bytes , bytes , typing .Optional [int ], bytes ]
@@ -276,6 +282,7 @@ class SyncOpenTelemetryTransport(httpx.BaseTransport):
276
282
right after the span is created
277
283
response_hook: A hook that receives the span, request, and response
278
284
that is called right before the span ends
285
+ excluded_urls: List of urls that should be excluded from tracing
279
286
"""
280
287
281
288
def __init__ (
@@ -284,6 +291,7 @@ def __init__(
284
291
tracer_provider : typing .Optional [TracerProvider ] = None ,
285
292
request_hook : typing .Optional [RequestHook ] = None ,
286
293
response_hook : typing .Optional [ResponseHook ] = None ,
294
+ excluded_urls : typing .Optional [ExcludeList ] = None ,
287
295
):
288
296
self ._transport = transport
289
297
self ._tracer = get_tracer (
@@ -293,6 +301,7 @@ def __init__(
293
301
)
294
302
self ._request_hook = request_hook
295
303
self ._response_hook = response_hook
304
+ self ._excluded_urls = excluded_urls
296
305
297
306
def __enter__ (self ) -> "SyncOpenTelemetryTransport" :
298
307
self ._transport .__enter__ ()
@@ -315,12 +324,16 @@ def handle_request(
315
324
httpx .Response ,
316
325
]:
317
326
"""Add request info to span."""
318
- if context .get_value ("suppress_instrumentation" ):
319
- return self ._transport .handle_request (* args , ** kwargs )
320
-
321
327
method , url , headers , stream , extensions = _extract_parameters (
322
328
args , kwargs
323
329
)
330
+
331
+ if self ._excluded_urls and self ._excluded_urls .url_disabled (url ):
332
+ return self ._transport .handle_request (* args , ** kwargs )
333
+
334
+ if context .get_value ("suppress_instrumentation" ):
335
+ return self ._transport .handle_request (* args , ** kwargs )
336
+
324
337
span_attributes = _prepare_attributes (method , url )
325
338
326
339
request_info = RequestInfo (method , url , headers , stream , extensions )
@@ -370,6 +383,7 @@ class AsyncOpenTelemetryTransport(httpx.AsyncBaseTransport):
370
383
right after the span is created
371
384
response_hook: A hook that receives the span, request, and response
372
385
that is called right before the span ends
386
+ excluded_urls: List of urls that should be excluded from tracing
373
387
"""
374
388
375
389
def __init__ (
@@ -378,6 +392,7 @@ def __init__(
378
392
tracer_provider : typing .Optional [TracerProvider ] = None ,
379
393
request_hook : typing .Optional [RequestHook ] = None ,
380
394
response_hook : typing .Optional [ResponseHook ] = None ,
395
+ excluded_urls : typing .Optional [ExcludeList ] = None ,
381
396
):
382
397
self ._transport = transport
383
398
self ._tracer = get_tracer (
@@ -387,6 +402,7 @@ def __init__(
387
402
)
388
403
self ._request_hook = request_hook
389
404
self ._response_hook = response_hook
405
+ self ._excluded_urls = excluded_urls
390
406
391
407
async def __aenter__ (self ) -> "AsyncOpenTelemetryTransport" :
392
408
await self ._transport .__aenter__ ()
@@ -407,12 +423,16 @@ async def handle_async_request(
407
423
httpx .Response ,
408
424
]:
409
425
"""Add request info to span."""
410
- if context .get_value ("suppress_instrumentation" ):
411
- return await self ._transport .handle_async_request (* args , ** kwargs )
412
-
413
426
method , url , headers , stream , extensions = _extract_parameters (
414
427
args , kwargs
415
428
)
429
+
430
+ if self ._excluded_urls and self ._excluded_urls .url_disabled (url ):
431
+ return await self ._transport .handle_async_request (* args , ** kwargs )
432
+
433
+ if context .get_value ("suppress_instrumentation" ):
434
+ return await self ._transport .handle_async_request (* args , ** kwargs )
435
+
416
436
span_attributes = _prepare_attributes (method , url )
417
437
418
438
span_name = _get_default_span_name (
@@ -459,6 +479,7 @@ class _InstrumentedClient(httpx.Client):
459
479
_tracer_provider = None
460
480
_request_hook = None
461
481
_response_hook = None
482
+ _excluded_urls = None
462
483
463
484
def __init__ (self , * args , ** kwargs ):
464
485
super ().__init__ (* args , ** kwargs )
@@ -478,6 +499,7 @@ class _InstrumentedAsyncClient(httpx.AsyncClient):
478
499
_tracer_provider = None
479
500
_request_hook = None
480
501
_response_hook = None
502
+ _excluded_urls = None
481
503
482
504
def __init__ (self , * args , ** kwargs ):
483
505
super ().__init__ (* args , ** kwargs )
@@ -513,11 +535,18 @@ def _instrument(self, **kwargs):
513
535
right after the span is created
514
536
``response_hook``: A hook that receives the span, request, and response
515
537
that is called right before the span ends
538
+ ``excluded_urls``: A string containing a comma-delimited
539
+ list of regexes used to exclude URLs from tracking
516
540
"""
517
541
self ._original_client = httpx .Client
518
542
self ._original_async_client = httpx .AsyncClient
519
543
request_hook = kwargs .get ("request_hook" )
520
544
response_hook = kwargs .get ("response_hook" )
545
+ excluded_urls = kwargs .get ("excluded_urls" )
546
+ if excluded_urls is None :
547
+ excluded_urls = _excluded_urls_from_env
548
+ else :
549
+ excluded_urls = parse_excluded_urls (excluded_urls )
521
550
if callable (request_hook ):
522
551
_InstrumentedClient ._request_hook = request_hook
523
552
_InstrumentedAsyncClient ._request_hook = request_hook
0 commit comments