microbootstrap 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,561 @@
1
+ Metadata-Version: 2.1
2
+ Name: microbootstrap
3
+ Version: 0.0.1
4
+ Summary: Package for bootstrapping new micro-services
5
+ Keywords: python,microservice,bootstrap,opentelemetry,logging,error-tracing,litestar,fastapi
6
+ Author: community-of-python
7
+ Requires-Python: >=3.9,<4.0
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Operating System :: MacOS
10
+ Classifier: Operating System :: Microsoft
11
+ Classifier: Operating System :: POSIX :: Linux
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.8
20
+ Classifier: Topic :: Software Development :: Build Tools
21
+ Classifier: Typing :: Typed
22
+ Provides-Extra: fastapi
23
+ Provides-Extra: litestar
24
+ Requires-Dist: fastapi (>=0.111.0,<0.112.0) ; extra == "fastapi"
25
+ Requires-Dist: granian[reload] (>=1.4.4,<2.0.0)
26
+ Requires-Dist: litestar (>=2.9.1,<3.0.0) ; extra == "litestar"
27
+ Requires-Dist: opentelemetry-api (>=1.25.0,<2.0.0)
28
+ Requires-Dist: opentelemetry-exporter-otlp (>=1.25.0,<2.0.0)
29
+ Requires-Dist: opentelemetry-exporter-prometheus-remote-write (>=0.46b0,<0.47)
30
+ Requires-Dist: opentelemetry-instrumentation (>=0.46b0,<0.47)
31
+ Requires-Dist: opentelemetry-instrumentation-asgi (>=0.46b0,<0.47)
32
+ Requires-Dist: opentelemetry-instrumentation-fastapi (>=0.46b0,<0.47) ; extra == "fastapi"
33
+ Requires-Dist: opentelemetry-instrumentation-system-metrics (>=0.46b0,<0.47)
34
+ Requires-Dist: opentelemetry-sdk (>=1.25.0,<2.0.0)
35
+ Requires-Dist: prometheus-client (>=0.20.0,<0.21.0) ; extra == "litestar"
36
+ Requires-Dist: prometheus-fastapi-instrumentator (>=6.1.0,<7.0.0) ; extra == "fastapi"
37
+ Requires-Dist: pydantic-settings (>=2.3.4,<3.0.0)
38
+ Requires-Dist: rich (>=13.7.1,<14.0.0)
39
+ Requires-Dist: sentry-sdk (>=2.7.1,<3.0.0)
40
+ Requires-Dist: structlog (>=24.2.0,<25.0.0)
41
+ Requires-Dist: typing-extensions (>=4.12.2,<5.0.0)
42
+ Description-Content-Type: text/markdown
43
+
44
+ <p align="center">
45
+ <img src="./logo.svg" width="350">
46
+ </p>
47
+ <br>
48
+ <p align="center">
49
+ <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>
50
+ </p>
51
+
52
+ # microbootstrap
53
+
54
+ <b>microbootstrap</b> helps you create applications with all necessary instruments already set up.
55
+
56
+ ```python
57
+ # settings.py
58
+ from microbootstrap import LitestarSettings
59
+
60
+
61
+ class YourSettings(LitestarSettings):
62
+ # Your settings stored here
63
+
64
+
65
+ settings = YourSettings()
66
+
67
+
68
+ # application.py
69
+ import litestar
70
+ from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
71
+
72
+ from your_application.settings import settings
73
+
74
+ # Litestar application for use!
75
+ application: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()
76
+ ```
77
+
78
+ With <b>microbootstrap</b>, you get an application with built-in support for:
79
+
80
+ - `sentry`
81
+ - `prometheus`
82
+ - `opentelemetry`
83
+ - `logging`
84
+
85
+ <b>microbootstrap</b> supports only `litestar` framework for now.
86
+
87
+ Interested? Let's jump right into it ⚡
88
+
89
+ ## Installation
90
+
91
+ You can install package with `pip` or `poetry`.
92
+
93
+ poetry:
94
+
95
+ ```bash
96
+ $ poetry add microbootstrap -E litestar
97
+ ```
98
+
99
+ pip:
100
+
101
+ ```bash
102
+ $ poetry add microbootstrap[litestar]
103
+ ```
104
+
105
+ ## Quickstart
106
+
107
+ To manipulate your application, you can use settings object.
108
+
109
+ ```python
110
+ from microbootstrap import LitestarSettings
111
+
112
+
113
+ class YourSettings(LitestarSettings):
114
+ # General settings
115
+ service_debug: bool = False
116
+ service_name: str = "my-awesome-service"
117
+
118
+ # Sentry settings
119
+ sentry_dsn: str = "your-setnry-dsn"
120
+
121
+ # Prometheus settings
122
+ prometheus_metrics_path: str "/my-path"
123
+
124
+ # Opentelemetry settings
125
+ opentelemetry_container_name: str = "your-container"
126
+ opentelemetry_endpoint: str = "/opentelemetry-endpoint"
127
+
128
+
129
+
130
+ settings = YourSettings()
131
+ ```
132
+
133
+ Then, use the `Bootstrapper` object to create an application based on your settings.
134
+
135
+ ```python
136
+ import litestar
137
+ from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
138
+
139
+ application: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()
140
+ ```
141
+
142
+ This way, you'll have an application with all the essential instruments already set up for you.
143
+
144
+ ## Settings
145
+
146
+ The settings object is at the heart of microbootstrap.
147
+
148
+ All framework-related settings inherit from the `BaseBootstrapSettings` object. `BaseBootstrapSettings` defines parameters for the service and different instruments.
149
+
150
+ However, the number of parameters is <b>not limited</b> to those defined in `BaseBootstrapSettings`. You can add as many as you want.
151
+
152
+ These parameters can be pulled from your environment. By default, no prefix is added to these parameters.
153
+
154
+ Example:
155
+
156
+ ```python
157
+ class YourSettings(BaseBootstrapSettings):
158
+ service_debug: bool = True
159
+ service_name: str = "micro-service"
160
+
161
+ your_awesome_parameter: str = "really awesome"
162
+
163
+ ... # Other settings here
164
+ ```
165
+
166
+ To pull `your_awesome_parameter` from the environment, set the environment variable with the name `YOUR_AWESOME_PARAMETER`.
167
+
168
+ If you want to use a prefix when pulling parameters, set the `ENVIRONMENT_PREFIX` environment variable beforehand.
169
+
170
+ Example:
171
+
172
+ ```bash
173
+ $ export ENVIRONMENT_PREFIX=YOUR_PREFIX_
174
+ ```
175
+
176
+ Then the settings object will try to pull the variable with the name `YOUR_PREFIX_YOUR_AWESOME_PARAMETER`.
177
+
178
+ ## Service settings
179
+
180
+ Every settings object for every framework contains service parameters that can be used by different instruments.
181
+
182
+ You can set them manually, or set the appropriate environment variables and let <b>microbootstrap</b> pull them automatically.
183
+
184
+ ```python
185
+ from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
186
+
187
+
188
+ class ServiceSettings(BaseBootstrapSettings):
189
+ service_debug: bool = True
190
+ service_environment: str | None = None
191
+ service_name: str = "micro-service"
192
+ service_description: str = "Micro service description"
193
+ service_version: str = "1.0.0"
194
+
195
+ ... # Other settings here
196
+
197
+ ```
198
+
199
+ ## Instruments
200
+
201
+ Currently, these instruments are already supported for bootstrapping:
202
+
203
+ - `sentry`
204
+ - `prometheus`
205
+ - `opentelemetry`
206
+ - `logging`
207
+
208
+ Let's make it clear, what it takes to bootstrap them.
209
+
210
+ ### Sentry
211
+
212
+ To bootstrap Sentry, you need to provide at least the `sentry_dsn`.
213
+ You can also provide other parameters through the settings object.
214
+
215
+ ```python
216
+ from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
217
+
218
+
219
+ class YourSettings(BaseBootstrapSettings):
220
+ service_environment: str | None = None
221
+
222
+ sentry_dsn: str | None = None
223
+ sentry_traces_sample_rate: float | None = None
224
+ sentry_sample_rate: float = pydantic.Field(default=1.0, le=1.0, ge=0.0)
225
+ sentry_max_breadcrumbs: int = 15
226
+ sentry_attach_stacktrace: bool = True
227
+ sentry_integrations: list[Integration] = []
228
+ sentry_additional_params: dict[str, typing.Any] = {}
229
+
230
+ ... # Other settings here
231
+ ```
232
+
233
+ All these settings are then passed to [sentry-sdk](https://pypi.org/project/sentry-sdk/) package, completing your Sentry integration.
234
+
235
+ ### Prometheus
236
+
237
+ To bootstrap Prometheus, you need to provide at least the `prometheus_metrics_path`.
238
+ You can also provide other parameters through the settings object.
239
+
240
+ ```python
241
+ from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
242
+
243
+
244
+ class YourSettings(BaseBootstrapSettings):
245
+ service_name: str
246
+
247
+ prometheus_metrics_path: str = "/metrics"
248
+ prometheus_additional_params: dict[str, typing.Any] = {}
249
+
250
+ ... # Other settings here
251
+ ```
252
+
253
+ These settings will be passed to [prometheus-client](https://pypi.org/project/prometheus-client/).
254
+ Still underlying top-level Prometheus library can change from framework to framework, but overall, you'll get a metrics handler at the provided path.
255
+
256
+ By default, metrics are available at the `/metrics` path.
257
+
258
+ ### Opentelemetry
259
+
260
+ Opentelemetry requires a lot of parameters to be bootstrapped:
261
+
262
+ - `service_name`
263
+ - `service_version`
264
+ - `opentelemetry_endpoint`
265
+ - `opentelemetry_namespace`
266
+ - `opentelemetry_container_name`.
267
+
268
+ But you can also provide some more if you need.
269
+
270
+ ```python
271
+ from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
272
+ from microbootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrumentor
273
+
274
+
275
+ class YourSettings(BaseBootstrapSettings):
276
+ service_name: str
277
+ service_version: str
278
+
279
+ opentelemetry_container_name: str | None = None
280
+ opentelemetry_endpoint: str | None = None
281
+ opentelemetry_namespace: str | None = None
282
+ opentelemetry_insecure: bool = True
283
+ opentelemetry_insrtumentors: list[OpenTelemetryInstrumentor] = []
284
+ opentelemetry_exclude_urls: list[str] = []
285
+
286
+ ... # Other settings here
287
+ ```
288
+
289
+ All these settings are then passed to [opentelemetry](https://opentelemetry.io/), completing your Opentelemetry integration.
290
+
291
+ ## Logging
292
+
293
+ <b>microbootstrap</b> provides in-memory json logging using [structlog](https://pypi.org/project/structlog/).
294
+ To learn more about in-memory logging, check out [MemoryHandler](https://docs.python.org/3/library/logging.handlers.html#memoryhandler)
295
+
296
+ To use this feature, your application has to be in non-debug mode, i.e. `service_debug` has to be `False`
297
+
298
+ ```python
299
+ import logging
300
+
301
+ from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
302
+
303
+
304
+ class YourSettings(BaseBootstrapSettings):
305
+ service_debug: bool = True
306
+
307
+ logging_log_level: int = logging.INFO
308
+ logging_flush_level: int = logging.ERROR
309
+ logging_buffer_capacity: int = 10
310
+ logging_unset_handlers: list[str] = ["uvicorn", "uvicorn.access"]
311
+ logging_extra_processors: list[typing.Any] = []
312
+ logging_exclude_endpoints: list[str] = []
313
+ ```
314
+
315
+ Parameters description:
316
+
317
+ - `logging_log_level` - default log level.
318
+ - `logging_flush_level` - all messages will be flushed from buffer, when log with this level appears.
319
+ - `logging_buffer_capacity` - how much messages your buffer will store, until flushed.
320
+ - `logging_unset_handlers` - unset logger handlers.
321
+ - `logging_extra_processors` - set additional structlog processors if you have some.
322
+ - `logging_exclude_endpoints` - remove logging on certain endpoints.
323
+
324
+ ## Configuration
325
+
326
+ Despite settings being pretty convenient mechanism, it's not always possible to store everything in settings.
327
+
328
+ Sometimes one needs to configure some instrument on the spot, here, how it's being done.
329
+
330
+ ### Instruments configuration
331
+
332
+ To configure instruemt manually, you have to import one of available configs from <b>microbootstrap</b>:
333
+
334
+ - `SentryConfig`
335
+ - `OpentelemetryConfig`
336
+ - `PrometheusConfig`
337
+ - `LoggingConfig`
338
+
339
+ And pass them into `.configure_instrument` or `.configure_instruments` bootstrapper method.
340
+
341
+ ```python
342
+ import litestar
343
+
344
+ from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
345
+ from microbootstrap import SentryConfig, OpentelemetryConfig
346
+
347
+
348
+ application: litestar.Litestar = (
349
+ LitestarBootstrapper(settings)
350
+ .configure_instrument(SentryConfig(sentry_dsn="https://new-dsn"))
351
+ .configure_instrument(OpentelemetryConfig(sentry_dsn="/new-endpoint"))
352
+ .bootstrap()
353
+ )
354
+ ```
355
+
356
+ Or
357
+
358
+ ```python
359
+ import litestar
360
+
361
+ from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
362
+ from microbootstrap import SentryConfig, OpentelemetryConfig
363
+
364
+
365
+ application: litestar.Litestar = (
366
+ LitestarBootstrapper(settings)
367
+ .configure_instruments(
368
+ SentryConfig(sentry_dsn="https://examplePublicKey@o0.ingest.sentry.io/0"),
369
+ OpentelemetryConfig(opentelemetry_endpoint="/new-endpoint")
370
+ )
371
+ .bootstrap()
372
+ )
373
+ ```
374
+
375
+ ### Application configuration
376
+
377
+ Application can be configured similarly
378
+
379
+ ```python
380
+ import litestar
381
+ from litestar.config.app import AppConfig
382
+
383
+ from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
384
+ from microbootstrap import SentryConfig, OpentelemetryConfig
385
+
386
+
387
+ @litestar.get("/my-handler")
388
+ async def my_handler() -> str:
389
+ return "Ok"
390
+
391
+ application: litestar.Litestar = (
392
+ LitestarBootstrapper(settings)
393
+ .configur_application(AppConfig(route_handlers=[my_handler]))
394
+ .bootstrap()
395
+ )
396
+ ```
397
+
398
+ > ### Important
399
+ >
400
+ > When configuring parameters with simple data types such as: `str`, `int`, `float`, e.t.c.
401
+ > Those variables are rewriting previous values.
402
+ >
403
+ > Example
404
+ >
405
+ > ```python
406
+ > from microbootstrap import LitestarSettings, SentryConfig
407
+ >
408
+ >
409
+ > class YourSettings(LitestarSettings):
410
+ > sentry_dsn: str = "https://my-sentry-dsn"
411
+ >
412
+ >
413
+ > application: litestar.Litestar = (
414
+ > LitestarBootstrapper(YourSettings())
415
+ > .configure_instrument(
416
+ > SentryConfig(sentry_dsn="https://my-new-configured-sentry-dsn")
417
+ > )
418
+ > .bootstrap()
419
+ > )
420
+ > ```
421
+ >
422
+ > In this example application will be bootstrapped with new `https://my-new-configured-sentry-dsn` sentry dsn
423
+ > instead of old one.
424
+ >
425
+ > But if you configure parameters with complex data types such as: `list`, `tuple`, `dict` or `set`.
426
+ > They are being expanded or merged into each other.
427
+ >
428
+ > Example
429
+ >
430
+ > ```python
431
+ > from microbootstrap import LitestarSettings, PrometheusConfig
432
+ >
433
+ >
434
+ > class YourSettings(LitestarSettings):
435
+ > prometheus_additional_params: dict[str, Any] = {"first_value": 1}
436
+ >
437
+ >
438
+ > application: litestar.Litestar = (
439
+ > LitestarBootstrapper(YourSettings())
440
+ > .configure_instrument(
441
+ > PrometheusConfig(prometheus_additional_params={"second_value": 2})
442
+ > )
443
+ > .bootstrap()
444
+ > )
445
+ > ```
446
+ >
447
+ > In this case prometheus will receive `{"first_value: 1", "second_value": 2}` inside `prometheus_additional_params`
448
+ > This is also true for `list`, `tuple` and `set`s
449
+
450
+ ## Advanced
451
+
452
+ If you miss some instrument, you can add your own.
453
+ Essentialy, `Instrument` is just a class with some abstractmethods.
454
+ Every instrument uses some config, so that's first thing, you have to define.
455
+
456
+ ```python
457
+ from microbootstrap.instruments.base import BaseInstrumentConfig
458
+
459
+
460
+ class MyInstrumentConfig(BaseInstrumentConfig):
461
+ your_string_parameter: str
462
+ your_list_parameter: list
463
+ ```
464
+
465
+ After that, you can create an instrument class, that is inheriting from `Instrument` and accepts your config as generic parameter
466
+
467
+ ```python
468
+ from microbootstrap.instruments.base import Instrument
469
+
470
+
471
+ class MyInstrument(Instrument[MyInstrumentConfig]):
472
+ def write_status(self, console_writer: ConsoleWriter) -> None:
473
+ pass
474
+
475
+ def is_ready(self) -> bool:
476
+ pass
477
+
478
+ def teardown(self) -> None:
479
+ pass
480
+
481
+ def bootstrap(self) -> None:
482
+ pass
483
+
484
+ @classmethod
485
+ def get_config_type(cls) -> type[MyInstrumentConfig]:
486
+ return MyInstrumentConfig
487
+ ```
488
+
489
+ And now you can define behaviour of your instrument
490
+
491
+ - `write_status` - writes status to console, indicating, is instrument bootstrapped.
492
+ - `is_ready` - defines ready for bootstrapping state of instrument, based on it's config values.
493
+ - `teardown` - graceful shutdown for instrument during application shutdown.
494
+ - `bootstrap` - main instrument's logic.
495
+
496
+ When you have a carcass of instrument, you can adapt it for every framework existing.
497
+ Let's adapt it for litestar for example
498
+
499
+ ```python
500
+ import litestar
501
+
502
+ from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
503
+
504
+ @LitestarBootstrapper.use_instrument()
505
+ class LitestarMyInstrument(MyInstrument):
506
+ def bootstrap_before(self) -> dict[str, typing.Any]:
507
+ pass
508
+
509
+ def bootstrap_after(self, application: litestar.Litestar) -> dict[str, typing.Any]:
510
+ pass
511
+
512
+ ```
513
+
514
+ To bind instrument to a bootstrapper, you have to use `.use_instrument` decorator.
515
+
516
+ To add some extra parameters to application you can use:
517
+
518
+ - `bootstrap_before` - add some arguments to application config before creation
519
+ - `bootstrap_after` - add some arguments to application after creation
520
+
521
+ After that you can use your instrument during bootstrap process
522
+
523
+ ```python
524
+ import litestar
525
+
526
+ from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
527
+ from microbootstrap import SentryConfig, OpentelemetryConfig
528
+
529
+ from your_app import MyInstrumentConfig
530
+
531
+
532
+ application: litestar.Litestar = (
533
+ LitestarBootstrapper(settings)
534
+ .configure_instrument(
535
+ MyInstrumentConfig(
536
+ your_string_parameter="very-nice-parameter",
537
+ your_list_parameter=["very-special-list"],
538
+ )
539
+ )
540
+ .bootstrap()
541
+ )
542
+ ```
543
+
544
+ or you can fill those parameters inside your main settings object
545
+
546
+ ```python
547
+ from microbootstrap import LitestarSettings
548
+ from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
549
+
550
+ from your_app import MyInstrumentConfig
551
+
552
+
553
+ class YourSettings(LitestarSettings, MyInstrumentConfig):
554
+ your_string_parameter: str = "very-nice-parameter"
555
+ your_list_parameter: list = ["very-special-list"]
556
+
557
+ settings = YourSettings()
558
+
559
+ application: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()
560
+ ```
561
+