Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#3967](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3967))
- `opentelemetry-instrumentation-redis`: add missing copyright header for opentelemetry-instrumentation-redis
([#3976](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3976))
- `opentelemetry-instrumentation-requests`: add ability to capture custom headers
([#3987](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3987))

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,97 @@ def response_hook(span, request_obj, response):
request_hook=request_hook, response_hook=response_hook
)

Capture HTTP request and response headers
*****************************************
You can configure the agent to capture specified HTTP headers as span attributes, according to the
`semantic conventions <https://opentelemetry.io/docs/specs/semconv/http/http-spans/#http-client-span>`_.

Request headers
***************
To capture HTTP request headers as span attributes, set the environment variable
``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST`` to a comma delimited list of HTTP header names.

For example using the environment variable,
::

export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST="content-type,custom_request_header"

will extract ``content-type`` and ``custom_request_header`` from the request headers and add them as span attributes.

Request header names in Requests are case-insensitive. So, giving the header name as ``CUStom-Header`` in the environment
variable will capture the header named ``custom-header``.

Regular expressions may also be used to match multiple headers that correspond to the given pattern. For example:
::

export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST="Accept.*,X-.*"

Would match all request headers that start with ``Accept`` and ``X-``.

To capture all request headers, set ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST`` to ``".*"``.
::

export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST=".*"

The name of the added span attribute will follow the format ``http.request.header.<header_name>`` where ``<header_name>``
is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a
single item list containing all the header values.

For example:
``http.request.header.custom_request_header = ["<value1>", "<value2>"]``

Response headers
****************
To capture HTTP response headers as span attributes, set the environment variable
``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE`` to a comma delimited list of HTTP header names.

For example using the environment variable,
::

export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE="content-type,custom_response_header"

will extract ``content-type`` and ``custom_response_header`` from the response headers and add them as span attributes.

Response header names in Requests are case-insensitive. So, giving the header name as ``CUStom-Header`` in the environment
variable will capture the header named ``custom-header``.

Regular expressions may also be used to match multiple headers that correspond to the given pattern. For example:
::

export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE="Content.*,X-.*"

Would match all response headers that start with ``Content`` and ``X-``.

To capture all response headers, set ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE`` to ``".*"``.
::

export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE=".*"

The name of the added span attribute will follow the format ``http.response.header.<header_name>`` where ``<header_name>``
is the normalized HTTP header name (lowercase, with ``-`` replaced by ``_``). The value of the attribute will be a
list containing the header values.

For example:
``http.response.header.custom_response_header = ["<value1>", "<value2>"]``

Sanitizing headers
******************
In order to prevent storing sensitive data such as personally identifiable information (PII), session keys, passwords,
etc, set the environment variable ``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS``
to a comma delimited list of HTTP header names to be sanitized.

Regexes may be used, and all header names will be matched in a case-insensitive manner.

For example using the environment variable,
::

export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS=".*session.*,set-cookie"

will replace the value of headers such as ``session-id`` and ``set-cookie`` with ``[REDACTED]`` in the span.

Note:
The environment variable names used to capture HTTP headers are still experimental, and thus are subject to change.

Custom Duration Histogram Boundaries
************************************
To customize the duration histogram bucket boundaries used for HTTP client request duration metrics,
Expand Down Expand Up @@ -150,9 +241,16 @@ def response_hook(span, request_obj, response):
from opentelemetry.trace import SpanKind, Tracer, get_tracer
from opentelemetry.trace.span import Span
from opentelemetry.util.http import (
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST,
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE,
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS,
ExcludeList,
detect_synthetic_user_agent,
get_custom_header_attributes,
get_custom_headers,
get_excluded_urls,
normalise_request_header_name,
normalise_response_header_name,
parse_excluded_urls,
redact_url,
sanitize_method,
Expand Down Expand Up @@ -201,6 +299,9 @@ def _instrument(
response_hook: _ResponseHookT = None,
excluded_urls: ExcludeList | None = None,
sem_conv_opt_in_mode: _StabilityMode = _StabilityMode.DEFAULT,
captured_request_headers: list[str] | None = None,
captured_response_headers: list[str] | None = None,
sensitive_headers: list[str] | None = None,
):
"""Enables tracing of all requests calls that go through
:code:`requests.session.Session.request` (this includes
Expand Down Expand Up @@ -258,6 +359,14 @@ def get_or_create_headers():
span_attributes[USER_AGENT_SYNTHETIC_TYPE] = synthetic_type
if user_agent:
span_attributes[USER_AGENT_ORIGINAL] = user_agent
span_attributes.update(
get_custom_header_attributes(
headers,
captured_request_headers,
sensitive_headers,
normalise_request_header_name,
)
)

metric_labels = {}
_set_http_method(
Expand Down Expand Up @@ -350,6 +459,14 @@ def get_or_create_headers():
version_text,
sem_conv_opt_in_mode,
)
span_attributes.update(
get_custom_header_attributes(
result.headers,
captured_response_headers,
sensitive_headers,
normalise_response_header_name,
)
)
for key, val in span_attributes.items():
span.set_attribute(key, val)

Expand Down Expand Up @@ -501,6 +618,15 @@ def _instrument(self, **kwargs: Any):
else parse_excluded_urls(excluded_urls)
),
sem_conv_opt_in_mode=semconv_opt_in_mode,
captured_request_headers=get_custom_headers(
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_REQUEST
),
captured_response_headers=get_custom_headers(
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_CLIENT_RESPONSE
),
sensitive_headers=get_custom_headers(
OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SANITIZE_FIELDS
),
)

def _uninstrument(self, **kwargs: Any):
Expand Down
Loading