Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full refactoring. #1

Merged
merged 46 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
8ce347f
Refactor bootstrapper base class and add sentry instrument. tests are…
insani7y Jul 12, 2024
6916196
Add opentelemetry]
insani7y Jul 13, 2024
8a95047
Continue implementing opentelemetry instrument
insani7y Jul 13, 2024
a980598
Continue implementing opentelemetry instrument
insani7y Jul 13, 2024
c4deff5
Continue implementing opentelemetry instrument
insani7y Jul 13, 2024
c66448e
Continue implementing opentelemetry instrument
insani7y Jul 13, 2024
105acf1
Continue implementing opentelemetry instrument
insani7y Jul 13, 2024
b4304d2
Continue implementing opentelemetry instrument
insani7y Jul 13, 2024
d318c27
Add logging instrument
insani7y Jul 17, 2024
9ce839c
Add logging instrument
insani7y Jul 17, 2024
fc1863b
Add logging instrument
insani7y Jul 17, 2024
5a81e07
Add logging instrument
insani7y Jul 17, 2024
70ecb38
Add prometheus instrument
insani7y Jul 17, 2024
69b8659
Small interface improvments
insani7y Jul 17, 2024
7e598a0
Small interface improvments
insani7y Jul 17, 2024
6e7c76a
Add teardown to litestar bootstrapper
insani7y Jul 17, 2024
61a2efc
Highly arguable decision
insani7y Jul 20, 2024
954d2dd
Highly arguable decision
insani7y Jul 20, 2024
b4b4f8e
Separate instruments and bootstrapper
insani7y Jul 20, 2024
305aff4
Make instrument box private
insani7y Jul 20, 2024
9814971
Make use_instrument typed
insani7y Jul 20, 2024
82ce504
Implement before and after hooks
insani7y Jul 20, 2024
dbdfcfb
Make is_ready a function
insani7y Jul 20, 2024
c4effbb
Make settings per framework
insani7y Jul 22, 2024
2b3e603
Make settings per framework
insani7y Jul 22, 2024
3eba74c
Add tests to some instruments
insani7y Jul 24, 2024
33fc201
Add tests to some instruments
insani7y Jul 24, 2024
7fb4f69
Add tests to some instruments
insani7y Jul 24, 2024
ad2f37b
Add tests to some instruments
insani7y Jul 24, 2024
f469d6c
Add tests to some instruments
insani7y Jul 24, 2024
5a53da4
Trigger codecov
insani7y Jul 24, 2024
40f161d
Try trigger codecov
insani7y Jul 24, 2024
7286144
Try trigger codecov
insani7y Jul 24, 2024
b6e0495
Try trigger codecov
insani7y Jul 24, 2024
80c4f71
Try trigger codecov
insani7y Jul 24, 2024
11cbca0
Fix comments
insani7y Jul 30, 2024
9b38a52
Fix comments
insani7y Jul 30, 2024
d090096
Add some helpers tests
insani7y Jul 30, 2024
a9e003a
Add some helpers tests
insani7y Jul 30, 2024
98732dd
Small changes
insani7y Jul 30, 2024
c49365c
Added tests for everythin
insani7y Aug 2, 2024
88a5436
Update packages
insani7y Aug 2, 2024
b8b4040
Start writing docs
insani7y Aug 2, 2024
31080a6
Logo draft
Jul 22, 2024
1120db7
Logo update
Jul 22, 2024
6a8e04a
Merge branch 'main' into feature/full-refactor
insani7y Aug 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 0 additions & 51 deletions microbootstrap/bootstrap.py
Original file line number Diff line number Diff line change
@@ -1,64 +1,13 @@
from __future__ import annotations
import contextlib
import typing


if typing.TYPE_CHECKING:
import granian

from microbootstrap.helpers import base as helpers_base
from microbootstrap.settings.base import BootstrapSettings


def bootstrap(
web_framework: type[
helpers_base.BootstrapWebFrameworkBootstrapper[
helpers_base.Application_contra,
helpers_base.Settings_contra,
helpers_base.ReturnType_co,
]
],
settings: helpers_base.Settings_contra,
app: helpers_base.Application_contra,
) -> helpers_base.ReturnType_co:
web_framework_bootstrapper = web_framework()
web_framework_bootstrapper.load_parameters(app=app, settings=settings)
return web_framework_bootstrapper.initialize()


def teardown(
web_framework: type[
helpers_base.BootstrapWebFrameworkBootstrapper[
helpers_base.Application_contra,
helpers_base.Settings_contra,
helpers_base.ReturnType_co,
]
],
settings: helpers_base.Settings_contra,
app: helpers_base.Application_contra,
) -> None:
web_framework_bootstrapper = web_framework()
web_framework_bootstrapper.load_parameters(app=app, settings=settings)
web_framework_bootstrapper.teardown()


@contextlib.contextmanager
def enter_bootstrapper_context(
*bootstrapper_classes: type[helpers_base.BootstrapServicesBootstrapper[helpers_base.Settings_contra]],
settings: helpers_base.Settings_contra,
) -> typing.Iterator[None]:
bootstrappers: typing.Final[list[helpers_base.BootstrapServicesBootstrapper[helpers_base.Settings_contra]]] = []
for one_class in bootstrapper_classes:
instance = one_class()
instance.load_parameters(settings)
instance.initialize()
bootstrappers.append(instance)

yield
for one_bootstrapper in bootstrappers:
one_bootstrapper.teardown()


