@@ -234,7 +234,13 @@ async def async_response_hook(span, request, response):
234234from opentelemetry .trace .span import Span
235235from opentelemetry .trace .status import StatusCode
236236from opentelemetry .util .http import remove_url_credentials , sanitize_method
237+ from opentelemetry .utils .http import (
238+ ExcludeList ,
239+ get_excluded_urls ,
240+ parse_excluded_urls ,
241+ )
237242
243+ _excluded_urls_from_env = get_excluded_urls ("HTTPX" )
238244_logger = logging .getLogger (__name__ )
239245
240246RequestHook = typing .Callable [[Span , "RequestInfo" ], None ]
@@ -411,6 +417,7 @@ class SyncOpenTelemetryTransport(httpx.BaseTransport):
411417 right after the span is created
412418 response_hook: A hook that receives the span, request, and response
413419 that is called right before the span ends
420+ excluded_urls: List of urls that should be excluded from tracing
414421 """
415422
416423 def __init__ (
@@ -419,6 +426,7 @@ def __init__(
419426 tracer_provider : TracerProvider | None = None ,
420427 request_hook : RequestHook | None = None ,
421428 response_hook : ResponseHook | None = None ,
429+ excluded_urls : ExcludeList | None = None ,
422430 ):
423431 _OpenTelemetrySemanticConventionStability ._initialize ()
424432 self ._sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability ._get_opentelemetry_stability_opt_in_mode (
@@ -434,6 +442,7 @@ def __init__(
434442 )
435443 self ._request_hook = request_hook
436444 self ._response_hook = response_hook
445+ self ._excluded_urls = excluded_urls
437446
438447 def __enter__ (self ) -> SyncOpenTelemetryTransport :
439448 self ._transport .__enter__ ()
@@ -459,10 +468,13 @@ def handle_request(
459468 """Add request info to span."""
460469 if not is_http_instrumentation_enabled ():
461470 return self ._transport .handle_request (* args , ** kwargs )
462-
463471 method , url , headers , stream , extensions = _extract_parameters (
464472 args , kwargs
465473 )
474+
475+ if self ._excluded_urls and self ._excluded_urls .url_disabled (url ):
476+ return self ._transport .handle_request (* args , ** kwargs )
477+
466478 method_original = method .decode ()
467479 span_name = _get_default_span_name (method_original )
468480 span_attributes = {}
@@ -536,6 +548,7 @@ class AsyncOpenTelemetryTransport(httpx.AsyncBaseTransport):
536548 right after the span is created
537549 response_hook: A hook that receives the span, request, and response
538550 that is called right before the span ends
551+ excluded_urls: List of urls that should be excluded from tracing
539552 """
540553
541554 def __init__ (
@@ -544,6 +557,7 @@ def __init__(
544557 tracer_provider : TracerProvider | None = None ,
545558 request_hook : AsyncRequestHook | None = None ,
546559 response_hook : AsyncResponseHook | None = None ,
560+ excluded_urls : ExcludeList | None = None ,
547561 ):
548562 _OpenTelemetrySemanticConventionStability ._initialize ()
549563 self ._sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability ._get_opentelemetry_stability_opt_in_mode (
@@ -559,6 +573,7 @@ def __init__(
559573 )
560574 self ._request_hook = request_hook
561575 self ._response_hook = response_hook
576+ self ._excluded_urls = excluded_urls
562577
563578 async def __aenter__ (self ) -> "AsyncOpenTelemetryTransport" :
564579 await self ._transport .__aenter__ ()
@@ -586,6 +601,13 @@ async def handle_async_request(
586601 method , url , headers , stream , extensions = _extract_parameters (
587602 args , kwargs
588603 )
604+
605+ if self ._excluded_urls and self ._excluded_urls .url_disabled (url ):
606+ return await self ._transport .handle_async_request (* args , ** kwargs )
607+
608+ if context .get_value ("suppress_instrumentation" ):
609+ return await self ._transport .handle_async_request (* args , ** kwargs )
610+
589611 method_original = method .decode ()
590612 span_name = _get_default_span_name (method_original )
591613 span_attributes = {}
@@ -674,6 +696,8 @@ def _instrument(self, **kwargs: typing.Any):
674696 and response that is called right before the span ends
675697 ``async_request_hook``: Async ``request_hook`` for ``httpx.AsyncClient``
676698 ``async_response_hook``: Async``response_hook`` for ``httpx.AsyncClient``
699+ ``excluded_urls``: A string containing a comma-delimited
700+ list of regexes used to exclude URLs from tracking
677701 """
678702 tracer_provider = kwargs .get ("tracer_provider" )
679703 request_hook = kwargs .get ("request_hook" )
@@ -690,6 +714,12 @@ def _instrument(self, **kwargs: typing.Any):
690714 if iscoroutinefunction (async_response_hook )
691715 else None
692716 )
717+
718+ excluded_urls = kwargs .get ("excluded_urls" )
719+ if excluded_urls is None :
720+ excluded_urls = _excluded_urls_from_env
721+ else :
722+ excluded_urls = parse_excluded_urls (excluded_urls )
693723
694724 _OpenTelemetrySemanticConventionStability ._initialize ()
695725 sem_conv_opt_in_mode = _OpenTelemetrySemanticConventionStability ._get_opentelemetry_stability_opt_in_mode (
@@ -711,6 +741,7 @@ def _instrument(self, **kwargs: typing.Any):
711741 sem_conv_opt_in_mode = sem_conv_opt_in_mode ,
712742 request_hook = request_hook ,
713743 response_hook = response_hook ,
744+ excluded_urls = excluded_urls ,
714745 ),
715746 )
716747 wrap_function_wrapper (
@@ -722,6 +753,7 @@ def _instrument(self, **kwargs: typing.Any):
722753 sem_conv_opt_in_mode = sem_conv_opt_in_mode ,
723754 async_request_hook = async_request_hook ,
724755 async_response_hook = async_response_hook ,
756+ excluded_urls = excluded_urls ,
725757 ),
726758 )
727759
@@ -739,13 +771,18 @@ def _handle_request_wrapper( # pylint: disable=too-many-locals
739771 sem_conv_opt_in_mode : _StabilityMode ,
740772 request_hook : RequestHook ,
741773 response_hook : ResponseHook ,
774+ excluded_urls : ExcludeList | None = None ,
742775 ):
743776 if not is_http_instrumentation_enabled ():
744777 return wrapped (* args , ** kwargs )
745778
746779 method , url , headers , stream , extensions = _extract_parameters (
747780 args , kwargs
748781 )
782+
783+ if excluded_urls and excluded_urls .url_disabled (url ):
784+ return wrapeed (* args , ** kwargs )
785+
749786 method_original = method .decode ()
750787 span_name = _get_default_span_name (method_original )
751788 span_attributes = {}
@@ -813,13 +850,18 @@ async def _handle_async_request_wrapper( # pylint: disable=too-many-locals
813850 sem_conv_opt_in_mode : _StabilityMode ,
814851 async_request_hook : AsyncRequestHook ,
815852 async_response_hook : AsyncResponseHook ,
853+ excluded_urls : ExcludeList | None = None ,
816854 ):
817855 if not is_http_instrumentation_enabled ():
818856 return await wrapped (* args , ** kwargs )
819857
820858 method , url , headers , stream , extensions = _extract_parameters (
821859 args , kwargs
822860 )
861+
862+ if excluded_urls and excluded_urls .url_disabled (url ):
863+ return await wrapeed (* args , ** kwargs )
864+
823865 method_original = method .decode ()
824866 span_name = _get_default_span_name (method_original )
825867 span_attributes = {}
0 commit comments