|
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