def create_granian_server(
target: str,
settings: BootstrapSettings,
Expand Down
74 changes: 74 additions & 0 deletions microbootstrap/bootstrappers/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from __future__ import annotations
import dataclasses
import typing

from microbootstrap.helpers import dataclass_to_dict_no_defaults, merge_dataclasses_configs, merge_dict_configs
from microbootstrap.instruments import OpentelemetryInstrumentConfig, SentryInstrumentConfig


if typing.TYPE_CHECKING:
from microbootstrap.instruments import Instrument
from microbootstrap.settings.base import BootstrapSettings


ApplicationT = typing.TypeVar("ApplicationT")
SettingsT = typing.TypeVar("SettingsT", bound="BootstrapSettings")
SelfT = typing.TypeVar("SelfT", bound="ApplicationBootstrapper[typing.Any, typing.Any, typing.Any]")
insani7y marked this conversation as resolved.
Show resolved Hide resolved


@dataclasses.dataclass()
class ApplicationBootstrapper(typing.Protocol[SettingsT, ApplicationT, dataclasses._DataclassT]):
settings: SettingsT
application_type: type[ApplicationT] = dataclasses.field(init=False)
application_config: dataclasses._DataclassT = dataclasses.field(init=False)

sentry_instrument_type: type[Instrument[SentryInstrumentConfig]] = dataclasses.field(init=False)
insani7y marked this conversation as resolved.
Show resolved Hide resolved
opentelemetry_instrument_type: type[Instrument[OpentelemetryInstrumentConfig]] = dataclasses.field(init=False)

__sentry_instrument: Instrument[SentryInstrumentConfig] = dataclasses.field(init=False)
__opentelemetry_instrument: Instrument[OpentelemetryInstrumentConfig] = dataclasses.field(init=False)

def __post_init__(self) -> None:
insani7y marked this conversation as resolved.
Show resolved Hide resolved
settings_dump = self.settings.model_dump()
self.__sentry_instrument = self.sentry_instrument_type(SentryInstrumentConfig(**settings_dump))
self.__opentelemetry_instrument = self.opentelemetry_instrument_type(
OpentelemetryInstrumentConfig(**settings_dump),
)

def configure_application(self: SelfT, application_config: dataclasses._DataclassT) -> SelfT:
self.application_config = merge_dataclasses_configs(self.application_config, application_config)
insani7y marked this conversation as resolved.
Show resolved Hide resolved
return self

def configure_opentelemetry(
self: SelfT,
opentelemetry_config: OpentelemetryInstrumentConfig,
) -> SelfT:
self.opentelemetry_instrument.configure_instrument(opentelemetry_config)
return self

def configure_sentry(
self: SelfT,
sentry_config: SentryInstrumentConfig,
) -> SelfT:
self.sentry_instrument.configure_instrument(sentry_config)
return self

def configure_logging(self: SelfT) -> SelfT:
raise NotImplementedError

def bootstrap(self: SelfT) -> ApplicationT:
application_config_dict = dataclass_to_dict_no_defaults(self.application_config)
for instrument in self.__instruments:
application_config = merge_dict_configs(
application_config_dict,
instrument.bootstrap(),
)
return self.application_type(**application_config)

def teardown(self: SelfT) -> None:
for instrument in self.__instruments:
instrument.teardown()

@property
def __instruments(self) -> list[Instrument[typing.Any]]:
return [self.__sentry_instrument, self.__opentelemetry_instrument]
52 changes: 52 additions & 0 deletions microbootstrap/bootstrappers/litestar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from __future__ import annotations
import typing

import litestar
import litestar.types
import sentry_sdk
from litestar import status_codes
from litestar.config.app import AppConfig
from litestar.contrib.opentelemetry.config import OpentelemetryInstrumentConfig
from litestar.contrib.opentelemetry.middleware import OpenTelemetryInstrumentationMiddleware
from litestar.exceptions.http_exceptions import HTTPException

from microbootstrap.bootstrappers.base import ApplicationBootstrapper
from microbootstrap.instruments import OpentelemetryInstrument, SentryInstrument
from microbootstrap.settings.litestar import LitestarBootstrapSettings


class LitestarSentryInstrument(SentryInstrument):
@staticmethod
async def sentry_exception_catcher_hook(
exception: Exception,
_request_scope: litestar.types.Scope,
) -> None:
if (
not isinstance(exception, HTTPException)
or exception.status_code >= status_codes.HTTP_500_INTERNAL_SERVER_ERROR
):
sentry_sdk.capture_exception(exception)

@property
def successful_bootstrap_result(self) -> dict[str, typing.Any]:
return {"after_exception": [self.sentry_exception_catcher_hook]}


class LitetstarOpentelemetryInstrument(OpentelemetryInstrument):
@property
def successful_bootstrap_result(self) -> dict[str, typing.Any]:
return {
"middleware": OpenTelemetryInstrumentationMiddleware(
OpentelemetryInstrumentConfig(
tracer_provider=self.tracer_provider,
exclude=self.instrument_config.opentelemetry_exclude_urls,
),
),
}


class LitestarBootstrapper(
ApplicationBootstrapper[LitestarBootstrapSettings, litestar.Litestar, AppConfig],
):
sentry_instrument_type = LitestarSentryInstrument
opentelemetry_instrument_type = LitetstarOpentelemetryInstrument
6 changes: 6 additions & 0 deletions microbootstrap/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class MicroBootstrapBaseError(Exception):
"""Base for all exceptions."""


class ConfigMergeError(MicroBootstrapBaseError):
"""Raises when it's impossible to merge configs due to type mismatch."""
88 changes: 0 additions & 88 deletions microbootstrap/frameworks/fastapi.py

This file was deleted.

Loading
Loading