<p align="center">
<img src="https://raw.githubusercontent.com/community-of-python/microbootstrap/main/logo.svg" width="350">
</p>
<br>
<p align="center">
<a href="https://codecov.io/gh/community-of-python/microbootstrap" target="_blank"><img src="https://codecov.io/gh/community-of-python/microbootstrap/branch/main/graph/badge.svg"></a>
<a href="https://pypi.org/project/microbootstrap/" target="_blank"><img src="https://img.shields.io/pypi/pyversions/microbootstrap"></a>
<a href="https://pypi.org/project/microbootstrap/" target="_blank"><img src="https://img.shields.io/pypi/v/microbootstrap"></a>
<a href="https://pypistats.org/packages/microbootstrap" target="_blank"><img src="https://img.shields.io/pypi/dm/microbootstrap"></a>
</p>
<b>microbootstrap</b> assists you in creating applications with all the necessary instruments already set up.
```python
# settings.py
from microbootstrap import LitestarSettings
class YourSettings(LitestarSettings):
... # Your settings are stored here
settings = YourSettings()
# application.py
import litestar
from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
from your_application.settings import settings
# Use the Litestar application!
application: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()
```
With <b>microbootstrap</b>, you receive an application with lightweight built-in support for:
- `sentry`
- `prometheus`
- `opentelemetry`
- `logging`
- `cors`
- `swagger` - with additional offline version support
- `health-checks`
Those instruments can be bootstrapped for:
- `fastapi`
- `litestar`
Interested? Let's dive right in ⚡
## Table of Contents
- [Installation](#installation)
- [Quickstart](#quickstart)
- [Settings](#settings)
- [Service settings](#service-settings)
- [Instruments](#instruments)
- [Sentry](#sentry)
- [Prometheus](#prometheus)
- [Opentelemetry](#opentelemetry)
- [Logging](#logging)
- [CORS](#cors)
- [Swagger](#swagger)
- [Health checks](#health-checks)
- [Configuration](#configuration)
- [Instruments configuration](#instruments-configuration)
- [Application configuration](#application-configuration)
- [Advanced](#advanced)
## Installation
You can install the package using either `pip` or `poetry`.
Also, you can specify extras during installation for concrete framework:
- `fastapi`
- `litestar`
For poetry:
```bash
$ poetry add microbootstrap -E fastapi
```
For pip:
```bash
$ pip install microbootstrap[fastapi]
```
## Quickstart
To configure your application, you can use the settings object.
```python
from microbootstrap import LitestarSettings
class YourSettings(LitestarSettings):
# General settings
service_debug: bool = False
service_name: str = "my-awesome-service"
# Sentry settings
sentry_dsn: str = "your-sentry-dsn"
# Prometheus settings
prometheus_metrics_path: str = "/my-path"
# Opentelemetry settings
opentelemetry_container_name: str = "your-container"
opentelemetry_endpoint: str = "/opentelemetry-endpoint"
settings = YourSettings()
```
Next, use the `Bootstrapper` object to create an application based on your settings.
```python
import litestar
from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
application: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()
```
This approach will provide you with an application that has all the essential instruments already set up for you.
## Settings
The settings object is the core of microbootstrap.
All framework-related settings inherit from the `BaseServiceSettings` object. `BaseServiceSettings` defines parameters for the service and various instruments.
However, the number of parameters is <b>not confined</b> to those defined in `BaseServiceSettings`. You can add as many as you need.
These parameters can be sourced from your environment. By default, no prefix is added to these parameters.
Example:
```python
class YourSettings(BaseServiceSettings):
service_debug: bool = True
service_name: str = "micro-service"
your_awesome_parameter: str = "really awesome"
... # Other settings here
```
To source `your_awesome_parameter` from the environment, set the environment variable named `YOUR_AWESOME_PARAMETER`.
If you prefer to use a prefix when sourcing parameters, set the `ENVIRONMENT_PREFIX` environment variable in advance.
Example:
```bash
$ export ENVIRONMENT_PREFIX=YOUR_PREFIX_
```
Then the settings object will attempt to source the variable named `YOUR_PREFIX_YOUR_AWESOME_PARAMETER`.
## Service settings
Each settings object for every framework includes service parameters that can be utilized by various instruments.
You can configure them manually, or set the corresponding environment variables and let <b>microbootstrap</b> to source them automatically.
```python
from microbootstrap.settings import BaseServiceSettings
class ServiceSettings(BaseServiceSettings):
service_debug: bool = True
service_environment: str | None = None
service_name: str = "micro-service"
service_description: str = "Micro service description"
service_version: str = "1.0.0"
... # Other settings here
```
## Instruments
At present, the following instruments are supported for bootstrapping:
- `sentry`
- `prometheus`
- `opentelemetry`
- `logging`
- `cors`
- `swagger`
Let's clarify the process required to bootstrap these instruments.
### Sentry
To bootstrap Sentry, you must provide at least the `sentry_dsn`.
Additional parameters can also be supplied through the settings object.
```python
from microbootstrap.settings import BaseServiceSettings
class YourSettings(BaseServiceSettings):
service_environment: str | None = None
sentry_dsn: str | None = None
sentry_traces_sample_rate: float | None = None
sentry_sample_rate: float = pydantic.Field(default=1.0, le=1.0, ge=0.0)
sentry_max_breadcrumbs: int = 15
sentry_max_value_length: int = 16384
sentry_attach_stacktrace: bool = True
sentry_integrations: list[Integration] = []
sentry_additional_params: dict[str, typing.Any] = {}
... # Other settings here
```
These settings are subsequently passed to the [sentry-sdk](https://pypi.org/project/sentry-sdk/) package, finalizing your Sentry integration.
### Prometheus
Prometheus integration presents a challenge because the underlying libraries for `FastAPI` and `Litestar` differ significantly, making it impossible to unify them under a single interface. As a result, the Prometheus settings for `FastAPI` and `Litestar` must be configured separately.
#### Fastapi
To bootstrap prometheus you have to provide `prometheus_metrics_path`
```python
from microbootstrap.settings import FastApiSettings
class YourFastApiSettings(FastApiSettings):
service_name: str
prometheus_metrics_path: str = "/metrics"
prometheus_metrics_include_in_schema: bool = False
prometheus_instrumentator_params: dict[str, typing.Any] = {}
prometheus_instrument_params: dict[str, typing.Any] = {}
prometheus_expose_params: dict[str, typing.Any] = {}
... # Other settings here
```
Parameters description:
- `service_name` - will be attached to metric's names, but has to be named in [snake_case](https://en.wikipedia.org/wiki/Snake_case).
- `prometheus_metrics_path` - path to metrics handler.
- `prometheus_metrics_include_in_schema` - whether to include metrics route in OpenAPI schema.
- `prometheus_instrumentator_params` - will be passed to `Instrumentor` during initialization.
- `prometheus_instrument_params` - will be passed to `Instrumentor.instrument(...)`.
- `prometheus_expose_params` - will be passed to `Instrumentor.expose(...)`.
FastApi prometheus bootstrapper uses [prometheus-fastapi-instrumentator](https://github.com/trallnag/prometheus-fastapi-instrumentator) that's why there are three different dict for parameters.
#### Fastapi
To bootstrap prometheus you have to provide `prometheus_metrics_path`
```python
from microbootstrap.settings import LitestarSettings
class YourFastApiSettings(LitestarSettings):
service_name: str
prometheus_metrics_path: str = "/metrics"
prometheus_additional_params: dict[str, typing.Any] = {}
... # Other settings here
```
Parameters description:
- `service_name` - will be attached to metric's names, there are no name restrictions.
- `prometheus_metrics_path` - path to metrics handler.
- `prometheus_additional_params` - will be passed to `litestar.contrib.prometheus.PrometheusConfig`.
### Opentelemetry
To bootstrap Opentelemetry, you must provide several parameters:
- `service_name`
- `service_version`
- `opentelemetry_endpoint`
- `opentelemetry_namespace`
- `opentelemetry_container_name`
However, additional parameters can also be supplied if needed.
```python
from microbootstrap.settings import BaseServiceSettings
from microbootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrumentor
class YourSettings(BaseServiceSettings):
service_name: str
service_version: str
opentelemetry_container_name: str | None = None
opentelemetry_endpoint: str | None = None
opentelemetry_namespace: str | None = None
opentelemetry_insecure: bool = True
opentelemetry_instrumentors: list[OpenTelemetryInstrumentor] = []
opentelemetry_exclude_urls: list[str] = []
... # Other settings here
```
Parameters description:
- `service_name` - will be passed to the `Resource`.
- `service_version` - will be passed to the `Resource`.
- `opentelemetry_endpoint` - will be passed to `OTLPSpanExporter` as endpoint.
- `opentelemetry_namespace` - will be passed to the `Resource`.
- `opentelemetry_insecure` - is opentelemetry connection secure.
- `opentelemetry_container_name` - will be passed to the `Resource`.
- `opentelemetry_instrumentors` - a list of extra instrumentors.
- `opentelemetry_exclude_urls` - list of ignored urls.
These settings are subsequently passed to [opentelemetry](https://opentelemetry.io/), finalizing your Opentelemetry integration.
### Logging
<b>microbootstrap</b> provides in-memory JSON logging through the use of [structlog](https://pypi.org/project/structlog/).
For more information on in-memory logging, refer to [MemoryHandler](https://docs.python.org/3/library/logging.handlers.html#memoryhandler).
To utilize this feature, your application must be in non-debug mode, meaning `service_debug` should be set to `False`.
```python
import logging
from microbootstrap.settings import BaseServiceSettings
class YourSettings(BaseServiceSettings):
service_debug: bool = False
logging_log_level: int = logging.INFO
logging_flush_level: int = logging.ERROR
logging_buffer_capacity: int = 10
logging_unset_handlers: list[str] = ["uvicorn", "uvicorn.access"]
logging_extra_processors: list[typing.Any] = []
logging_exclude_endpoints: list[str] = []
```
Parameters description:
- `logging_log_level` - The default log level.
- `logging_flush_level` - All messages will be flushed from the buffer when a log with this level appears.
- `logging_buffer_capacity` - The number of messages your buffer will store before being flushed.
- `logging_unset_handlers` - Unset logger handlers.
- `logging_extra_processors` - Set additional structlog processors if needed.
- `logging_exclude_endpoints` - Exclude logging on specific endpoints.
### CORS
```python
from microbootstrap.settings import BaseServiceSettings
class YourSettings(BaseServiceSettings):
cors_allowed_origins: list[str] = pydantic.Field(default_factory=list)
cors_allowed_methods: list[str] = pydantic.Field(default_factory=list)
cors_allowed_headers: list[str] = pydantic.Field(default_factory=list)
cors_exposed_headers: list[str] = pydantic.Field(default_factory=list)
cors_allowed_credentials: bool = False
cors_allowed_origin_regex: str | None = None
cors_max_age: int = 600
```
Parameter descriptions:
- `cors_allowed_origins` - A list of origins that are permitted.
- `cors_allowed_methods` - A list of HTTP methods that are allowed.
- `cors_allowed_headers` - A list of headers that are permitted.
- `cors_exposed_headers` - A list of headers that are exposed via the 'Access-Control-Expose-Headers' header.
- `cors_allowed_credentials` - A boolean value that dictates whether or not to set the 'Access-Control-Allow-Credentials' header.
- `cors_allowed_origin_regex` - A regex used to match against origins.
- `cors_max_age` - The response caching Time-To-Live (TTL) in seconds, defaults to 600.
### Swagger
```python
from microbootstrap.settings import BaseServiceSettings
class YourSettings(BaseServiceSettings):
service_name: str = "micro-service"
service_description: str = "Micro service description"
service_version: str = "1.0.0"
service_static_path: str = "/static"
swagger_path: str = "/docs"
swagger_offline_docs: bool = False
swagger_extra_params: dict[str, Any] = {}
```
Parameter descriptions:
- `service_name` - The name of the service, which will be displayed in the documentation.
- `service_description` - A brief description of the service, which will also be displayed in the documentation.
- `service_version` - The current version of the service.
- `service_static_path` - The path for static files in the service.
- `swagger_path` - The path where the documentation can be found.
- `swagger_offline_docs` - A boolean value that, when set to True, allows the Swagger JS bundles to be accessed offline. This is because the service starts to host via static.
- `swagger_extra_params` - Additional parameters to pass into the OpenAPI configuration.
### Health checks
```python
from microbootstrap.settings import BaseServiceSettings
class YourSettings(BaseServiceSettings):
service_name: str = "micro-service"
service_version: str = "1.0.0"
health_checks_enabled: bool = True
health_checks_path: str = "/health/"
health_checks_include_in_schema: bool = False
```
Parameter descriptions:
- `service_name` - Will be displayed in health check response.
- `service_version` - Will be displayed in health check response.
- `health_checks_enabled` - Must be True to enable health checks.
- `health_checks_path` - Path for health check handler.
- `health_checks_include_in_schema` - Must be True to include `health_checks_path` (`/health/`) in OpenAPI schema.
## Configuration
While settings provide a convenient mechanism, it's not always feasible to store everything within them.
There may be cases where you need to configure a tool directly. Here's how it can be done.
### Instruments configuration
To manually configure an instrument, you need to import one of the available configurations from <b>microbootstrap</b>:
- `SentryConfig`
- `OpentelemetryConfig`
- `PrometheusConfig`
- `LoggingConfig`
- `SwaggerConfig`
- `CorsConfig`
These configurations can then be passed into the `.configure_instrument` or `.configure_instruments` bootstrapper methods.
```python
import litestar
from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
from microbootstrap import SentryConfig, OpentelemetryConfig
application: litestar.Litestar = (
LitestarBootstrapper(settings)
.configure_instrument(SentryConfig(sentry_dsn="https://new-dsn"))
.configure_instrument(OpentelemetryConfig(opentelemetry_endpoint="/new-endpoint"))
.bootstrap()
)
```
Alternatively,
```python
import litestar
from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
from microbootstrap import SentryConfig, OpentelemetryConfig
application: litestar.Litestar = (
LitestarBootstrapper(settings)
.configure_instruments(
SentryConfig(sentry_dsn="https://examplePublicKey@o0.ingest.sentry.io/0"),
OpentelemetryConfig(opentelemetry_endpoint="/new-endpoint")
)
.bootstrap()
)
```
### Application configuration
The application can be configured in a similar manner:
```python
import litestar
from microbootstrap.config.litestar import LitestarConfig
from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
from microbootstrap import SentryConfig, OpentelemetryConfig
@litestar.get("/my-handler")
async def my_handler() -> str:
return "Ok"
application: litestar.Litestar = (
LitestarBootstrapper(settings)
.configure_application(LitestarConfig(route_handlers=[my_handler]))
.bootstrap()
)
```
> ### Important
>
> When configuring parameters with simple data types such as: `str`, `int`, `float`, etc., these variables overwrite previous values.
>
> Example:
>
> ```python
> from microbootstrap import LitestarSettings, SentryConfig
>
>
> class YourSettings(LitestarSettings):
> sentry_dsn: str = "https://my-sentry-dsn"
>
>
> application: litestar.Litestar = (
> LitestarBootstrapper(YourSettings())
> .configure_instrument(
> SentryConfig(sentry_dsn="https://my-new-configured-sentry-dsn")
> )
> .bootstrap()
> )
> ```
>
> In this example, the application will be bootstrapped with the new `https://my-new-configured-sentry-dsn` Sentry DSN, replacing the old one.
>
> However, when you configure parameters with complex data types such as: `list`, `tuple`, `dict`, or `set`, they are expanded or merged.
>
> Example:
>
> ```python
> from microbootstrap import LitestarSettings, PrometheusConfig
>
>
> class YourSettings(LitestarSettings):
> prometheus_additional_params: dict[str, Any] = {"first_value": 1}
>
>
> application: litestar.Litestar = (
> LitestarBootstrapper(YourSettings())
> .configure_instrument(
> PrometheusConfig(prometheus_additional_params={"second_value": 2})
> )
> .bootstrap()
> )
> ```
>
> In this case, Prometheus will receive `{"first_value": 1, "second_value": 2}` inside `prometheus_additional_params`. This is also true for `list`, `tuple`, and `set`.
### Using microbootstrap without a framework
When working on projects that don't use Litestar or FastAPI, you can still take advantage of monitoring and logging capabilities using `InstrumentsSetupper`. This class sets up Sentry, OpenTelemetry, and Logging instruments in a way that's easy to integrate with your project.
You can use `InstrumentsSetupper` as a context manager, like this:
```python
from microbootstrap.instruments_setupper import InstrumentsSetupper
from microbootstrap import InstrumentsSetupperSettings
class YourSettings(InstrumentsSetupperSettings):
...
with InstrumentsSetupper(YourSettings()):
while True:
print("doing something useful")
time.sleep(1)
```
Alternatively, you can use the `setup()` and `teardown()` methods instead of a context manager:
```python
current_setupper = InstrumentsSetupper(YourSettings())
current_setupper.setup()
try:
while True:
print("doing something useful")
time.sleep(1)
finally:
current_setupper.teardown()
```
Like bootstrappers, you can reconfigure instruments using the `configure_instrument()` and `configure_instruments()` methods.
## Advanced
If you miss some instrument, you can add your own.
Essentially, `Instrument` is just a class with some abstractmethods.
Every instrument uses some config, so that's first thing, you have to define.
```python
from microbootstrap.instruments.base import BaseInstrumentConfig
class MyInstrumentConfig(BaseInstrumentConfig):
your_string_parameter: str
your_list_parameter: list
```
Next, you can create an instrument class that inherits from `Instrument` and accepts your configuration as a generic parameter.
```python
from microbootstrap.instruments.base import Instrument
class MyInstrument(Instrument[MyInstrumentConfig]):
instrument_name: str
ready_condition: str
def is_ready(self) -> bool:
pass
def teardown(self) -> None:
pass
def bootstrap(self) -> None:
pass
@classmethod
def get_config_type(cls) -> type[MyInstrumentConfig]:
return MyInstrumentConfig
```
Now, you can define the behavior of your instrument.
Attributes:
- `instrument_name` - This will be displayed in your console during bootstrap.
- `ready_condition` - This will be displayed in your console during bootstrap if the instrument is not ready.
Methods:
- `is_ready` - This defines the readiness of the instrument for bootstrapping, based on its configuration values. This is required.
- `teardown` - This allows for a graceful shutdown of the instrument during application shutdown. This is not required.
- `bootstrap` - This is the main logic of the instrument. This is not required.
Once you have the framework of the instrument, you can adapt it for any existing framework. For instance, let's adapt it for litestar.
```python
import litestar
from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
@LitestarBootstrapper.use_instrument()
class LitestarMyInstrument(MyInstrument):
def bootstrap_before(self) -> dict[str, typing.Any]:
pass
def bootstrap_after(self, application: litestar.Litestar) -> dict[str, typing.Any]:
pass
```
To bind the instrument to a bootstrapper, use the `.use_instrument` decorator.
To add extra parameters to the application, you can use:
- `bootstrap_before` - This adds arguments to the application configuration before creation.
- `bootstrap_after` - This adds arguments to the application after creation.
Afterwards, you can use your instrument during the bootstrap process.
```python
import litestar
from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
from microbootstrap import SentryConfig, OpentelemetryConfig
from your_app import MyInstrumentConfig
application: litestar.Litestar = (
LitestarBootstrapper(settings)
.configure_instrument(
MyInstrumentConfig(
your_string_parameter="very-nice-parameter",
your_list_parameter=["very-special-list"],
)
)
.bootstrap()
)
```
Alternatively, you can fill these parameters within your main settings object.
```python
from microbootstrap import LitestarSettings
from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
from your_app import MyInstrumentConfig
class YourSettings(LitestarSettings, MyInstrumentConfig):
your_string_parameter: str = "very-nice-parameter"
your_list_parameter: list = ["very-special-list"]
settings = YourSettings()
application: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()
```
Raw data
{
"_id": null,
"home_page": null,
"name": "microbootstrap",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.9",
"maintainer_email": null,
"keywords": "python, microservice, bootstrap, opentelemetry, logging, error-tracing, litestar, fastapi",
"author": "community-of-python",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/43/24/8481aeab4e20f901024879e98656f7d23d57c20d7b65567434fdcb4926bf/microbootstrap-0.8.1.tar.gz",
"platform": null,
"description": "<p align=\"center\">\n <img src=\"https://raw.githubusercontent.com/community-of-python/microbootstrap/main/logo.svg\" width=\"350\">\n</p>\n<br>\n<p align=\"center\">\n <a href=\"https://codecov.io/gh/community-of-python/microbootstrap\" target=\"_blank\"><img src=\"https://codecov.io/gh/community-of-python/microbootstrap/branch/main/graph/badge.svg\"></a>\n <a href=\"https://pypi.org/project/microbootstrap/\" target=\"_blank\"><img src=\"https://img.shields.io/pypi/pyversions/microbootstrap\"></a>\n <a href=\"https://pypi.org/project/microbootstrap/\" target=\"_blank\"><img src=\"https://img.shields.io/pypi/v/microbootstrap\"></a>\n <a href=\"https://pypistats.org/packages/microbootstrap\" target=\"_blank\"><img src=\"https://img.shields.io/pypi/dm/microbootstrap\"></a>\n</p>\n\n<b>microbootstrap</b> assists you in creating applications with all the necessary instruments already set up.\n\n```python\n# settings.py\nfrom microbootstrap import LitestarSettings\n\n\nclass YourSettings(LitestarSettings):\n ... # Your settings are stored here\n\n\nsettings = YourSettings()\n\n\n# application.py\nimport litestar\nfrom microbootstrap.bootstrappers.litestar import LitestarBootstrapper\n\nfrom your_application.settings import settings\n\n# Use the Litestar application!\napplication: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()\n```\n\nWith <b>microbootstrap</b>, you receive an application with lightweight built-in support for:\n\n- `sentry`\n- `prometheus`\n- `opentelemetry`\n- `logging`\n- `cors`\n- `swagger` - with additional offline version support\n- `health-checks`\n\nThose instruments can be bootstrapped for:\n\n- `fastapi`\n- `litestar`\n\nInterested? Let's dive right in \u26a1\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Quickstart](#quickstart)\n- [Settings](#settings)\n- [Service settings](#service-settings)\n- [Instruments](#instruments)\n - [Sentry](#sentry)\n - [Prometheus](#prometheus)\n - [Opentelemetry](#opentelemetry)\n - [Logging](#logging)\n - [CORS](#cors)\n - [Swagger](#swagger)\n - [Health checks](#health-checks)\n- [Configuration](#configuration)\n - [Instruments configuration](#instruments-configuration)\n - [Application configuration](#application-configuration)\n- [Advanced](#advanced)\n\n## Installation\n\nYou can install the package using either `pip` or `poetry`.\nAlso, you can specify extras during installation for concrete framework:\n\n- `fastapi`\n- `litestar`\n\nFor poetry:\n\n```bash\n$ poetry add microbootstrap -E fastapi\n```\n\nFor pip:\n\n```bash\n$ pip install microbootstrap[fastapi]\n```\n\n## Quickstart\n\nTo configure your application, you can use the settings object.\n\n```python\nfrom microbootstrap import LitestarSettings\n\n\nclass YourSettings(LitestarSettings):\n # General settings\n service_debug: bool = False\n service_name: str = \"my-awesome-service\"\n\n # Sentry settings\n sentry_dsn: str = \"your-sentry-dsn\"\n\n # Prometheus settings\n prometheus_metrics_path: str = \"/my-path\"\n\n # Opentelemetry settings\n opentelemetry_container_name: str = \"your-container\"\n opentelemetry_endpoint: str = \"/opentelemetry-endpoint\"\n\n\n\nsettings = YourSettings()\n```\n\nNext, use the `Bootstrapper` object to create an application based on your settings.\n\n```python\nimport litestar\nfrom microbootstrap.bootstrappers.litestar import LitestarBootstrapper\n\napplication: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()\n```\n\nThis approach will provide you with an application that has all the essential instruments already set up for you.\n\n## Settings\n\nThe settings object is the core of microbootstrap.\n\nAll framework-related settings inherit from the `BaseServiceSettings` object. `BaseServiceSettings` defines parameters for the service and various instruments.\n\nHowever, the number of parameters is <b>not confined</b> to those defined in `BaseServiceSettings`. You can add as many as you need.\n\nThese parameters can be sourced from your environment. By default, no prefix is added to these parameters.\n\nExample:\n\n```python\nclass YourSettings(BaseServiceSettings):\n service_debug: bool = True\n service_name: str = \"micro-service\"\n\n your_awesome_parameter: str = \"really awesome\"\n\n ... # Other settings here\n```\n\nTo source `your_awesome_parameter` from the environment, set the environment variable named `YOUR_AWESOME_PARAMETER`.\n\nIf you prefer to use a prefix when sourcing parameters, set the `ENVIRONMENT_PREFIX` environment variable in advance.\n\nExample:\n\n```bash\n$ export ENVIRONMENT_PREFIX=YOUR_PREFIX_\n```\n\nThen the settings object will attempt to source the variable named `YOUR_PREFIX_YOUR_AWESOME_PARAMETER`.\n\n## Service settings\n\nEach settings object for every framework includes service parameters that can be utilized by various instruments.\n\nYou can configure them manually, or set the corresponding environment variables and let <b>microbootstrap</b> to source them automatically.\n\n```python\nfrom microbootstrap.settings import BaseServiceSettings\n\n\nclass ServiceSettings(BaseServiceSettings):\n service_debug: bool = True\n service_environment: str | None = None\n service_name: str = \"micro-service\"\n service_description: str = \"Micro service description\"\n service_version: str = \"1.0.0\"\n\n ... # Other settings here\n\n```\n\n## Instruments\n\nAt present, the following instruments are supported for bootstrapping:\n\n- `sentry`\n- `prometheus`\n- `opentelemetry`\n- `logging`\n- `cors`\n- `swagger`\n\nLet's clarify the process required to bootstrap these instruments.\n\n### Sentry\n\nTo bootstrap Sentry, you must provide at least the `sentry_dsn`.\nAdditional parameters can also be supplied through the settings object.\n\n```python\nfrom microbootstrap.settings import BaseServiceSettings\n\n\nclass YourSettings(BaseServiceSettings):\n service_environment: str | None = None\n\n sentry_dsn: str | None = None\n sentry_traces_sample_rate: float | None = None\n sentry_sample_rate: float = pydantic.Field(default=1.0, le=1.0, ge=0.0)\n sentry_max_breadcrumbs: int = 15\n sentry_max_value_length: int = 16384\n sentry_attach_stacktrace: bool = True\n sentry_integrations: list[Integration] = []\n sentry_additional_params: dict[str, typing.Any] = {}\n\n ... # Other settings here\n```\n\nThese settings are subsequently passed to the [sentry-sdk](https://pypi.org/project/sentry-sdk/) package, finalizing your Sentry integration.\n\n### Prometheus\n\nPrometheus integration presents a challenge because the underlying libraries for `FastAPI` and `Litestar` differ significantly, making it impossible to unify them under a single interface. As a result, the Prometheus settings for `FastAPI` and `Litestar` must be configured separately.\n\n#### Fastapi\n\nTo bootstrap prometheus you have to provide `prometheus_metrics_path`\n\n```python\nfrom microbootstrap.settings import FastApiSettings\n\n\nclass YourFastApiSettings(FastApiSettings):\n service_name: str\n\n prometheus_metrics_path: str = \"/metrics\"\n prometheus_metrics_include_in_schema: bool = False\n prometheus_instrumentator_params: dict[str, typing.Any] = {}\n prometheus_instrument_params: dict[str, typing.Any] = {}\n prometheus_expose_params: dict[str, typing.Any] = {}\n\n ... # Other settings here\n```\n\nParameters description:\n\n- `service_name` - will be attached to metric's names, but has to be named in [snake_case](https://en.wikipedia.org/wiki/Snake_case).\n- `prometheus_metrics_path` - path to metrics handler.\n- `prometheus_metrics_include_in_schema` - whether to include metrics route in OpenAPI schema.\n- `prometheus_instrumentator_params` - will be passed to `Instrumentor` during initialization.\n- `prometheus_instrument_params` - will be passed to `Instrumentor.instrument(...)`.\n- `prometheus_expose_params` - will be passed to `Instrumentor.expose(...)`.\n\nFastApi prometheus bootstrapper uses [prometheus-fastapi-instrumentator](https://github.com/trallnag/prometheus-fastapi-instrumentator) that's why there are three different dict for parameters.\n\n#### Fastapi\n\nTo bootstrap prometheus you have to provide `prometheus_metrics_path`\n\n```python\nfrom microbootstrap.settings import LitestarSettings\n\n\nclass YourFastApiSettings(LitestarSettings):\n service_name: str\n\n prometheus_metrics_path: str = \"/metrics\"\n prometheus_additional_params: dict[str, typing.Any] = {}\n\n ... # Other settings here\n```\n\nParameters description:\n\n- `service_name` - will be attached to metric's names, there are no name restrictions.\n- `prometheus_metrics_path` - path to metrics handler.\n- `prometheus_additional_params` - will be passed to `litestar.contrib.prometheus.PrometheusConfig`.\n\n### Opentelemetry\n\nTo bootstrap Opentelemetry, you must provide several parameters:\n\n- `service_name`\n- `service_version`\n- `opentelemetry_endpoint`\n- `opentelemetry_namespace`\n- `opentelemetry_container_name`\n\nHowever, additional parameters can also be supplied if needed.\n\n```python\nfrom microbootstrap.settings import BaseServiceSettings\nfrom microbootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrumentor\n\n\nclass YourSettings(BaseServiceSettings):\n service_name: str\n service_version: str\n\n opentelemetry_container_name: str | None = None\n opentelemetry_endpoint: str | None = None\n opentelemetry_namespace: str | None = None\n opentelemetry_insecure: bool = True\n opentelemetry_instrumentors: list[OpenTelemetryInstrumentor] = []\n opentelemetry_exclude_urls: list[str] = []\n\n ... # Other settings here\n```\n\nParameters description:\n\n- `service_name` - will be passed to the `Resource`.\n- `service_version` - will be passed to the `Resource`.\n- `opentelemetry_endpoint` - will be passed to `OTLPSpanExporter` as endpoint.\n- `opentelemetry_namespace` - will be passed to the `Resource`.\n- `opentelemetry_insecure` - is opentelemetry connection secure.\n- `opentelemetry_container_name` - will be passed to the `Resource`.\n- `opentelemetry_instrumentors` - a list of extra instrumentors.\n- `opentelemetry_exclude_urls` - list of ignored urls.\n\nThese settings are subsequently passed to [opentelemetry](https://opentelemetry.io/), finalizing your Opentelemetry integration.\n\n### Logging\n\n<b>microbootstrap</b> provides in-memory JSON logging through the use of [structlog](https://pypi.org/project/structlog/).\nFor more information on in-memory logging, refer to [MemoryHandler](https://docs.python.org/3/library/logging.handlers.html#memoryhandler).\n\nTo utilize this feature, your application must be in non-debug mode, meaning `service_debug` should be set to `False`.\n\n```python\nimport logging\n\nfrom microbootstrap.settings import BaseServiceSettings\n\n\nclass YourSettings(BaseServiceSettings):\n service_debug: bool = False\n\n logging_log_level: int = logging.INFO\n logging_flush_level: int = logging.ERROR\n logging_buffer_capacity: int = 10\n logging_unset_handlers: list[str] = [\"uvicorn\", \"uvicorn.access\"]\n logging_extra_processors: list[typing.Any] = []\n logging_exclude_endpoints: list[str] = []\n```\n\nParameters description:\n\n- `logging_log_level` - The default log level.\n- `logging_flush_level` - All messages will be flushed from the buffer when a log with this level appears.\n- `logging_buffer_capacity` - The number of messages your buffer will store before being flushed.\n- `logging_unset_handlers` - Unset logger handlers.\n- `logging_extra_processors` - Set additional structlog processors if needed.\n- `logging_exclude_endpoints` - Exclude logging on specific endpoints.\n\n### CORS\n\n```python\nfrom microbootstrap.settings import BaseServiceSettings\n\n\nclass YourSettings(BaseServiceSettings):\n cors_allowed_origins: list[str] = pydantic.Field(default_factory=list)\n cors_allowed_methods: list[str] = pydantic.Field(default_factory=list)\n cors_allowed_headers: list[str] = pydantic.Field(default_factory=list)\n cors_exposed_headers: list[str] = pydantic.Field(default_factory=list)\n cors_allowed_credentials: bool = False\n cors_allowed_origin_regex: str | None = None\n cors_max_age: int = 600\n```\n\nParameter descriptions:\n\n- `cors_allowed_origins` - A list of origins that are permitted.\n- `cors_allowed_methods` - A list of HTTP methods that are allowed.\n- `cors_allowed_headers` - A list of headers that are permitted.\n- `cors_exposed_headers` - A list of headers that are exposed via the 'Access-Control-Expose-Headers' header.\n- `cors_allowed_credentials` - A boolean value that dictates whether or not to set the 'Access-Control-Allow-Credentials' header.\n- `cors_allowed_origin_regex` - A regex used to match against origins.\n- `cors_max_age` - The response caching Time-To-Live (TTL) in seconds, defaults to 600.\n\n### Swagger\n\n```python\nfrom microbootstrap.settings import BaseServiceSettings\n\n\nclass YourSettings(BaseServiceSettings):\n service_name: str = \"micro-service\"\n service_description: str = \"Micro service description\"\n service_version: str = \"1.0.0\"\n service_static_path: str = \"/static\"\n\n swagger_path: str = \"/docs\"\n swagger_offline_docs: bool = False\n swagger_extra_params: dict[str, Any] = {}\n```\n\nParameter descriptions:\n\n- `service_name` - The name of the service, which will be displayed in the documentation.\n- `service_description` - A brief description of the service, which will also be displayed in the documentation.\n- `service_version` - The current version of the service.\n- `service_static_path` - The path for static files in the service.\n- `swagger_path` - The path where the documentation can be found.\n- `swagger_offline_docs` - A boolean value that, when set to True, allows the Swagger JS bundles to be accessed offline. This is because the service starts to host via static.\n- `swagger_extra_params` - Additional parameters to pass into the OpenAPI configuration.\n\n### Health checks\n\n```python\nfrom microbootstrap.settings import BaseServiceSettings\n\n\nclass YourSettings(BaseServiceSettings):\n service_name: str = \"micro-service\"\n service_version: str = \"1.0.0\"\n\n health_checks_enabled: bool = True\n health_checks_path: str = \"/health/\"\n health_checks_include_in_schema: bool = False\n```\n\nParameter descriptions:\n\n- `service_name` - Will be displayed in health check response.\n- `service_version` - Will be displayed in health check response.\n- `health_checks_enabled` - Must be True to enable health checks.\n- `health_checks_path` - Path for health check handler.\n- `health_checks_include_in_schema` - Must be True to include `health_checks_path` (`/health/`) in OpenAPI schema.\n\n## Configuration\n\nWhile settings provide a convenient mechanism, it's not always feasible to store everything within them.\n\nThere may be cases where you need to configure a tool directly. Here's how it can be done.\n\n### Instruments configuration\n\nTo manually configure an instrument, you need to import one of the available configurations from <b>microbootstrap</b>:\n\n- `SentryConfig`\n- `OpentelemetryConfig`\n- `PrometheusConfig`\n- `LoggingConfig`\n- `SwaggerConfig`\n- `CorsConfig`\n\nThese configurations can then be passed into the `.configure_instrument` or `.configure_instruments` bootstrapper methods.\n\n```python\nimport litestar\n\nfrom microbootstrap.bootstrappers.litestar import LitestarBootstrapper\nfrom microbootstrap import SentryConfig, OpentelemetryConfig\n\n\napplication: litestar.Litestar = (\n LitestarBootstrapper(settings)\n .configure_instrument(SentryConfig(sentry_dsn=\"https://new-dsn\"))\n .configure_instrument(OpentelemetryConfig(opentelemetry_endpoint=\"/new-endpoint\"))\n .bootstrap()\n)\n```\n\nAlternatively,\n\n```python\nimport litestar\n\nfrom microbootstrap.bootstrappers.litestar import LitestarBootstrapper\nfrom microbootstrap import SentryConfig, OpentelemetryConfig\n\n\napplication: litestar.Litestar = (\n LitestarBootstrapper(settings)\n .configure_instruments(\n SentryConfig(sentry_dsn=\"https://examplePublicKey@o0.ingest.sentry.io/0\"),\n OpentelemetryConfig(opentelemetry_endpoint=\"/new-endpoint\")\n )\n .bootstrap()\n)\n```\n\n### Application configuration\n\nThe application can be configured in a similar manner:\n\n```python\nimport litestar\n\nfrom microbootstrap.config.litestar import LitestarConfig\nfrom microbootstrap.bootstrappers.litestar import LitestarBootstrapper\nfrom microbootstrap import SentryConfig, OpentelemetryConfig\n\n\n@litestar.get(\"/my-handler\")\nasync def my_handler() -> str:\n return \"Ok\"\n\napplication: litestar.Litestar = (\n LitestarBootstrapper(settings)\n .configure_application(LitestarConfig(route_handlers=[my_handler]))\n .bootstrap()\n)\n```\n\n> ### Important\n>\n> When configuring parameters with simple data types such as: `str`, `int`, `float`, etc., these variables overwrite previous values.\n>\n> Example:\n>\n> ```python\n> from microbootstrap import LitestarSettings, SentryConfig\n>\n>\n> class YourSettings(LitestarSettings):\n> sentry_dsn: str = \"https://my-sentry-dsn\"\n>\n>\n> application: litestar.Litestar = (\n> LitestarBootstrapper(YourSettings())\n> .configure_instrument(\n> SentryConfig(sentry_dsn=\"https://my-new-configured-sentry-dsn\")\n> )\n> .bootstrap()\n> )\n> ```\n>\n> In this example, the application will be bootstrapped with the new `https://my-new-configured-sentry-dsn` Sentry DSN, replacing the old one.\n>\n> However, when you configure parameters with complex data types such as: `list`, `tuple`, `dict`, or `set`, they are expanded or merged.\n>\n> Example:\n>\n> ```python\n> from microbootstrap import LitestarSettings, PrometheusConfig\n>\n>\n> class YourSettings(LitestarSettings):\n> prometheus_additional_params: dict[str, Any] = {\"first_value\": 1}\n>\n>\n> application: litestar.Litestar = (\n> LitestarBootstrapper(YourSettings())\n> .configure_instrument(\n> PrometheusConfig(prometheus_additional_params={\"second_value\": 2})\n> )\n> .bootstrap()\n> )\n> ```\n>\n> In this case, Prometheus will receive `{\"first_value\": 1, \"second_value\": 2}` inside `prometheus_additional_params`. This is also true for `list`, `tuple`, and `set`.\n\n### Using microbootstrap without a framework\n\nWhen working on projects that don't use Litestar or FastAPI, you can still take advantage of monitoring and logging capabilities using `InstrumentsSetupper`. This class sets up Sentry, OpenTelemetry, and Logging instruments in a way that's easy to integrate with your project.\n\nYou can use `InstrumentsSetupper` as a context manager, like this:\n\n```python\nfrom microbootstrap.instruments_setupper import InstrumentsSetupper\nfrom microbootstrap import InstrumentsSetupperSettings\n\n\nclass YourSettings(InstrumentsSetupperSettings):\n ...\n\n\nwith InstrumentsSetupper(YourSettings()):\n while True:\n print(\"doing something useful\")\n time.sleep(1)\n```\n\nAlternatively, you can use the `setup()` and `teardown()` methods instead of a context manager:\n\n```python\ncurrent_setupper = InstrumentsSetupper(YourSettings())\ncurrent_setupper.setup()\ntry:\n while True:\n print(\"doing something useful\")\n time.sleep(1)\nfinally:\n current_setupper.teardown()\n```\n\nLike bootstrappers, you can reconfigure instruments using the `configure_instrument()` and `configure_instruments()` methods.\n\n## Advanced\n\nIf you miss some instrument, you can add your own.\nEssentially, `Instrument` is just a class with some abstractmethods.\nEvery instrument uses some config, so that's first thing, you have to define.\n\n```python\nfrom microbootstrap.instruments.base import BaseInstrumentConfig\n\n\nclass MyInstrumentConfig(BaseInstrumentConfig):\n your_string_parameter: str\n your_list_parameter: list\n```\n\nNext, you can create an instrument class that inherits from `Instrument` and accepts your configuration as a generic parameter.\n\n```python\nfrom microbootstrap.instruments.base import Instrument\n\n\nclass MyInstrument(Instrument[MyInstrumentConfig]):\n instrument_name: str\n ready_condition: str\n\n def is_ready(self) -> bool:\n pass\n\n def teardown(self) -> None:\n pass\n\n def bootstrap(self) -> None:\n pass\n\n @classmethod\n def get_config_type(cls) -> type[MyInstrumentConfig]:\n return MyInstrumentConfig\n```\n\nNow, you can define the behavior of your instrument.\n\nAttributes:\n\n- `instrument_name` - This will be displayed in your console during bootstrap.\n- `ready_condition` - This will be displayed in your console during bootstrap if the instrument is not ready.\n\nMethods:\n\n- `is_ready` - This defines the readiness of the instrument for bootstrapping, based on its configuration values. This is required.\n- `teardown` - This allows for a graceful shutdown of the instrument during application shutdown. This is not required.\n- `bootstrap` - This is the main logic of the instrument. This is not required.\n\nOnce you have the framework of the instrument, you can adapt it for any existing framework. For instance, let's adapt it for litestar.\n\n```python\nimport litestar\n\nfrom microbootstrap.bootstrappers.litestar import LitestarBootstrapper\n\n@LitestarBootstrapper.use_instrument()\nclass LitestarMyInstrument(MyInstrument):\n def bootstrap_before(self) -> dict[str, typing.Any]:\n pass\n\n def bootstrap_after(self, application: litestar.Litestar) -> dict[str, typing.Any]:\n pass\n```\n\nTo bind the instrument to a bootstrapper, use the `.use_instrument` decorator.\n\nTo add extra parameters to the application, you can use:\n\n- `bootstrap_before` - This adds arguments to the application configuration before creation.\n- `bootstrap_after` - This adds arguments to the application after creation.\n\nAfterwards, you can use your instrument during the bootstrap process.\n\n```python\nimport litestar\n\nfrom microbootstrap.bootstrappers.litestar import LitestarBootstrapper\nfrom microbootstrap import SentryConfig, OpentelemetryConfig\n\nfrom your_app import MyInstrumentConfig\n\n\napplication: litestar.Litestar = (\n LitestarBootstrapper(settings)\n .configure_instrument(\n MyInstrumentConfig(\n your_string_parameter=\"very-nice-parameter\",\n your_list_parameter=[\"very-special-list\"],\n )\n )\n .bootstrap()\n)\n```\n\nAlternatively, you can fill these parameters within your main settings object.\n\n```python\nfrom microbootstrap import LitestarSettings\nfrom microbootstrap.bootstrappers.litestar import LitestarBootstrapper\n\nfrom your_app import MyInstrumentConfig\n\n\nclass YourSettings(LitestarSettings, MyInstrumentConfig):\n your_string_parameter: str = \"very-nice-parameter\"\n your_list_parameter: list = [\"very-special-list\"]\n\nsettings = YourSettings()\n\napplication: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "Package for bootstrapping new micro-services",
"version": "0.8.1",
"project_urls": {
"documentation": "https://pypi.org/project/microbootstrap/",
"homepage": "https://github.com/community-of-python/microbootstrap",
"repository": "https://github.com/community-of-python/microbootstrap"
},
"split_keywords": [
"python",
" microservice",
" bootstrap",
" opentelemetry",
" logging",
" error-tracing",
" litestar",
" fastapi"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "dd3af8ba1d9472253dfdbdca7484de7c482ee70727b5ec87f599186d9f28c569",
"md5": "9ccc74e882102f07e5e6644271e1f0dd",
"sha256": "7b76c325827f7f3c5a186c1822caab39d4f4dfe34c0b99e16c98f23067778615"
},
"downloads": -1,
"filename": "microbootstrap-0.8.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "9ccc74e882102f07e5e6644271e1f0dd",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.9",
"size": 28159,
"upload_time": "2024-10-28T09:13:51",
"upload_time_iso_8601": "2024-10-28T09:13:51.333767Z",
"url": "https://files.pythonhosted.org/packages/dd/3a/f8ba1d9472253dfdbdca7484de7c482ee70727b5ec87f599186d9f28c569/microbootstrap-0.8.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "43248481aeab4e20f901024879e98656f7d23d57c20d7b65567434fdcb4926bf",
"md5": "93a4d09946a03285673c599c0293a60e",
"sha256": "3e5636eb5d04e6f8772311cc9790d26721f7e6d4044eff64e32b52cc32d4af11"
},
"downloads": -1,
"filename": "microbootstrap-0.8.1.tar.gz",
"has_sig": false,
"md5_digest": "93a4d09946a03285673c599c0293a60e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.9",
"size": 24538,
"upload_time": "2024-10-28T09:13:52",
"upload_time_iso_8601": "2024-10-28T09:13:52.941686Z",
"url": "https://files.pythonhosted.org/packages/43/24/8481aeab4e20f901024879e98656f7d23d57c20d7b65567434fdcb4926bf/microbootstrap-0.8.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-28 09:13:52",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "community-of-python",
"github_project": "microbootstrap",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "microbootstrap"
}