|
5 | 5 | from prometheus_fastapi_instrumentator import Instrumentator
|
6 | 6 |
|
7 | 7 | from lite_bootstrap.bootstrappers.base import BaseBootstrapper
|
8 |
| -from lite_bootstrap.instruments.healthchecks_instrument import HealthChecksInstrument, HealthCheckTypedDict |
9 |
| -from lite_bootstrap.instruments.logging_instrument import LoggingInstrument |
10 |
| -from lite_bootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrument |
11 |
| -from lite_bootstrap.instruments.prometheus_instrument import PrometheusInstrument |
12 |
| -from lite_bootstrap.instruments.sentry_instrument import SentryInstrument |
13 |
| -from lite_bootstrap.service_config import ServiceConfig |
| 8 | +from lite_bootstrap.instruments.healthchecks_instrument import ( |
| 9 | + HealthChecksConfig, |
| 10 | + HealthChecksInstrument, |
| 11 | + HealthCheckTypedDict, |
| 12 | +) |
| 13 | +from lite_bootstrap.instruments.logging_instrument import LoggingConfig, LoggingInstrument |
| 14 | +from lite_bootstrap.instruments.opentelemetry_instrument import OpentelemetryConfig, OpenTelemetryInstrument |
| 15 | +from lite_bootstrap.instruments.prometheus_instrument import PrometheusConfig, PrometheusInstrument |
| 16 | +from lite_bootstrap.instruments.sentry_instrument import SentryConfig, SentryInstrument |
14 | 17 |
|
15 | 18 |
|
16 | 19 | with contextlib.suppress(ImportError):
|
|
19 | 22 | from opentelemetry.trace import get_tracer_provider
|
20 | 23 |
|
21 | 24 |
|
| 25 | +@dataclasses.dataclass(kw_only=True, slots=True, frozen=True) |
| 26 | +class FastAPIConfig(HealthChecksConfig, LoggingConfig, OpentelemetryConfig, PrometheusConfig, SentryConfig): |
| 27 | + application: fastapi.FastAPI = dataclasses.field(default_factory=fastapi.FastAPI) |
| 28 | + opentelemetry_excluded_urls: list[str] = dataclasses.field(default_factory=list) |
| 29 | + prometheus_instrumentator_params: dict[str, typing.Any] = dataclasses.field(default_factory=dict) |
| 30 | + prometheus_instrument_params: dict[str, typing.Any] = dataclasses.field(default_factory=dict) |
| 31 | + prometheus_expose_params: dict[str, typing.Any] = dataclasses.field(default_factory=dict) |
| 32 | + |
| 33 | + |
22 | 34 | @dataclasses.dataclass(kw_only=True, slots=True, frozen=True)
|
23 | 35 | class FastAPIHealthChecksInstrument(HealthChecksInstrument):
|
24 |
| - enabled: bool = True |
25 |
| - path: str = "/health/" |
26 |
| - include_in_schema: bool = False |
| 36 | + bootstrap_config: FastAPIConfig |
27 | 37 |
|
28 |
| - def build_fastapi_health_check_router(self, service_config: ServiceConfig) -> fastapi.APIRouter: |
| 38 | + def build_fastapi_health_check_router(self) -> fastapi.APIRouter: |
29 | 39 | fastapi_router = fastapi.APIRouter(
|
30 | 40 | tags=["probes"],
|
31 |
| - include_in_schema=self.include_in_schema, |
| 41 | + include_in_schema=self.bootstrap_config.health_checks_include_in_schema, |
32 | 42 | )
|
33 | 43 |
|
34 |
| - @fastapi_router.get(self.path) |
| 44 | + @fastapi_router.get(self.bootstrap_config.health_checks_path) |
35 | 45 | async def health_check_handler() -> HealthCheckTypedDict:
|
36 |
| - return self.render_health_check_data(service_config) |
| 46 | + return self.render_health_check_data() |
37 | 47 |
|
38 | 48 | return fastapi_router
|
39 | 49 |
|
40 |
| - def bootstrap(self, service_config: ServiceConfig, application: fastapi.FastAPI | None = None) -> None: |
41 |
| - if application: |
42 |
| - application.include_router(self.build_fastapi_health_check_router(service_config)) |
| 50 | + def bootstrap(self) -> None: |
| 51 | + self.bootstrap_config.application.include_router(self.build_fastapi_health_check_router()) |
43 | 52 |
|
44 | 53 |
|
45 | 54 | @dataclasses.dataclass(kw_only=True, frozen=True)
|
46 |
| -class FastAPILoggingInstrument(LoggingInstrument): ... |
| 55 | +class FastAPILoggingInstrument(LoggingInstrument): |
| 56 | + bootstrap_config: FastAPIConfig |
47 | 57 |
|
48 | 58 |
|
49 | 59 | @dataclasses.dataclass(kw_only=True, frozen=True)
|
50 | 60 | class FastAPIOpenTelemetryInstrument(OpenTelemetryInstrument):
|
51 |
| - excluded_urls: list[str] = dataclasses.field(default_factory=list) |
| 61 | + bootstrap_config: FastAPIConfig |
52 | 62 |
|
53 |
| - def bootstrap(self, service_config: ServiceConfig, application: fastapi.FastAPI | None = None) -> None: |
54 |
| - super().bootstrap(service_config, application) |
| 63 | + def bootstrap(self) -> None: |
| 64 | + super().bootstrap() |
55 | 65 | FastAPIInstrumentor.instrument_app(
|
56 |
| - app=application, |
| 66 | + app=self.bootstrap_config.application, |
57 | 67 | tracer_provider=get_tracer_provider(),
|
58 |
| - excluded_urls=",".join(self.excluded_urls), |
| 68 | + excluded_urls=",".join(self.bootstrap_config.opentelemetry_excluded_urls), |
59 | 69 | )
|
60 | 70 |
|
61 |
| - def teardown(self, application: fastapi.FastAPI | None = None) -> None: |
62 |
| - if application: |
63 |
| - FastAPIInstrumentor.uninstrument_app(application) |
| 71 | + def teardown(self) -> None: |
| 72 | + FastAPIInstrumentor.uninstrument_app(self.bootstrap_config.application) |
64 | 73 | super().teardown()
|
65 | 74 |
|
66 | 75 |
|
67 | 76 | @dataclasses.dataclass(kw_only=True, frozen=True)
|
68 |
| -class FastAPISentryInstrument(SentryInstrument): ... |
| 77 | +class FastAPISentryInstrument(SentryInstrument): |
| 78 | + bootstrap_config: FastAPIConfig |
69 | 79 |
|
70 | 80 |
|
71 | 81 | @dataclasses.dataclass(kw_only=True, frozen=True)
|
72 | 82 | class FastAPIPrometheusInstrument(PrometheusInstrument):
|
73 |
| - metrics_path: str = "/metrics" |
74 |
| - metrics_include_in_schema: bool = False |
75 |
| - instrumentator_params: dict[str, typing.Any] = dataclasses.field(default_factory=dict) |
76 |
| - instrument_params: dict[str, typing.Any] = dataclasses.field(default_factory=dict) |
77 |
| - expose_params: dict[str, typing.Any] = dataclasses.field(default_factory=dict) |
78 |
| - |
79 |
| - def bootstrap(self, _: ServiceConfig, application: fastapi.FastAPI | None = None) -> None: |
80 |
| - if application: |
81 |
| - Instrumentator(**self.instrumentator_params).instrument( |
82 |
| - application, |
83 |
| - **self.instrument_params, |
84 |
| - ).expose( |
85 |
| - application, |
86 |
| - endpoint=self.metrics_path, |
87 |
| - include_in_schema=self.metrics_include_in_schema, |
88 |
| - **self.expose_params, |
89 |
| - ) |
| 83 | + bootstrap_config: FastAPIConfig |
| 84 | + |
| 85 | + def bootstrap(self) -> None: |
| 86 | + Instrumentator(**self.bootstrap_config.prometheus_instrument_params).instrument( |
| 87 | + self.bootstrap_config.application, |
| 88 | + **self.bootstrap_config.prometheus_instrument_params, |
| 89 | + ).expose( |
| 90 | + self.bootstrap_config.application, |
| 91 | + endpoint=self.bootstrap_config.prometheus_metrics_path, |
| 92 | + include_in_schema=self.bootstrap_config.prometheus_metrics_include_in_schema, |
| 93 | + **self.bootstrap_config.prometheus_expose_params, |
| 94 | + ) |
90 | 95 |
|
91 | 96 |
|
92 |
| -@dataclasses.dataclass(kw_only=True, slots=True, frozen=True) |
93 |
| -class FastAPIBootstrapper(BaseBootstrapper[fastapi.FastAPI, fastapi.FastAPI]): |
94 |
| - bootstrap_object: fastapi.FastAPI |
95 |
| - instruments: typing.Sequence[ |
96 |
| - FastAPIOpenTelemetryInstrument |
97 |
| - | FastAPISentryInstrument |
98 |
| - | FastAPIHealthChecksInstrument |
99 |
| - | FastAPILoggingInstrument |
100 |
| - | FastAPIPrometheusInstrument |
| 97 | +class FastAPIBootstrapper(BaseBootstrapper[fastapi.FastAPI]): |
| 98 | + instruments_types: typing.ClassVar = [ |
| 99 | + FastAPIOpenTelemetryInstrument, |
| 100 | + FastAPISentryInstrument, |
| 101 | + FastAPIHealthChecksInstrument, |
| 102 | + FastAPILoggingInstrument, |
| 103 | + FastAPIPrometheusInstrument, |
101 | 104 | ]
|
102 |
| - service_config: ServiceConfig |
| 105 | + bootstrap_config: FastAPIConfig |
| 106 | + __slots__ = "bootstrap_config", "instruments" |
| 107 | + |
| 108 | + def __init__(self, bootstrap_config: FastAPIConfig) -> None: |
| 109 | + super().__init__(bootstrap_config) |
103 | 110 |
|
104 | 111 | def _prepare_application(self) -> fastapi.FastAPI:
|
105 |
| - return self.bootstrap_object |
| 112 | + return self.bootstrap_config.application |
0 commit comments