Skip to content

Commit

Permalink
feat: add header extraction parameters to `FastAPIInstrumentor().inst…
Browse files Browse the repository at this point in the history
…rument_app` (#2241)

* add header parameters to FastAPIInstrumentor().instrument_app

* add changelog

* move #2072 changelog to unreleased

* remove accidental pprint

* linting

* future annotations for fastapi

* same logic for instrument()

* Fix lint

* Fix test case

---------

Co-authored-by: Diego Hurtado <[email protected]>
  • Loading branch information
samuelcolvin and ocelotl authored Aug 1, 2024
1 parent c3e9f75 commit 3e18560
Show file tree
Hide file tree
Showing 3 changed files with 571 additions and 10 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#2367](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2367))


### Added
- `opentelemetry-instrumentation-fastapi` Add support for configuring header extraction via runtime constructor parameters
([#2241](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2241))

## Version 1.23.0/0.44b0 (2024-02-23)

- Drop support for 3.7
Expand All @@ -236,6 +240,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added

- `opentelemetry-instrumentation-psycopg` Initial release for psycopg 3.x
- `opentelemetry-instrumentation-asgi` Add support for configuring ASGI middleware header extraction via runtime constructor parameters
([#2026](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2026))

## Version 1.22.0/0.43b0 (2023-12-14)

Expand Down Expand Up @@ -275,8 +281,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
([#1948](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1948))
- Added schema_url (`"https://opentelemetry.io/schemas/1.11.0"`) to all metrics and traces
([#1977](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1977))
- Add support for configuring ASGI middleware header extraction via runtime constructor parameters
([#2026](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/2026))

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A
Request headers
***************
To capture HTTP request headers as span attributes, set the environment variable
``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST`` to a comma delimited list of HTTP header names.
``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST`` to a comma delimited list of HTTP header names,
or pass the ``http_capture_headers_server_request`` keyword argument to the ``instrument_app`` method.
For example,
For example using the environment variable,
::
export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_REQUEST="content-type,custom_request_header"
Expand Down Expand Up @@ -120,9 +121,10 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A
Response headers
****************
To capture HTTP response headers as span attributes, set the environment variable
``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE`` to a comma delimited list of HTTP header names.
``OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE`` to a comma delimited list of HTTP header names,
or pass the ``http_capture_headers_server_response`` keyword argument to the ``instrument_app`` method.
For example,
For example using the environment variable,
::
export OTEL_INSTRUMENTATION_HTTP_CAPTURE_HEADERS_SERVER_RESPONSE="content-type,custom_response_header"
Expand Down Expand Up @@ -155,10 +157,12 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A
******************
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.
to a comma delimited list of HTTP header names to be sanitized, or pass the ``http_capture_headers_sanitize_fields``
keyword argument to the ``instrument_app`` method.
For example,
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"
Expand All @@ -171,6 +175,9 @@ def client_response_hook(span: Span, scope: dict[str, Any], message: dict[str, A
API
---
"""

from __future__ import annotations

import logging
from importlib.metadata import PackageNotFoundError, distribution
from typing import Collection
Expand Down Expand Up @@ -227,6 +234,9 @@ def instrument_app(
tracer_provider=None,
meter_provider=None,
excluded_urls=None,
http_capture_headers_server_request: list[str] | None = None,
http_capture_headers_server_response: list[str] | None = None,
http_capture_headers_sanitize_fields: list[str] | None = None,
):
"""Instrument an uninstrumented FastAPI application."""
if not hasattr(app, "_is_instrumented_by_opentelemetry"):
Expand Down Expand Up @@ -265,6 +275,9 @@ def instrument_app(
# Pass in tracer/meter to get __name__and __version__ of fastapi instrumentation
tracer=tracer,
meter=meter,
http_capture_headers_server_request=http_capture_headers_server_request,
http_capture_headers_server_response=http_capture_headers_server_response,
http_capture_headers_sanitize_fields=http_capture_headers_sanitize_fields,
)
app._is_instrumented_by_opentelemetry = True
if app not in _InstrumentedFastAPI._instrumented_fastapi_apps:
Expand Down Expand Up @@ -314,6 +327,15 @@ def _instrument(self, **kwargs):
_InstrumentedFastAPI._client_response_hook = kwargs.get(
"client_response_hook"
)
_InstrumentedFastAPI._http_capture_headers_server_request = kwargs.get(
"http_capture_headers_server_request"
)
_InstrumentedFastAPI._http_capture_headers_server_response = (
kwargs.get("http_capture_headers_server_response")
)
_InstrumentedFastAPI._http_capture_headers_sanitize_fields = (
kwargs.get("http_capture_headers_sanitize_fields")
)
_excluded_urls = kwargs.get("excluded_urls")
_InstrumentedFastAPI._excluded_urls = (
_excluded_urls_from_env
Expand Down Expand Up @@ -368,6 +390,9 @@ def __init__(self, *args, **kwargs):
# Pass in tracer/meter to get __name__and __version__ of fastapi instrumentation
tracer=tracer,
meter=meter,
http_capture_headers_server_request=_InstrumentedFastAPI._http_capture_headers_server_request,
http_capture_headers_server_response=_InstrumentedFastAPI._http_capture_headers_server_response,
http_capture_headers_sanitize_fields=_InstrumentedFastAPI._http_capture_headers_sanitize_fields,
)
self._is_instrumented_by_opentelemetry = True
_InstrumentedFastAPI._instrumented_fastapi_apps.add(self)
Expand Down
Loading

0 comments on commit 3e18560

Please sign in to comment.