diff --git a/docs/introduction/configuration.md b/docs/introduction/configuration.md index 608557e..99a434d 100644 --- a/docs/introduction/configuration.md +++ b/docs/introduction/configuration.md @@ -67,13 +67,14 @@ To bootstrap Opentelemetry, you must provide at least: Additional parameters: -- `opentelemetry_service_name` -- `opentelemetry_container_name` -- `opentelemetry_endpoint` -- `opentelemetry_namespace` -- `opentelemetry_insecure` -- `opentelemetry_instrumentors` -- `opentelemetry_log_traces` +- `opentelemetry_service_name` - if provided, will be passed to the `Resource` instead of `service_name`. +- `opentelemetry_container_name` - will be passed to the `Resource`. +- `opentelemetry_endpoint` - will be passed to `OTLPSpanExporter` as endpoint. +- `opentelemetry_namespace` - will be passed to the `Resource`. +- `opentelemetry_insecure` - is opentelemetry connection secure. +- `opentelemetry_instrumentors` - a list of extra instrumentors. +- `opentelemetry_log_traces` - traces will be logged to stdout. +- `opentelemetry_generate_health_check_spans` - generate spans for health check handlers if `True`. Additional parameters for Litestar and FastAPI: diff --git a/lite_bootstrap/bootstrappers/fastapi_bootstrapper.py b/lite_bootstrap/bootstrappers/fastapi_bootstrapper.py index 80456d1..55f64a5 100644 --- a/lite_bootstrap/bootstrappers/fastapi_bootstrapper.py +++ b/lite_bootstrap/bootstrappers/fastapi_bootstrapper.py @@ -104,11 +104,12 @@ class FastAPILoggingInstrument(LoggingInstrument): class FastAPIOpenTelemetryInstrument(OpenTelemetryInstrument): bootstrap_config: FastAPIConfig - def _build_excluded_urls(self) -> list[str]: - excluded_urls = [*self.bootstrap_config.opentelemetry_excluded_urls] - for one_url in (self.bootstrap_config.health_checks_path, self.bootstrap_config.prometheus_metrics_path): - if one_url and one_url not in excluded_urls: - excluded_urls.append(one_url) + def _build_excluded_urls(self) -> set[str]: + excluded_urls = set(self.bootstrap_config.opentelemetry_excluded_urls) + excluded_urls.add(self.bootstrap_config.prometheus_metrics_path) + if not self.bootstrap_config.opentelemetry_generate_health_check_spans: + excluded_urls.add(self.bootstrap_config.health_checks_path) + return excluded_urls def bootstrap(self) -> None: diff --git a/lite_bootstrap/bootstrappers/faststream_bootstrapper.py b/lite_bootstrap/bootstrappers/faststream_bootstrapper.py index 2200c54..8bacbd9 100644 --- a/lite_bootstrap/bootstrappers/faststream_bootstrapper.py +++ b/lite_bootstrap/bootstrappers/faststream_bootstrapper.py @@ -19,9 +19,12 @@ import prometheus_client if import_checker.is_opentelemetry_installed: + from opentelemetry import trace from opentelemetry.metrics import Meter, MeterProvider from opentelemetry.trace import TracerProvider, get_tracer_provider + tracer: typing.Final = trace.get_tracer(__name__) + @typing.runtime_checkable class FastStreamTelemetryMiddlewareProtocol(typing.Protocol): @@ -70,6 +73,11 @@ async def check_health(_: object) -> "AsgiResponse": else AsgiResponse(b"Service is unhealthy", 500, headers={"content-type": "application/json"}) ) + if self.bootstrap_config.opentelemetry_generate_health_check_spans: + check_health = tracer.start_as_current_span(f"GET {self.bootstrap_config.health_checks_path}")( + check_health, + ) + self.bootstrap_config.application.mount(self.bootstrap_config.health_checks_path, check_health) async def _define_health_status(self) -> bool: diff --git a/lite_bootstrap/bootstrappers/litestar_bootstrapper.py b/lite_bootstrap/bootstrappers/litestar_bootstrapper.py index 06649a3..0698f7d 100644 --- a/lite_bootstrap/bootstrappers/litestar_bootstrapper.py +++ b/lite_bootstrap/bootstrappers/litestar_bootstrapper.py @@ -100,11 +100,12 @@ class LitestarLoggingInstrument(LoggingInstrument): class LitestarOpenTelemetryInstrument(OpenTelemetryInstrument): bootstrap_config: LitestarConfig - def _build_excluded_urls(self) -> list[str]: - excluded_urls = [*self.bootstrap_config.opentelemetry_excluded_urls] - for one_url in (self.bootstrap_config.health_checks_path, self.bootstrap_config.prometheus_metrics_path): - if one_url and one_url not in excluded_urls: - excluded_urls.append(one_url) + def _build_excluded_urls(self) -> set[str]: + excluded_urls = set(self.bootstrap_config.opentelemetry_excluded_urls) + excluded_urls.add(self.bootstrap_config.prometheus_metrics_path) + if not self.bootstrap_config.opentelemetry_generate_health_check_spans: + excluded_urls.add(self.bootstrap_config.health_checks_path) + return excluded_urls def bootstrap(self) -> None: @@ -112,7 +113,7 @@ def bootstrap(self) -> None: self.bootstrap_config.application_config.middleware.append( OpenTelemetryConfig( tracer_provider=get_tracer_provider(), - exclude=self._build_excluded_urls(), + exclude=list(self._build_excluded_urls()), ).middleware, ) diff --git a/lite_bootstrap/instruments/opentelemetry_instrument.py b/lite_bootstrap/instruments/opentelemetry_instrument.py index e810801..2bd0780 100644 --- a/lite_bootstrap/instruments/opentelemetry_instrument.py +++ b/lite_bootstrap/instruments/opentelemetry_instrument.py @@ -36,6 +36,7 @@ class OpentelemetryConfig(BaseConfig): default_factory=list ) opentelemetry_log_traces: bool = False + opentelemetry_generate_health_check_spans: bool = True @dataclasses.dataclass(kw_only=True, slots=True, frozen=True) diff --git a/tests/test_fastapi_bootstrap.py b/tests/test_fastapi_bootstrap.py index 842e771..1f2c32d 100644 --- a/tests/test_fastapi_bootstrap.py +++ b/tests/test_fastapi_bootstrap.py @@ -28,6 +28,7 @@ def fastapi_config() -> FastAPIConfig: opentelemetry_endpoint="otl", opentelemetry_instrumentors=[CustomInstrumentor()], opentelemetry_log_traces=True, + opentelemetry_generate_health_check_spans=False, prometheus_metrics_path="/custom-metrics/", sentry_dsn="https://testdsn@localhost/1", swagger_offline_docs=True, diff --git a/tests/test_litestar_bootstrap.py b/tests/test_litestar_bootstrap.py index 09e2e98..4cb1387 100644 --- a/tests/test_litestar_bootstrap.py +++ b/tests/test_litestar_bootstrap.py @@ -22,6 +22,7 @@ def litestar_config() -> LitestarConfig: opentelemetry_endpoint="otl", opentelemetry_instrumentors=[CustomInstrumentor()], opentelemetry_log_traces=True, + opentelemetry_generate_health_check_spans=False, prometheus_metrics_path="/custom-metrics/", sentry_dsn="https://testdsn@localhost/1", swagger_offline_docs=True,