@@ -57,6 +57,97 @@ def response_hook(span, request_obj, response):
5757 request_hook=request_hook, response_hook=response_hook
5858 )
5959
60+ Capture HTTP request and response headers
61+ *****************************************
62+ You can configure the agent to capture specified HTTP headers as span attributes, according to the
63+ `semantic conventions <https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-client-span>`_.
64+
65+ Request headers
66+ ***************
67+ To capture HTTP request headers as span attributes, set the environment variable
68+ ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST`` to a comma delimited list of HTTP header names.
69+
70+ For example using the environment variable,
71+ ::
72+
73+ export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST="content-type,custom_request_header"
74+
75+ will extract ``content-type`` and ``custom_request_header`` from the request headers and add them as span attributes.
76+
77+ Request header names in Requests are case-insensitive. So, giving the header name as ``CUStom-Header`` in the environment
78+ variable will capture the header named ``custom-header``.
79+
80+ Regular expressions may also be used to match multiple headers that correspond to the given pattern. For example:
81+ ::
82+
83+ export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST="Accept.*,X-.*"
84+
85+ Would match all request headers that start with ``Accept`` and ``X-``.
86+
87+ To capture all request headers, set ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST`` to ``".*"``.
88+ ::
89+
90+ export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST=".*"
91+
92+ The name of the added span attribute will follow the format ``http.request.header.<header_name>`` where ``<header_name>``
93+ is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a
94+ single item list containing all the header values.
95+
96+ For example:
97+ ``http.request.header.custom_request_header = ["<value1>", "<value2>"]``
98+
99+ Response headers
100+ ****************
101+ To capture HTTP response headers as span attributes, set the environment variable
102+ ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE`` to a comma delimited list of HTTP header names.
103+
104+ For example using the environment variable,
105+ ::
106+
107+ export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE="content-type,custom_response_header"
108+
109+ will extract ``content-type`` and ``custom_response_header`` from the response headers and add them as span attributes.
110+
111+ Response header names in Requests are case-insensitive. So, giving the header name as ``CUStom-Header`` in the environment
112+ variable will capture the header named ``custom-header``.
113+
114+ Regular expressions may also be used to match multiple headers that correspond to the given pattern. For example:
115+ ::
116+
117+ export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE="Content.*,X-.*"
118+
119+ Would match all response headers that start with ``Content`` and ``X-``.
120+
121+ To capture all response headers, set ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE`` to ``".*"``.
122+ ::
123+
124+ export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE=".*"
125+
126+ The name of the added span attribute will follow the format ``http.response.header.<header_name>`` where ``<header_name>``
127+ is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a
128+ list containing the header values.
129+
130+ For example:
131+ ``http.response.header.custom_response_header = ["<value1>", "<value2>"]``
132+
133+ Sanitizing headers
134+ ******************
135+ In order to prevent storing sensitive data such as personally identifiable information (PII), session keys, passwords,
136+ etc, set the environment variable ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS``
137+ to a comma delimited list of HTTP header names to be sanitized.
138+
139+ Regexes may be used, and all header names will be matched in a case-insensitive manner.
140+
141+ For example using the environment variable,
142+ ::
143+
144+ export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS=".*session.*,set-cookie"
145+
146+ will replace the value of headers such as ``session-id`` and ``set-cookie`` with ``[REDACTED]`` in the span.
147+
148+ Note:
149+ The environment variable names used to capture HTTP headers are still experimental, and thus are subject to change.
150+
60151Custom Duration Histogram Boundaries
61152************************************
62153To customize the duration histogram bucket boundaries used for HTTP client request duration metrics,
@@ -150,9 +241,16 @@ def response_hook(span, request_obj, response):
150241from opentelemetry .trace import SpanKind , Tracer , get_tracer
151242from opentelemetry .trace .span import Span
152243from opentelemetry .util .http import (
244+ OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST ,
245+ OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE ,
246+ OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS ,
153247 ExcludeList ,
154248 detect_synthetic_user_agent ,
249+ get_custom_header_attributes ,
250+ get_custom_headers ,
155251 get_excluded_urls ,
252+ normalise_request_header_name ,
253+ normalise_response_header_name ,
156254 normalize_user_agent ,
157255 parse_excluded_urls ,
158256 redact_url ,
@@ -202,6 +300,9 @@ def _instrument(
202300 response_hook : _ResponseHookT = None ,
203301 excluded_urls : ExcludeList | None = None ,
204302 sem_conv_opt_in_mode : _StabilityMode = _StabilityMode .DEFAULT ,
303+ captured_request_headers : list [str ] | None = None ,
304+ captured_response_headers : list [str ] | None = None ,
305+ sensitive_headers : list [str ] | None = None ,
205306):
206307 """Enables tracing of all requests calls that go through
207308 :code:`requests.session.Session.request` (this includes
@@ -260,6 +361,14 @@ def get_or_create_headers():
260361 span_attributes [USER_AGENT_SYNTHETIC_TYPE ] = synthetic_type
261362 if user_agent :
262363 span_attributes [USER_AGENT_ORIGINAL ] = user_agent
364+ span_attributes .update (
365+ get_custom_header_attributes (
366+ headers ,
367+ captured_request_headers ,
368+ sensitive_headers ,
369+ normalise_request_header_name ,
370+ )
371+ )
263372
264373 metric_labels = {}
265374 _set_http_method (
@@ -352,6 +461,14 @@ def get_or_create_headers():
352461 version_text ,
353462 sem_conv_opt_in_mode ,
354463 )
464+ span_attributes .update (
465+ get_custom_header_attributes (
466+ result .headers ,
467+ captured_response_headers ,
468+ sensitive_headers ,
469+ normalise_response_header_name ,
470+ )
471+ )
355472 for key , val in span_attributes .items ():
356473 span .set_attribute (key , val )
357474
@@ -503,6 +620,15 @@ def _instrument(self, **kwargs: Any):
503620 else parse_excluded_urls (excluded_urls )
504621 ),
505622 sem_conv_opt_in_mode = semconv_opt_in_mode ,
623+ captured_request_headers = get_custom_headers (
624+ OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST
625+ ),
626+ captured_response_headers = get_custom_headers (
627+ OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE
628+ ),
629+ sensitive_headers = get_custom_headers (
630+ OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS
631+ ),
506632 )
507633
508634 def _uninstrument (self , ** kwargs : Any ):
0 commit comments