Skip to content

Commit 2934ace

Browse files
authored
Merge pull request #17 from modern-python/merge-configs
merge configs
2 parents db422bf + f75a2ce commit 2934ace

20 files changed

+383
-389
lines changed

lite_bootstrap/__init__.py

Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,13 @@
1-
from lite_bootstrap.bootstrappers.fastapi_bootstrapper import (
2-
FastAPIBootstrapper,
3-
FastAPIHealthChecksInstrument,
4-
FastAPILoggingInstrument,
5-
FastAPIOpenTelemetryInstrument,
6-
FastAPIPrometheusInstrument,
7-
FastAPISentryInstrument,
8-
)
9-
from lite_bootstrap.bootstrappers.free_bootstrapper import FreeBootstrapper
10-
from lite_bootstrap.bootstrappers.litestar_bootstrapper import (
11-
LitestarBootstrapper,
12-
LitestarHealthChecksInstrument,
13-
LitestarLoggingInstrument,
14-
LitestarOpenTelemetryInstrument,
15-
LitestarPrometheusInstrument,
16-
LitestarSentryInstrument,
17-
)
18-
from lite_bootstrap.instruments.healthchecks_instrument import HealthChecksInstrument
19-
from lite_bootstrap.instruments.logging_instrument import LoggingInstrument
20-
from lite_bootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrument
21-
from lite_bootstrap.instruments.sentry_instrument import SentryInstrument
22-
from lite_bootstrap.service_config import ServiceConfig
1+
from lite_bootstrap.bootstrappers.fastapi_bootstrapper import FastAPIBootstrapper, FastAPIConfig
2+
from lite_bootstrap.bootstrappers.free_bootstrapper import FreeBootstrapper, FreeBootstrapperConfig
3+
from lite_bootstrap.bootstrappers.litestar_bootstrapper import LitestarBootstrapper, LitestarConfig
234

245

256
__all__ = [
267
"FastAPIBootstrapper",
27-
"FastAPIHealthChecksInstrument",
28-
"FastAPILoggingInstrument",
29-
"FastAPIOpenTelemetryInstrument",
30-
"FastAPIPrometheusInstrument",
31-
"FastAPISentryInstrument",
8+
"FastAPIConfig",
329
"FreeBootstrapper",
33-
"HealthChecksInstrument",
10+
"FreeBootstrapperConfig",
3411
"LitestarBootstrapper",
35-
"LitestarHealthChecksInstrument",
36-
"LitestarLoggingInstrument",
37-
"LitestarOpenTelemetryInstrument",
38-
"LitestarPrometheusInstrument",
39-
"LitestarSentryInstrument",
40-
"LoggingInstrument",
41-
"OpenTelemetryInstrument",
42-
"SentryInstrument",
43-
"ServiceConfig",
12+
"LitestarConfig",
4413
]

lite_bootstrap/bootstrappers/base.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
11
import abc
22
import typing
33

4-
from lite_bootstrap.instruments.base import BaseInstrument
5-
from lite_bootstrap.service_config import ServiceConfig
6-
from lite_bootstrap.types import ApplicationT, BootstrapObjectT
4+
from lite_bootstrap.instruments.base import BaseConfig, BaseInstrument
5+
from lite_bootstrap.types import ApplicationT
76

87

9-
class BaseBootstrapper(abc.ABC, typing.Generic[BootstrapObjectT, ApplicationT]):
10-
bootstrap_object: BootstrapObjectT
11-
instruments: typing.Sequence[BaseInstrument]
12-
service_config: ServiceConfig
8+
InstrumentT = typing.TypeVar("InstrumentT", bound=BaseInstrument)
9+
10+
11+
class BaseBootstrapper(abc.ABC, typing.Generic[ApplicationT]):
12+
instruments_types: typing.ClassVar[list[type[BaseInstrument]]]
13+
instruments: list[BaseInstrument]
14+
bootstrap_config: BaseConfig
15+
16+
def __init__(self, bootstrap_config: BaseConfig) -> None:
17+
self.bootstrap_config = bootstrap_config
18+
self.instruments = []
19+
for instrument_type in self.instruments_types:
20+
instrument = instrument_type(bootstrap_config=bootstrap_config)
21+
if instrument.is_ready():
22+
self.instruments.append(instrument)
1323

1424
@abc.abstractmethod
1525
def _prepare_application(self) -> ApplicationT: ...
1626

1727
def bootstrap(self) -> ApplicationT:
1828
for one_instrument in self.instruments:
19-
if one_instrument.is_ready(self.service_config):
20-
one_instrument.bootstrap(self.service_config, self.bootstrap_object)
29+
one_instrument.bootstrap()
2130
return self._prepare_application()
2231

2332
def teardown(self) -> None:
2433
for one_instrument in self.instruments:
25-
if one_instrument.is_ready(self.service_config):
26-
one_instrument.teardown(self.bootstrap_object)
34+
one_instrument.teardown()

