|
| 1 | +import contextlib |
| 2 | +import dataclasses |
| 3 | +import typing |
| 4 | + |
| 5 | +from lite_bootstrap.bootstraps.base import BaseBootstrap |
| 6 | +from lite_bootstrap.instruments.healthchecks_instrument import HealthChecksInstrument, HealthCheckTypedDict |
| 7 | +from lite_bootstrap.instruments.logging_instrument import LoggingInstrument |
| 8 | +from lite_bootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrument |
| 9 | +from lite_bootstrap.instruments.sentry_instrument import SentryInstrument |
| 10 | +from lite_bootstrap.service_config import ServiceConfig |
| 11 | + |
| 12 | + |
| 13 | +with contextlib.suppress(ImportError): |
| 14 | + import litestar |
| 15 | + from litestar.config.app import AppConfig |
| 16 | + from litestar.contrib.opentelemetry import OpenTelemetryConfig |
| 17 | + from opentelemetry.trace import get_tracer_provider |
| 18 | + |
| 19 | + |
| 20 | +@dataclasses.dataclass(kw_only=True, slots=True, frozen=True) |
| 21 | +class LitestarHealthChecksInstrument(HealthChecksInstrument): |
| 22 | + enabled: bool = True |
| 23 | + path: str = "/health/" |
| 24 | + include_in_schema: bool = False |
| 25 | + |
| 26 | + def build_litestar_health_check_router(self, service_config: ServiceConfig) -> litestar.Router: |
| 27 | + @litestar.get(media_type=litestar.MediaType.JSON) |
| 28 | + async def health_check_handler() -> HealthCheckTypedDict: |
| 29 | + return self.render_health_check_data(service_config) |
| 30 | + |
| 31 | + return litestar.Router( |
| 32 | + path=self.path, |
| 33 | + route_handlers=[health_check_handler], |
| 34 | + tags=["probes"], |
| 35 | + include_in_schema=self.include_in_schema, |
| 36 | + ) |
| 37 | + |
| 38 | + def bootstrap(self, service_config: ServiceConfig, app_config: AppConfig | None = None) -> None: |
| 39 | + if app_config: |
| 40 | + app_config.route_handlers.append(self.build_litestar_health_check_router(service_config)) |
| 41 | + |
| 42 | + |
| 43 | +@dataclasses.dataclass(kw_only=True, frozen=True) |
| 44 | +class LitestarLoggingInstrument(LoggingInstrument): ... |
| 45 | + |
| 46 | + |
| 47 | +@dataclasses.dataclass(kw_only=True, frozen=True) |
| 48 | +class LitestarOpenTelemetryInstrument(OpenTelemetryInstrument): |
| 49 | + excluded_urls: list[str] = dataclasses.field(default_factory=list) |
| 50 | + |
| 51 | + def bootstrap(self, service_config: ServiceConfig, app_config: AppConfig | None = None) -> None: |
| 52 | + super().bootstrap(service_config, app_config) |
| 53 | + if app_config: |
| 54 | + app_config.middleware.append( |
| 55 | + OpenTelemetryConfig( |
| 56 | + tracer_provider=get_tracer_provider(), |
| 57 | + exclude=self.excluded_urls, |
| 58 | + ).middleware, |
| 59 | + ) |
| 60 | + |
| 61 | + |
| 62 | +@dataclasses.dataclass(kw_only=True, frozen=True) |
| 63 | +class LitestarSentryInstrument(SentryInstrument): ... |
| 64 | + |
| 65 | + |
| 66 | +@dataclasses.dataclass(kw_only=True, slots=True, frozen=True) |
| 67 | +class LitestarBootstrap(BaseBootstrap[AppConfig]): |
| 68 | + application: AppConfig |
| 69 | + instruments: typing.Sequence[ |
| 70 | + LitestarOpenTelemetryInstrument |
| 71 | + | LitestarSentryInstrument |
| 72 | + | LitestarHealthChecksInstrument |
| 73 | + | LitestarLoggingInstrument |
| 74 | + ] |
| 75 | + service_config: ServiceConfig |
0 commit comments