lite_bootstrap/bootstrappers/fastapi_bootstrapper.py

Lines changed: 61 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
from prometheus_fastapi_instrumentator import Instrumentator
66

77
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
1417

1518

1619
with contextlib.suppress(ImportError):
@@ -19,87 +22,91 @@
1922
from opentelemetry.trace import get_tracer_provider
2023

2124

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+
2234
@dataclasses.dataclass(kw_only=True, slots=True, frozen=True)
2335
class FastAPIHealthChecksInstrument(HealthChecksInstrument):
24-
enabled: bool = True
25-
path: str = "/health/"
26-
include_in_schema: bool = False
36+
bootstrap_config: FastAPIConfig
2737

28-
def build_fastapi_health_check_router(self, service_config: ServiceConfig) -> fastapi.APIRouter:
38+
def build_fastapi_health_check_router(self) -> fastapi.APIRouter:
2939
fastapi_router = fastapi.APIRouter(
3040
tags=["probes"],
31-
include_in_schema=self.include_in_schema,
41+
include_in_schema=self.bootstrap_config.health_checks_include_in_schema,
3242
)
3343

34-
@fastapi_router.get(self.path)
44+
@fastapi_router.get(self.bootstrap_config.health_checks_path)
3545
async def health_check_handler() -> HealthCheckTypedDict:
36-
return self.render_health_check_data(service_config)
46+
return self.render_health_check_data()
3747

3848
return fastapi_router
3949

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())
4352

4453

4554
@dataclasses.dataclass(kw_only=True, frozen=True)
46-
class FastAPILoggingInstrument(LoggingInstrument): ...
55+
class FastAPILoggingInstrument(LoggingInstrument):
56+
bootstrap_config: FastAPIConfig
4757

4858

4959
@dataclasses.dataclass(kw_only=True, frozen=True)
5060
class FastAPIOpenTelemetryInstrument(OpenTelemetryInstrument):
51-
excluded_urls: list[str] = dataclasses.field(default_factory=list)
61+
bootstrap_config: FastAPIConfig
5262

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()
5565
FastAPIInstrumentor.instrument_app(
56-
app=application,
66+
app=self.bootstrap_config.application,
5767
tracer_provider=get_tracer_provider(),
58-
excluded_urls=",".join(self.excluded_urls),
68+
excluded_urls=",".join(self.bootstrap_config.opentelemetry_excluded_urls),
5969
)
6070

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)
6473
super().teardown()
6574

6675

6776
@dataclasses.dataclass(kw_only=True, frozen=True)
68-
class FastAPISentryInstrument(SentryInstrument): ...
77+
class FastAPISentryInstrument(SentryInstrument):
78+
bootstrap_config: FastAPIConfig
6979

7080

7181
@dataclasses.dataclass(kw_only=True, frozen=True)
7282
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+
)
9095

9196

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,
101104
]
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)
103110

104111
def _prepare_application(self) -> fastapi.FastAPI:
105-
return self.bootstrap_object
112+
return self.bootstrap_config.application

lite_bootstrap/bootstrappers/free_bootstrapper.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,26 @@
22
import typing
33

44
from lite_bootstrap.bootstrappers.base import BaseBootstrapper
5-
from lite_bootstrap.instruments.logging_instrument import LoggingInstrument
6-
from lite_bootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrument
7-
from lite_bootstrap.instruments.sentry_instrument import SentryInstrument
8-
from lite_bootstrap.service_config import ServiceConfig
5+
from lite_bootstrap.instruments.logging_instrument import LoggingConfig, LoggingInstrument
6+
from lite_bootstrap.instruments.opentelemetry_instrument import OpentelemetryConfig, OpenTelemetryInstrument
7+
from lite_bootstrap.instruments.sentry_instrument import SentryConfig, SentryInstrument
98

109

1110
@dataclasses.dataclass(kw_only=True, slots=True, frozen=True)
12-
class FreeBootstrapper(BaseBootstrapper[None, None]):
13-
bootstrap_object: None = None
14-
instruments: typing.Sequence[OpenTelemetryInstrument | SentryInstrument | LoggingInstrument]
15-
service_config: ServiceConfig
11+
class FreeBootstrapperConfig(LoggingConfig, OpentelemetryConfig, SentryConfig): ...
12+
13+
14+
class FreeBootstrapper(BaseBootstrapper[None]):
15+
instruments_types: typing.ClassVar = [
16+
OpenTelemetryInstrument,
17+
SentryInstrument,
18+
LoggingInstrument,
19+
]
20+
bootstrap_config: FreeBootstrapperConfig
21+
__slots__ = "bootstrap_config", "instruments"
22+
23+
def __init__(self, bootstrap_config: FreeBootstrapperConfig) -> None:
24+
super().__init__(bootstrap_config)
1625

1726
def _prepare_application(self) -> None:
18-
return self.bootstrap_object
27+
return None

0 commit comments

Comments
 (0)