microbootstrap 0.2.3__tar.gz → 0.3.0__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.
Files changed (30) hide show
  1. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/PKG-INFO +85 -32
  2. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/README.md +83 -31
  3. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/__init__.py +5 -3
  4. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/bootstrappers/base.py +16 -13
  5. microbootstrap-0.3.0/microbootstrap/bootstrappers/fastapi.py +115 -0
  6. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/bootstrappers/litestar.py +18 -22
  7. microbootstrap-0.3.0/microbootstrap/config/fastapi.py +66 -0
  8. microbootstrap-0.3.0/microbootstrap/config/litestar.py +14 -0
  9. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/granian_server.py +3 -3
  10. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/instrument_box.py +8 -7
  11. microbootstrap-0.3.0/microbootstrap/instruments/prometheus_instrument.py +40 -0
  12. microbootstrap-0.3.0/microbootstrap/py.typed +0 -0
  13. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/settings.py +32 -10
  14. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/pyproject.toml +4 -2
  15. microbootstrap-0.2.3/microbootstrap/instruments/prometheus_instrument.py +0 -28
  16. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/bootstrappers/__init__.py +0 -0
  17. {microbootstrap-0.2.3/microbootstrap/instruments → microbootstrap-0.3.0/microbootstrap/config}/__init__.py +0 -0
  18. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/console_writer.py +0 -0
  19. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/exceptions.py +0 -0
  20. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/helpers.py +0 -0
  21. {microbootstrap-0.2.3/microbootstrap/middlewares → microbootstrap-0.3.0/microbootstrap/instruments}/__init__.py +0 -0
  22. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/base.py +0 -0
  23. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/cors_instrument.py +0 -0
  24. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/logging_instrument.py +0 -0
  25. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/opentelemetry_instrument.py +0 -0
  26. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/sentry_instrument.py +0 -0
  27. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/swagger_instrument.py +0 -0
  28. /microbootstrap-0.2.3/microbootstrap/py.typed → /microbootstrap-0.3.0/microbootstrap/middlewares/__init__.py +0 -0
  29. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/middlewares/fastapi.py +0 -0
  30. {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/middlewares/litestar.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: microbootstrap
3
- Version: 0.2.3
3
+ Version: 0.3.0
4
4
  Summary: Package for bootstrapping new micro-services
5
5
  Keywords: python,microservice,bootstrap,opentelemetry,logging,error-tracing,litestar,fastapi
6
6
  Author: community-of-python
@@ -22,6 +22,7 @@ Provides-Extra: fastapi
22
22
  Provides-Extra: litestar
23
23
  Requires-Dist: eval-type-backport (>=0.2.0,<0.3.0)
24
24
  Requires-Dist: fastapi (>=0.111.0,<0.112.0) ; extra == "fastapi"
25
+ Requires-Dist: fastapi-offline-docs (>=1.0.1,<2.0.0) ; extra == "fastapi"
25
26
  Requires-Dist: granian[reload] (>=1.4.4,<2.0.0)
26
27
  Requires-Dist: litestar (>=2.9.1,<3.0.0) ; extra == "litestar"
27
28
  Requires-Dist: litestar-offline-docs (>=1.0.1,<2.0.0) ; extra == "litestar"
@@ -80,7 +81,6 @@ from your_application.settings import settings
80
81
  application: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()
81
82
  ```
82
83
 
83
- Currently, only `litestar` is supported.
84
84
  With <b>microbootstrap</b>, you receive an application with lightweight built-in support for:
85
85
 
86
86
  - `sentry`
@@ -90,6 +90,11 @@ With <b>microbootstrap</b>, you receive an application with lightweight built-in
90
90
  - `cors`
91
91
  - `swagger` - with additional offline version support
92
92
 
93
+ Those instruments can be bootstrapped for:
94
+
95
+ - `fastapi`
96
+ - `litestar`
97
+
93
98
  Interested? Let's dive right in ⚡
94
99
 
95
100
  ## Table of Contents
@@ -112,18 +117,22 @@ Interested? Let's dive right in ⚡
112
117
 
113
118
  ## Installation
114
119
 
115
- You can install the package using either `pip` or `poetry`.
120
+ You can install the package using either `pip` or `poetry`.
121
+ Also, you can specify extras during installation for concrete framework:
122
+
123
+ - `fastapi`
124
+ - `litestar`
116
125
 
117
126
  For poetry:
118
127
 
119
128
  ```bash
120
- $ poetry add microbootstrap -E litestar
129
+ $ poetry add microbootstrap -E fastapi
121
130
  ```
122
131
 
123
132
  For pip:
124
133
 
125
134
  ```bash
126
- $ pip install microbootstrap[litestar]
135
+ $ pip install microbootstrap[fastapi]
127
136
  ```
128
137
 
129
138
  ## Quickstart
@@ -169,16 +178,16 @@ This approach will provide you with an application that has all the essential in
169
178
 
170
179
  The settings object is the core of microbootstrap.
171
180
 
172
- All framework-related settings inherit from the `BaseBootstrapSettings` object. `BaseBootstrapSettings` defines parameters for the service and various instruments.
181
+ All framework-related settings inherit from the `BaseServiceSettings` object. `BaseServiceSettings` defines parameters for the service and various instruments.
173
182
 
174
- However, the number of parameters is <b>not confined</b> to those defined in `BaseBootstrapSettings`. You can add as many as you need.
183
+ However, the number of parameters is <b>not confined</b> to those defined in `BaseServiceSettings`. You can add as many as you need.
175
184
 
176
185
  These parameters can be sourced from your environment. By default, no prefix is added to these parameters.
177
186
 
178
187
  Example:
179
188
 
180
189
  ```python
181
- class YourSettings(BaseBootstrapSettings):
190
+ class YourSettings(BaseServiceSettings):
182
191
  service_debug: bool = True
183
192
  service_name: str = "micro-service"
184
193
 
@@ -206,10 +215,10 @@ Each settings object for every framework includes service parameters that can be
206
215
  You can configure them manually, or set the corresponding environment variables and let <b>microbootstrap</b> to source them automatically.
207
216
 
208
217
  ```python
209
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
218
+ from microbootstrap.settings import BaseServiceSettings
210
219
 
211
220
 
212
- class ServiceSettings(BaseBootstrapSettings):
221
+ class ServiceSettings(BaseServiceSettings):
213
222
  service_debug: bool = True
214
223
  service_environment: str | None = None
215
224
  service_name: str = "micro-service"
@@ -239,10 +248,10 @@ To bootstrap Sentry, you must provide at least the `sentry_dsn`.
239
248
  Additional parameters can also be supplied through the settings object.
240
249
 
241
250
  ```python
242
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
251
+ from microbootstrap.settings import BaseServiceSettings
243
252
 
244
253
 
245
- class YourSettings(BaseBootstrapSettings):
254
+ class YourSettings(BaseServiceSettings):
246
255
  service_environment: str | None = None
247
256
 
248
257
  sentry_dsn: str | None = None
@@ -260,14 +269,46 @@ These settings are subsequently passed to the [sentry-sdk](https://pypi.org/proj
260
269
 
261
270
  ### Prometheus
262
271
 
263
- To bootstrap Prometheus, you must provide at least the `prometheus_metrics_path`.
264
- Additional parameters can also be supplied through the settings object.
272
+ Prometheus is not an easy case, because two underlying libraries for `fastapi` and `litestar` are so different, that could not be cast to a single interface. For that reason prometheus settings for `fastapi` and `litestar` are a little bit different
273
+
274
+ #### Fastapi
275
+
276
+ To bootstrap prometheus you have to provide `prometheus_metrics_path`
277
+
278
+ ```python
279
+ from microbootstrap.settings import FastApiSettings
280
+
281
+
282
+ class YourFastApiSettings(FastApiSettings):
283
+ service_name: str
284
+
285
+ prometheus_metrics_path: str = "/metrics"
286
+ prometheus_instrumentator_params: dict[str, typing.Any] = {}
287
+ prometheus_instrument_params: dict[str, typing.Any] = {}
288
+ prometheus_expose_params: dict[str, typing.Any] = {}
289
+
290
+ ... # Other settings here
291
+ ```
292
+
293
+ Parameters description:
294
+
295
+ - `service_name` - will be attached to metric's names, but has to be named in [snake_case](https://en.wikipedia.org/wiki/Snake_case).
296
+ - `prometheus_metrics_path` - path to metrics handler.
297
+ - `prometheus_instrumentator_params` - will be passed to `Instrumentor` during initialization.
298
+ - `prometheus_instrument_params` - will be passed to `Instrumentor.instrument(...)`.
299
+ - `prometheus_expose_params` - will be passed to `Instrumentor.expose(...)`.
300
+
301
+ FastApi prometheus bootstrapper uses [prometheus-fastapi-instrumentator](https://github.com/trallnag/prometheus-fastapi-instrumentator) that's why there are three different dict for parameters.
302
+
303
+ #### Fastapi
304
+
305
+ To bootstrap prometheus you have to provide `prometheus_metrics_path`
265
306
 
266
307
  ```python
267
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
308
+ from microbootstrap.settings import LitestarSettings
268
309
 
269
310
 
270
- class YourSettings(BaseBootstrapSettings):
311
+ class YourFastApiSettings(LitestarSettings):
271
312
  service_name: str
272
313
 
273
314
  prometheus_metrics_path: str = "/metrics"
@@ -276,10 +317,11 @@ class YourSettings(BaseBootstrapSettings):
276
317
  ... # Other settings here
277
318
  ```
278
319
 
279
- These settings are subsequently passed to the [prometheus-client](https://pypi.org/project/prometheus-client/) package.
280
- The underlying top-level Prometheus library may vary from framework to framework, but in general, a metrics handler will be available at the provided path.
320
+ Parameters description:
281
321
 
282
- By default, metrics are accessible at the `/metrics` path.
322
+ - `service_name` - will be attached to metric's names, there are no name restrictions.
323
+ - `prometheus_metrics_path` - path to metrics handler.
324
+ - `prometheus_additional_params` - will be passed to `litestar.contrib.prometheus.PrometheusConfig`.
283
325
 
284
326
  ### Opentelemetry
285
327
 
@@ -289,16 +331,16 @@ To bootstrap Opentelemetry, you must provide several parameters:
289
331
  - `service_version`
290
332
  - `opentelemetry_endpoint`
291
333
  - `opentelemetry_namespace`
292
- - `opentelemetry_container_name`.
334
+ - `opentelemetry_container_name`
293
335
 
294
336
  However, additional parameters can also be supplied if needed.
295
337
 
296
338
  ```python
297
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
339
+ from microbootstrap.settings import BaseServiceSettings
298
340
  from microbootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrumentor
299
341
 
300
342
 
301
- class YourSettings(BaseBootstrapSettings):
343
+ class YourSettings(BaseServiceSettings):
302
344
  service_name: str
303
345
  service_version: str
304
346
 
@@ -306,12 +348,23 @@ class YourSettings(BaseBootstrapSettings):
306
348
  opentelemetry_endpoint: str | None = None
307
349
  opentelemetry_namespace: str | None = None
308
350
  opentelemetry_insecure: bool = True
309
- opentelemetry_insrtumentors: list[OpenTelemetryInstrumentor] = []
351
+ opentelemetry_instrumentors: list[OpenTelemetryInstrumentor] = []
310
352
  opentelemetry_exclude_urls: list[str] = []
311
353
 
312
354
  ... # Other settings here
313
355
  ```
314
356
 
357
+ Parameters description:
358
+
359
+ - `service_name` - will be passed to the `Resource`.
360
+ - `service_version` - will be passed to the `Resource`.
361
+ - `opentelemetry_endpoint` - will be passed to `OTLPSpanExporter` as endpoint.
362
+ - `opentelemetry_namespace` - will be passed to the `Resource`.
363
+ - `opentelemetry_insecure` - is opentelemetry connection secure.
364
+ - `opentelemetry_container_name` - will be passed to the `Resource`.
365
+ - `opentelemetry_instrumentors` - a list of extra instrumentors.
366
+ - `opentelemetry_exclude_urls` - list of ignored urls.
367
+
315
368
  These settings are subsequently passed to [opentelemetry](https://opentelemetry.io/), finalizing your Opentelemetry integration.
316
369
 
317
370
  ### Logging
@@ -324,10 +377,10 @@ To utilize this feature, your application must be in non-debug mode, meaning `se
324
377
  ```python
325
378
  import logging
326
379
 
327
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
380
+ from microbootstrap.settings import BaseServiceSettings
328
381
 
329
382
 
330
- class YourSettings(BaseBootstrapSettings):
383
+ class YourSettings(BaseServiceSettings):
331
384
  service_debug: bool = False
332
385
 
333
386
  logging_log_level: int = logging.INFO
@@ -338,7 +391,7 @@ class YourSettings(BaseBootstrapSettings):
338
391
  logging_exclude_endpoints: list[str] = []
339
392
  ```
340
393
 
341
- Parameter descriptions:
394
+ Parameters description:
342
395
 
343
396
  - `logging_log_level` - The default log level.
344
397
  - `logging_flush_level` - All messages will be flushed from the buffer when a log with this level appears.
@@ -350,10 +403,10 @@ Parameter descriptions:
350
403
  ### CORS
351
404
 
352
405
  ```python
353
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
406
+ from microbootstrap.settings import BaseServiceSettings
354
407
 
355
408
 
356
- class YourSettings(BaseBootstrapSettings):
409
+ class YourSettings(BaseServiceSettings):
357
410
  cors_allowed_origins: list[str] = pydantic.Field(default_factory=list)
358
411
  cors_allowed_methods: list[str] = pydantic.Field(default_factory=list)
359
412
  cors_allowed_headers: list[str] = pydantic.Field(default_factory=list)
@@ -376,10 +429,10 @@ Parameter descriptions:
376
429
  ### Swagger
377
430
 
378
431
  ```python
379
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
432
+ from microbootstrap.settings import BaseServiceSettings
380
433
 
381
434
 
382
- class YourSettings(BaseBootstrapSettings):
435
+ class YourSettings(BaseServiceSettings):
383
436
  service_name: str = "micro-service"
384
437
  service_description: str = "Micro service description"
385
438
  service_version: str = "1.0.0"
@@ -459,8 +512,8 @@ The application can be configured in a similar manner:
459
512
 
460
513
  ```python
461
514
  import litestar
462
- from litestar.config.app import AppConfig
463
515
 
516
+ from microbootstrap.config.litestar import LitestarConfig
464
517
  from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
465
518
  from microbootstrap import SentryConfig, OpentelemetryConfig
466
519
 
@@ -471,7 +524,7 @@ async def my_handler() -> str:
471
524
 
472
525
  application: litestar.Litestar = (
473
526
  LitestarBootstrapper(settings)
474
- .configure_application(AppConfig(route_handlers=[my_handler]))
527
+ .configure_application(LitestarConfig(route_handlers=[my_handler]))
475
528
  .bootstrap()
476
529
  )
477
530
  ```
@@ -33,7 +33,6 @@ from your_application.settings import settings
33
33
  application: litestar.Litestar = LitestarBootstrapper(settings).bootstrap()
34
34
  ```
35
35
 
36
- Currently, only `litestar` is supported.
37
36
  With <b>microbootstrap</b>, you receive an application with lightweight built-in support for:
38
37
 
39
38
  - `sentry`
@@ -43,6 +42,11 @@ With <b>microbootstrap</b>, you receive an application with lightweight built-in
43
42
  - `cors`
44
43
  - `swagger` - with additional offline version support
45
44
 
45
+ Those instruments can be bootstrapped for:
46
+
47
+ - `fastapi`
48
+ - `litestar`
49
+
46
50
  Interested? Let's dive right in ⚡
47
51
 
48
52
  ## Table of Contents
@@ -65,18 +69,22 @@ Interested? Let's dive right in ⚡
65
69
 
66
70
  ## Installation
67
71
 
68
- You can install the package using either `pip` or `poetry`.
72
+ You can install the package using either `pip` or `poetry`.
73
+ Also, you can specify extras during installation for concrete framework:
74
+
75
+ - `fastapi`
76
+ - `litestar`
69
77
 
70
78
  For poetry:
71
79
 
72
80
  ```bash
73
- $ poetry add microbootstrap -E litestar
81
+ $ poetry add microbootstrap -E fastapi
74
82
  ```
75
83
 
76
84
  For pip:
77
85
 
78
86
  ```bash
79
- $ pip install microbootstrap[litestar]
87
+ $ pip install microbootstrap[fastapi]
80
88
  ```
81
89
 
82
90
  ## Quickstart
@@ -122,16 +130,16 @@ This approach will provide you with an application that has all the essential in
122
130
 
123
131
  The settings object is the core of microbootstrap.
124
132
 
125
- All framework-related settings inherit from the `BaseBootstrapSettings` object. `BaseBootstrapSettings` defines parameters for the service and various instruments.
133
+ All framework-related settings inherit from the `BaseServiceSettings` object. `BaseServiceSettings` defines parameters for the service and various instruments.
126
134
 
127
- However, the number of parameters is <b>not confined</b> to those defined in `BaseBootstrapSettings`. You can add as many as you need.
135
+ However, the number of parameters is <b>not confined</b> to those defined in `BaseServiceSettings`. You can add as many as you need.
128
136
 
129
137
  These parameters can be sourced from your environment. By default, no prefix is added to these parameters.
130
138
 
131
139
  Example:
132
140
 
133
141
  ```python
134
- class YourSettings(BaseBootstrapSettings):
142
+ class YourSettings(BaseServiceSettings):
135
143
  service_debug: bool = True
136
144
  service_name: str = "micro-service"
137
145
 
@@ -159,10 +167,10 @@ Each settings object for every framework includes service parameters that can be
159
167
  You can configure them manually, or set the corresponding environment variables and let <b>microbootstrap</b> to source them automatically.
160
168
 
161
169
  ```python
162
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
170
+ from microbootstrap.settings import BaseServiceSettings
163
171
 
164
172
 
165
- class ServiceSettings(BaseBootstrapSettings):
173
+ class ServiceSettings(BaseServiceSettings):
166
174
  service_debug: bool = True
167
175
  service_environment: str | None = None
168
176
  service_name: str = "micro-service"
@@ -192,10 +200,10 @@ To bootstrap Sentry, you must provide at least the `sentry_dsn`.
192
200
  Additional parameters can also be supplied through the settings object.
193
201
 
194
202
  ```python
195
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
203
+ from microbootstrap.settings import BaseServiceSettings
196
204
 
197
205
 
198
- class YourSettings(BaseBootstrapSettings):
206
+ class YourSettings(BaseServiceSettings):
199
207
  service_environment: str | None = None
200
208
 
201
209
  sentry_dsn: str | None = None
@@ -213,14 +221,46 @@ These settings are subsequently passed to the [sentry-sdk](https://pypi.org/proj
213
221
 
214
222
  ### Prometheus
215
223
 
216
- To bootstrap Prometheus, you must provide at least the `prometheus_metrics_path`.
217
- Additional parameters can also be supplied through the settings object.
224
+ Prometheus is not an easy case, because two underlying libraries for `fastapi` and `litestar` are so different, that could not be cast to a single interface. For that reason prometheus settings for `fastapi` and `litestar` are a little bit different
225
+
226
+ #### Fastapi
227
+
228
+ To bootstrap prometheus you have to provide `prometheus_metrics_path`
229
+
230
+ ```python
231
+ from microbootstrap.settings import FastApiSettings
232
+
233
+
234
+ class YourFastApiSettings(FastApiSettings):
235
+ service_name: str
236
+
237
+ prometheus_metrics_path: str = "/metrics"
238
+ prometheus_instrumentator_params: dict[str, typing.Any] = {}
239
+ prometheus_instrument_params: dict[str, typing.Any] = {}
240
+ prometheus_expose_params: dict[str, typing.Any] = {}
241
+
242
+ ... # Other settings here
243
+ ```
244
+
245
+ Parameters description:
246
+
247
+ - `service_name` - will be attached to metric's names, but has to be named in [snake_case](https://en.wikipedia.org/wiki/Snake_case).
248
+ - `prometheus_metrics_path` - path to metrics handler.
249
+ - `prometheus_instrumentator_params` - will be passed to `Instrumentor` during initialization.
250
+ - `prometheus_instrument_params` - will be passed to `Instrumentor.instrument(...)`.
251
+ - `prometheus_expose_params` - will be passed to `Instrumentor.expose(...)`.
252
+
253
+ FastApi prometheus bootstrapper uses [prometheus-fastapi-instrumentator](https://github.com/trallnag/prometheus-fastapi-instrumentator) that's why there are three different dict for parameters.
254
+
255
+ #### Fastapi
256
+
257
+ To bootstrap prometheus you have to provide `prometheus_metrics_path`
218
258
 
219
259
  ```python
220
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
260
+ from microbootstrap.settings import LitestarSettings
221
261
 
222
262
 
223
- class YourSettings(BaseBootstrapSettings):
263
+ class YourFastApiSettings(LitestarSettings):
224
264
  service_name: str
225
265
 
226
266
  prometheus_metrics_path: str = "/metrics"
@@ -229,10 +269,11 @@ class YourSettings(BaseBootstrapSettings):
229
269
  ... # Other settings here
230
270
  ```
231
271
 
232
- These settings are subsequently passed to the [prometheus-client](https://pypi.org/project/prometheus-client/) package.
233
- The underlying top-level Prometheus library may vary from framework to framework, but in general, a metrics handler will be available at the provided path.
272
+ Parameters description:
234
273
 
235
- By default, metrics are accessible at the `/metrics` path.
274
+ - `service_name` - will be attached to metric's names, there are no name restrictions.
275
+ - `prometheus_metrics_path` - path to metrics handler.
276
+ - `prometheus_additional_params` - will be passed to `litestar.contrib.prometheus.PrometheusConfig`.
236
277
 
237
278
  ### Opentelemetry
238
279
 
@@ -242,16 +283,16 @@ To bootstrap Opentelemetry, you must provide several parameters:
242
283
  - `service_version`
243
284
  - `opentelemetry_endpoint`
244
285
  - `opentelemetry_namespace`
245
- - `opentelemetry_container_name`.
286
+ - `opentelemetry_container_name`
246
287
 
247
288
  However, additional parameters can also be supplied if needed.
248
289
 
249
290
  ```python
250
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
291
+ from microbootstrap.settings import BaseServiceSettings
251
292
  from microbootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrumentor
252
293
 
253
294
 
254
- class YourSettings(BaseBootstrapSettings):
295
+ class YourSettings(BaseServiceSettings):
255
296
  service_name: str
256
297
  service_version: str
257
298
 
@@ -259,12 +300,23 @@ class YourSettings(BaseBootstrapSettings):
259
300
  opentelemetry_endpoint: str | None = None
260
301
  opentelemetry_namespace: str | None = None
261
302
  opentelemetry_insecure: bool = True
262
- opentelemetry_insrtumentors: list[OpenTelemetryInstrumentor] = []
303
+ opentelemetry_instrumentors: list[OpenTelemetryInstrumentor] = []
263
304
  opentelemetry_exclude_urls: list[str] = []
264
305
 
265
306
  ... # Other settings here
266
307
  ```
267
308
 
309
+ Parameters description:
310
+
311
+ - `service_name` - will be passed to the `Resource`.
312
+ - `service_version` - will be passed to the `Resource`.
313
+ - `opentelemetry_endpoint` - will be passed to `OTLPSpanExporter` as endpoint.
314
+ - `opentelemetry_namespace` - will be passed to the `Resource`.
315
+ - `opentelemetry_insecure` - is opentelemetry connection secure.
316
+ - `opentelemetry_container_name` - will be passed to the `Resource`.
317
+ - `opentelemetry_instrumentors` - a list of extra instrumentors.
318
+ - `opentelemetry_exclude_urls` - list of ignored urls.
319
+
268
320
  These settings are subsequently passed to [opentelemetry](https://opentelemetry.io/), finalizing your Opentelemetry integration.
269
321
 
270
322
  ### Logging
@@ -277,10 +329,10 @@ To utilize this feature, your application must be in non-debug mode, meaning `se
277
329
  ```python
278
330
  import logging
279
331
 
280
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
332
+ from microbootstrap.settings import BaseServiceSettings
281
333
 
282
334
 
283
- class YourSettings(BaseBootstrapSettings):
335
+ class YourSettings(BaseServiceSettings):
284
336
  service_debug: bool = False
285
337
 
286
338
  logging_log_level: int = logging.INFO
@@ -291,7 +343,7 @@ class YourSettings(BaseBootstrapSettings):
291
343
  logging_exclude_endpoints: list[str] = []
292
344
  ```
293
345
 
294
- Parameter descriptions:
346
+ Parameters description:
295
347
 
296
348
  - `logging_log_level` - The default log level.
297
349
  - `logging_flush_level` - All messages will be flushed from the buffer when a log with this level appears.
@@ -303,10 +355,10 @@ Parameter descriptions:
303
355
  ### CORS
304
356
 
305
357
  ```python
306
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
358
+ from microbootstrap.settings import BaseServiceSettings
307
359
 
308
360
 
309
- class YourSettings(BaseBootstrapSettings):
361
+ class YourSettings(BaseServiceSettings):
310
362
  cors_allowed_origins: list[str] = pydantic.Field(default_factory=list)
311
363
  cors_allowed_methods: list[str] = pydantic.Field(default_factory=list)
312
364
  cors_allowed_headers: list[str] = pydantic.Field(default_factory=list)
@@ -329,10 +381,10 @@ Parameter descriptions:
329
381
  ### Swagger
330
382
 
331
383
  ```python
332
- from microbootstrap.bootstrappers.litestar import BaseBootstrapSettings
384
+ from microbootstrap.settings import BaseServiceSettings
333
385
 
334
386
 
335
- class YourSettings(BaseBootstrapSettings):
387
+ class YourSettings(BaseServiceSettings):
336
388
  service_name: str = "micro-service"
337
389
  service_description: str = "Micro service description"
338
390
  service_version: str = "1.0.0"
@@ -412,8 +464,8 @@ The application can be configured in a similar manner:
412
464
 
413
465
  ```python
414
466
  import litestar
415
- from litestar.config.app import AppConfig
416
467
 
468
+ from microbootstrap.config.litestar import LitestarConfig
417
469
  from microbootstrap.bootstrappers.litestar import LitestarBootstrapper
418
470
  from microbootstrap import SentryConfig, OpentelemetryConfig
419
471
 
@@ -424,7 +476,7 @@ async def my_handler() -> str:
424
476
 
425
477
  application: litestar.Litestar = (
426
478
  LitestarBootstrapper(settings)
427
- .configure_application(AppConfig(route_handlers=[my_handler]))
479
+ .configure_application(LitestarConfig(route_handlers=[my_handler]))
428
480
  .bootstrap()
429
481
  )
430
482
  ```
@@ -1,19 +1,21 @@
1
1
  from microbootstrap.instruments.cors_instrument import CorsConfig
2
2
  from microbootstrap.instruments.logging_instrument import LoggingConfig
3
3
  from microbootstrap.instruments.opentelemetry_instrument import OpentelemetryConfig
4
- from microbootstrap.instruments.prometheus_instrument import PrometheusConfig
4
+ from microbootstrap.instruments.prometheus_instrument import FastApiPrometheusConfig, LitestarPrometheusConfig
5
5
  from microbootstrap.instruments.sentry_instrument import SentryConfig
6
6
  from microbootstrap.instruments.swagger_instrument import SwaggerConfig
7
- from microbootstrap.settings import LitestarSettings
7
+ from microbootstrap.settings import FastApiSettings, LitestarSettings
8
8
 
9
9
 
10
10
  __all__ = (
11
11
  "SentryConfig",
12
12
  "OpentelemetryConfig",
13
- "PrometheusConfig",
13
+ "FastApiPrometheusConfig",
14
+ "LitestarPrometheusConfig",
14
15
  "LoggingConfig",
15
16
  "LitestarBootstrapper",
16
17
  "LitestarSettings",
18
+ "FastApiSettings",
17
19
  "CorsConfig",
18
20
  "SwaggerConfig",
19
21
  )
@@ -24,15 +24,15 @@ class ApplicationBootstrapper(abc.ABC, typing.Generic[SettingsT, ApplicationT, D
24
24
  application_type: type[ApplicationT]
25
25
  application_config: DataclassT
26
26
  console_writer: ConsoleWriter
27
- __instrument_box: InstrumentBox
27
+ instrument_box: InstrumentBox
28
28
 
29
29
  def __init__(self, settings: SettingsT) -> None:
30
30
  self.settings = settings
31
31
  self.console_writer = ConsoleWriter(writer_enabled=settings.service_debug)
32
32
 
33
- if not hasattr(self, "__instrument_box"):
34
- self.__instrument_box = InstrumentBox()
35
- self.__instrument_box.initialize(self.settings)
33
+ if not hasattr(self, "instrument_box"):
34
+ self.instrument_box = InstrumentBox()
35
+ self.instrument_box.initialize(self.settings)
36
36
 
37
37
  def configure_application(
38
38
  self: typing_extensions.Self,
@@ -45,7 +45,7 @@ class ApplicationBootstrapper(abc.ABC, typing.Generic[SettingsT, ApplicationT, D
45
45
  self: typing_extensions.Self,
46
46
  instrument_config: InstrumentConfigT,
47
47
  ) -> typing_extensions.Self:
48
- self.__instrument_box.configure_instrument(instrument_config)
48
+ self.instrument_box.configure_instrument(instrument_config)
49
49
  return self
50
50
 
51
51
  def configure_instruments(
@@ -63,27 +63,30 @@ class ApplicationBootstrapper(abc.ABC, typing.Generic[SettingsT, ApplicationT, D
63
63
  [type[Instrument[InstrumentConfigT]]],
64
64
  type[Instrument[InstrumentConfigT]],
65
65
  ]:
66
- if not hasattr(cls, "__instrument_box"):
67
- cls.__instrument_box = InstrumentBox()
68
- return cls.__instrument_box.extend_instruments
66
+ if not hasattr(cls, "instrument_box"):
67
+ cls.instrument_box = InstrumentBox()
68
+ return cls.instrument_box.extend_instruments
69
69
 
70
70
  def bootstrap(self: typing_extensions.Self) -> ApplicationT:
71
- resulting_application_config = dataclass_to_dict_no_defaults(self.application_config)
72
- for instrument in self.__instrument_box.instruments:
71
+ resulting_application_config: dict[str, typing.Any] = {}
72
+ for instrument in self.instrument_box.instruments:
73
73
  if instrument.is_ready():
74
74
  instrument.bootstrap()
75
-
76
75
  resulting_application_config = merge_dict_configs(
77
76
  resulting_application_config,
78
77
  instrument.bootstrap_before(),
79
78
  )
80
79
  instrument.write_status(self.console_writer)
81
80
 
81
+ resulting_application_config = merge_dict_configs(
82
+ resulting_application_config,
83
+ dataclass_to_dict_no_defaults(self.application_config),
84
+ )
82
85
  application = self.application_type(
83
86
  **merge_dict_configs(resulting_application_config, self.bootstrap_before()),
84
87
  )
85
88
 
86
- for instrument in self.__instrument_box.instruments:
89
+ for instrument in self.instrument_box.instruments:
87
90
  if instrument.is_ready():
88
91
  application = instrument.bootstrap_after(application)
89
92
 
@@ -98,5 +101,5 @@ class ApplicationBootstrapper(abc.ABC, typing.Generic[SettingsT, ApplicationT, D
98
101
  return application
99
102
 
100
103
  def teardown(self: typing_extensions.Self) -> None:
101
- for instrument in self.__instrument_box.instruments:
104
+ for instrument in self.instrument_box.instruments:
102
105
  instrument.teardown()
@@ -0,0 +1,115 @@
1
+ import typing
2
+
3
+ import fastapi
4
+ import typing_extensions
5
+ from fastapi.middleware.cors import CORSMiddleware
6
+ from fastapi_offline_docs import enable_offline_docs
7
+ from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
8
+ from prometheus_fastapi_instrumentator import Instrumentator
9
+ from sentry_sdk.integrations.fastapi import FastApiIntegration
10
+
11
+ from microbootstrap.bootstrappers.base import ApplicationBootstrapper
12
+ from microbootstrap.config.fastapi import FastApiConfig
13
+ from microbootstrap.instruments.cors_instrument import CorsInstrument
14
+ from microbootstrap.instruments.logging_instrument import LoggingInstrument
15
+ from microbootstrap.instruments.opentelemetry_instrument import OpentelemetryInstrument
16
+ from microbootstrap.instruments.prometheus_instrument import FastApiPrometheusConfig, PrometheusInstrument
17
+ from microbootstrap.instruments.sentry_instrument import SentryInstrument
18
+ from microbootstrap.instruments.swagger_instrument import SwaggerInstrument
19
+ from microbootstrap.middlewares.fastapi import build_fastapi_logging_middleware
20
+ from microbootstrap.settings import FastApiSettings
21
+
22
+
23
+ class FastApiBootstrapper(
24
+ ApplicationBootstrapper[FastApiSettings, fastapi.FastAPI, FastApiConfig],
25
+ ):
26
+ application_config = FastApiConfig()
27
+ application_type = fastapi.FastAPI
28
+
29
+ def bootstrap_before(self: typing_extensions.Self) -> dict[str, typing.Any]:
30
+ return {
31
+ "debug": self.settings.service_debug,
32
+ "on_shutdown": [self.teardown],
33
+ "on_startup": [self.console_writer.print_bootstrap_table],
34
+ }
35
+
36
+
37
+ @FastApiBootstrapper.use_instrument()
38
+ class FastApiSentryInstrument(SentryInstrument):
39
+ def bootstrap(self) -> None:
40
+ for sentry_integration in self.instrument_config.sentry_integrations:
41
+ if isinstance(sentry_integration, FastApiIntegration):
42
+ break
43
+ else:
44
+ self.instrument_config.sentry_integrations.append(FastApiIntegration())
45
+ super().bootstrap()
46
+
47
+
48
+ @FastApiBootstrapper.use_instrument()
49
+ class FastApiSwaggerInstrument(SwaggerInstrument):
50
+ def bootstrap_before(self) -> dict[str, typing.Any]:
51
+ return {
52
+ "title": self.instrument_config.service_name,
53
+ "description": self.instrument_config.service_description,
54
+ "docs_url": self.instrument_config.swagger_path,
55
+ "version": self.instrument_config.service_version,
56
+ }
57
+
58
+ def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
59
+ if self.instrument_config.swagger_offline_docs:
60
+ enable_offline_docs(application, static_files_handler=self.instrument_config.service_static_path)
61
+ return application
62
+
63
+
64
+ @FastApiBootstrapper.use_instrument()
65
+ class FastApiCorsInstrument(CorsInstrument):
66
+ def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
67
+ application.add_middleware(
68
+ CORSMiddleware,
69
+ allow_origins=self.instrument_config.cors_allowed_origins,
70
+ allow_methods=self.instrument_config.cors_allowed_methods,
71
+ allow_headers=self.instrument_config.cors_allowed_headers,
72
+ allow_credentials=self.instrument_config.cors_allowed_credentials,
73
+ allow_origin_regex=self.instrument_config.cors_allowed_origin_regex,
74
+ expose_headers=self.instrument_config.cors_exposed_headers,
75
+ max_age=self.instrument_config.cors_max_age,
76
+ )
77
+ return application
78
+
79
+
80
+ @FastApiBootstrapper.use_instrument()
81
+ class FastApiOpentelemetryInstrument(OpentelemetryInstrument):
82
+ def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
83
+ FastAPIInstrumentor.instrument_app(
84
+ application,
85
+ tracer_provider=self.tracer_provider,
86
+ excluded_urls=self.instrument_config.opentelemetry_exclude_urls,
87
+ )
88
+ return application
89
+
90
+
91
+ @FastApiBootstrapper.use_instrument()
92
+ class FastApiLoggingInstrument(LoggingInstrument):
93
+ def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
94
+ application.add_middleware(
95
+ build_fastapi_logging_middleware(self.instrument_config.logging_exclude_endpoints),
96
+ )
97
+ return application
98
+
99
+
100
+ @FastApiBootstrapper.use_instrument()
101
+ class FastApiPrometheusInstrument(PrometheusInstrument[FastApiPrometheusConfig]):
102
+ def bootstrap_after(self, application: fastapi.FastAPI) -> fastapi.FastAPI:
103
+ Instrumentator(**self.instrument_config.prometheus_instrumentator_params).instrument(
104
+ application,
105
+ **self.instrument_config.prometheus_instrument_params,
106
+ ).expose(
107
+ application,
108
+ endpoint=self.instrument_config.prometheus_metrics_path,
109
+ **self.instrument_config.prometheus_expose_params,
110
+ )
111
+ return application
112
+
113
+ @classmethod
114
+ def get_config_type(cls) -> type[FastApiPrometheusConfig]:
115
+ return FastApiPrometheusConfig
@@ -3,22 +3,20 @@ import typing
3
3
 
4
4
  import litestar
5
5
  import litestar.types
6
- import sentry_sdk
7
6
  import typing_extensions
8
- from litestar import openapi, status_codes
9
- from litestar.config.app import AppConfig as LitestarConfig
7
+ from litestar import openapi
10
8
  from litestar.config.cors import CORSConfig as LitestarCorsConfig
11
9
  from litestar.contrib.opentelemetry.config import OpenTelemetryConfig as LitestarOpentelemetryConfig
12
- from litestar.contrib.prometheus import PrometheusConfig as LitestarPrometheusConfig
13
- from litestar.contrib.prometheus import PrometheusController
14
- from litestar.exceptions.http_exceptions import HTTPException
10
+ from litestar.contrib.prometheus import PrometheusConfig, PrometheusController
15
11
  from litestar_offline_docs import generate_static_files_config
12
+ from sentry_sdk.integrations.litestar import LitestarIntegration
16
13
 
17
14
  from microbootstrap.bootstrappers.base import ApplicationBootstrapper
15
+ from microbootstrap.config.litestar import LitestarConfig
18
16
  from microbootstrap.instruments.cors_instrument import CorsInstrument
19
17
  from microbootstrap.instruments.logging_instrument import LoggingInstrument
20
18
  from microbootstrap.instruments.opentelemetry_instrument import OpentelemetryInstrument
21
- from microbootstrap.instruments.prometheus_instrument import PrometheusInstrument
19
+ from microbootstrap.instruments.prometheus_instrument import LitestarPrometheusConfig, PrometheusInstrument
22
20
  from microbootstrap.instruments.sentry_instrument import SentryInstrument
23
21
  from microbootstrap.instruments.swagger_instrument import SwaggerInstrument
24
22
  from microbootstrap.middlewares.litestar import build_litestar_logging_middleware
@@ -41,19 +39,13 @@ class LitestarBootstrapper(
41
39
 
42
40
  @LitestarBootstrapper.use_instrument()
43
41
  class LitestarSentryInstrument(SentryInstrument):
44
- @staticmethod
45
- async def sentry_exception_catcher_hook(
46
- exception: Exception,
47
- _request_scope: litestar.types.Scope,
48
- ) -> None:
49
- if (
50
- not isinstance(exception, HTTPException)
51
- or exception.status_code >= status_codes.HTTP_500_INTERNAL_SERVER_ERROR
52
- ):
53
- sentry_sdk.capture_exception(exception)
54
-
55
- def bootstrap_before(self) -> dict[str, typing.Any]:
56
- return {"after_exception": [self.sentry_exception_catcher_hook]}
42
+ def bootstrap(self) -> None:
43
+ for sentry_integration in self.instrument_config.sentry_integrations:
44
+ if isinstance(sentry_integration, LitestarIntegration):
45
+ break
46
+ else:
47
+ self.instrument_config.sentry_integrations.append(LitestarIntegration())
48
+ super().bootstrap()
57
49
 
58
50
 
59
51
  @LitestarBootstrapper.use_instrument()
@@ -123,15 +115,19 @@ class LitestarLoggingInstrument(LoggingInstrument):
123
115
 
124
116
 
125
117
  @LitestarBootstrapper.use_instrument()
126
- class LitestarPrometheusInstrument(PrometheusInstrument):
118
+ class LitestarPrometheusInstrument(PrometheusInstrument[LitestarPrometheusConfig]):
127
119
  def bootstrap_before(self) -> dict[str, typing.Any]:
128
120
  class LitestarPrometheusController(PrometheusController):
129
121
  path = self.instrument_config.prometheus_metrics_path
130
122
  openmetrics_format = True
131
123
 
132
- litestar_prometheus_config: typing.Final = LitestarPrometheusConfig(
124
+ litestar_prometheus_config: typing.Final = PrometheusConfig(
133
125
  app_name=self.instrument_config.service_name,
134
126
  **self.instrument_config.prometheus_additional_params,
135
127
  )
136
128
 
137
129
  return {"route_handlers": [LitestarPrometheusController], "middleware": [litestar_prometheus_config.middleware]}
130
+
131
+ @classmethod
132
+ def get_config_type(cls) -> type[LitestarPrometheusConfig]:
133
+ return LitestarPrometheusConfig
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+ import dataclasses
3
+ import typing
4
+
5
+ from fastapi.datastructures import Default
6
+ from fastapi.utils import generate_unique_id
7
+ from starlette.responses import JSONResponse
8
+
9
+
10
+ if typing.TYPE_CHECKING:
11
+ from fastapi import FastAPI, Request, routing
12
+ from fastapi.middleware import Middleware
13
+ from fastapi.params import Depends
14
+ from starlette.responses import Response
15
+ from starlette.routing import BaseRoute
16
+ from starlette.types import Lifespan
17
+
18
+
19
+ AppType = typing.TypeVar("AppType", bound="FastAPI")
20
+
21
+
22
+ @dataclasses.dataclass
23
+ class FastApiConfig:
24
+ debug: bool = False
25
+ routes: list[BaseRoute] | None = None
26
+ title: str = "FastAPI"
27
+ summary: str | None = None
28
+ description: str = ""
29
+ version: str = "0.1.0"
30
+ openapi_url: str | None = "/openapi.json"
31
+ openapi_tags: list[dict[str, typing.Any]] | None = None
32
+ servers: list[dict[str, str | typing.Any]] | None = None
33
+ dependencies: typing.Sequence[Depends] | None = None
34
+ default_response_class: type[Response] = dataclasses.field(default_factory=lambda: Default(JSONResponse))
35
+ redirect_slashes: bool = True
36
+ docs_url: str | None = "/docs"
37
+ redoc_url: str | None = "/redoc"
38
+ swagger_ui_oauth2_redirect_url: str | None = "/docs/oauth2-redirect"
39
+ swagger_ui_init_oauth: dict[str, typing.Any] | None = None
40
+ middleware: typing.Sequence[Middleware] | None = None
41
+ exception_handlers: (
42
+ dict[
43
+ int | type[Exception],
44
+ typing.Callable[[Request, typing.Any], typing.Coroutine[typing.Any, typing.Any, Response]],
45
+ ]
46
+ | None
47
+ ) = None
48
+ on_startup: typing.Sequence[typing.Callable[[], typing.Any]] | None = None
49
+ on_shutdown: typing.Sequence[typing.Callable[[], typing.Any]] | None = None
50
+ lifespan: Lifespan[AppType] | None = None
51
+ terms_of_service: str | None = None
52
+ contact: dict[str, str | typing.Any] | None = None
53
+ license_info: dict[str, str | typing.Any] | None = None
54
+ openapi_prefix: str = ""
55
+ root_path: str = ""
56
+ root_path_in_servers: bool = True
57
+ responses: dict[int | str, dict[str, typing.Any]] | None = None
58
+ callbacks: list[BaseRoute] | None = None
59
+ webhooks: routing.APIRouter | None = None
60
+ deprecated: bool | None = None
61
+ include_in_schema: bool = True
62
+ swagger_ui_parameters: dict[str, typing.Any] | None = None
63
+ generate_unique_id_function: typing.Callable[[routing.APIRoute], str] = dataclasses.field(
64
+ default_factory=lambda: Default(generate_unique_id),
65
+ )
66
+ separate_input_output_schemas: bool = True
@@ -0,0 +1,14 @@
1
+ from __future__ import annotations
2
+ import dataclasses
3
+ import typing
4
+
5
+ from litestar.config.app import AppConfig
6
+
7
+
8
+ if typing.TYPE_CHECKING:
9
+ from litestar.types import OnAppInitHandler
10
+
11
+
12
+ @dataclasses.dataclass
13
+ class LitestarConfig(AppConfig):
14
+ on_app_init: typing.Sequence[OnAppInitHandler] | None = None
@@ -8,7 +8,7 @@ from granian.log import LogLevels
8
8
 
9
9
 
10
10
  if typing.TYPE_CHECKING:
11
- from microbootstrap.settings import BaseBootstrapSettings
11
+ from microbootstrap.settings import BaseServiceSettings
12
12
 
13
13
 
14
14
  GRANIAN_LOG_LEVELS_MAP = {
@@ -24,7 +24,7 @@ GRANIAN_LOG_LEVELS_MAP = {
24
24
  # TODO: create bootstrappers for application servers. granian/uvicorn # noqa: TD002
25
25
  def create_granian_server(
26
26
  target: str,
27
- settings: BaseBootstrapSettings,
27
+ settings: BaseServiceSettings,
28
28
  **granian_options: typing.Any, # noqa: ANN401
29
29
  ) -> granian.Granian:
30
30
  return granian.Granian(
@@ -34,7 +34,7 @@ def create_granian_server(
34
34
  interface=Interfaces.ASGI,
35
35
  loop=Loops.uvloop,
36
36
  workers=settings.server_workers_count,
37
- log_level=GRANIAN_LOG_LEVELS_MAP[settings.logging_log_level],
37
+ log_level=GRANIAN_LOG_LEVELS_MAP[getattr(settings, "logging_log_level", logging.INFO)],
38
38
  reload=settings.server_reload,
39
39
  **granian_options,
40
40
  )
@@ -1,3 +1,4 @@
1
+ import dataclasses
1
2
  import typing
2
3
 
3
4
  import typing_extensions
@@ -7,9 +8,10 @@ from microbootstrap.instruments.base import Instrument, InstrumentConfigT
7
8
  from microbootstrap.settings import SettingsT
8
9
 
9
10
 
11
+ @dataclasses.dataclass
10
12
  class InstrumentBox:
11
- __instruments__: typing.ClassVar[list[type[Instrument[typing.Any]]]] = []
12
- __initialized_instruments__: list[Instrument[typing.Any]]
13
+ __instruments__: list[type[Instrument[typing.Any]]] = dataclasses.field(default_factory=list)
14
+ __initialized_instruments__: list[Instrument[typing.Any]] = dataclasses.field(default_factory=list)
13
15
 
14
16
  def initialize(self, settings: SettingsT) -> None:
15
17
  settings_dump = settings.model_dump()
@@ -31,19 +33,18 @@ class InstrumentBox:
31
33
  f"Instrument for config {instrument_config.__class__.__name__} is not supported yet.",
32
34
  )
33
35
 
34
- @classmethod
35
36
  def extend_instruments(
36
- cls,
37
+ self,
37
38
  instrument_class: type[Instrument[InstrumentConfigT]],
38
39
  ) -> type[Instrument[InstrumentConfigT]]:
39
40
  """Extend list of instruments, excluding one whose config is already in use."""
40
- cls.__instruments__ = list(
41
+ self.__instruments__ = list(
41
42
  filter(
42
43
  lambda instrument: instrument.get_config_type() is not instrument_class.get_config_type(),
43
- cls.__instruments__,
44
+ self.__instruments__,
44
45
  ),
45
46
  )
46
- cls.__instruments__.append(instrument_class)
47
+ self.__instruments__.append(instrument_class)
47
48
  return instrument_class
48
49
 
49
50
  @property
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+ import typing
3
+
4
+ import pydantic
5
+
6
+ from microbootstrap.helpers import is_valid_path
7
+ from microbootstrap.instruments.base import BaseInstrumentConfig, Instrument
8
+
9
+
10
+ PrometheusConfigT = typing.TypeVar("PrometheusConfigT", bound="BasePrometheusConfig")
11
+
12
+
13
+ class BasePrometheusConfig(BaseInstrumentConfig):
14
+ service_name: str = "micro-service"
15
+
16
+ prometheus_metrics_path: str = "/metrics"
17
+
18
+
19
+ class LitestarPrometheusConfig(BasePrometheusConfig):
20
+ prometheus_additional_params: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
21
+
22
+
23
+ class FastApiPrometheusConfig(BasePrometheusConfig):
24
+ prometheus_instrumentator_params: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
25
+ prometheus_instrument_params: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
26
+ prometheus_expose_params: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
27
+
28
+
29
+ class PrometheusInstrument(Instrument[PrometheusConfigT]):
30
+ instrument_name = "Prometheus"
31
+ ready_condition = "Provide metrics_path for metrics exposure"
32
+
33
+ def is_ready(self) -> bool:
34
+ return bool(self.instrument_config.prometheus_metrics_path) and is_valid_path(
35
+ self.instrument_config.prometheus_metrics_path,
36
+ )
37
+
38
+ @classmethod
39
+ def get_config_type(cls) -> type[BasePrometheusConfig]:
40
+ return BasePrometheusConfig
File without changes
@@ -4,22 +4,24 @@ import typing
4
4
 
5
5
  import pydantic_settings
6
6
 
7
- from microbootstrap import CorsConfig, LoggingConfig, OpentelemetryConfig, PrometheusConfig, SentryConfig, SwaggerConfig
7
+ from microbootstrap import (
8
+ CorsConfig,
9
+ FastApiPrometheusConfig,
10
+ LitestarPrometheusConfig,
11
+ LoggingConfig,
12
+ OpentelemetryConfig,
13
+ SentryConfig,
14
+ SwaggerConfig,
15
+ )
8
16
 
9
17
 
10
- SettingsT = typing.TypeVar("SettingsT", bound="BaseBootstrapSettings")
18
+ SettingsT = typing.TypeVar("SettingsT", bound="BaseServiceSettings")
11
19
  ENVIRONMENT_PREFIX: typing.Final = "ENVIRONMENT_PREFIX"
12
20
 
13
21
 
14
22
  # TODO: add offline docs and cors support # noqa: TD002
15
- class BaseBootstrapSettings(
23
+ class BaseServiceSettings(
16
24
  pydantic_settings.BaseSettings,
17
- LoggingConfig,
18
- OpentelemetryConfig,
19
- SentryConfig,
20
- PrometheusConfig,
21
- SwaggerConfig,
22
- CorsConfig,
23
25
  ):
24
26
  service_debug: bool = True
25
27
  service_environment: str | None = None
@@ -41,5 +43,25 @@ class BaseBootstrapSettings(
41
43
  )
42
44
 
43
45
 
44
- class LitestarSettings(BaseBootstrapSettings):
46
+ class LitestarSettings(
47
+ BaseServiceSettings,
48
+ LoggingConfig,
49
+ OpentelemetryConfig,
50
+ SentryConfig,
51
+ LitestarPrometheusConfig,
52
+ SwaggerConfig,
53
+ CorsConfig,
54
+ ):
45
55
  """Settings for a litestar botstrap."""
56
+
57
+
58
+ class FastApiSettings(
59
+ BaseServiceSettings,
60
+ LoggingConfig,
61
+ OpentelemetryConfig,
62
+ SentryConfig,
63
+ FastApiPrometheusConfig,
64
+ SwaggerConfig,
65
+ CorsConfig,
66
+ ):
67
+ """Settings for a fastapi botstrap."""
@@ -26,7 +26,7 @@ classifiers = [
26
26
  "Programming Language :: Python :: 3.11",
27
27
  "Programming Language :: Python :: 3.12",
28
28
  ]
29
- version = "0.2.3"
29
+ version = "0.3.0"
30
30
  description = "Package for bootstrapping new micro-services"
31
31
  authors = ["community-of-python"]
32
32
  readme = "README.md"
@@ -65,7 +65,7 @@ litestar-offline-docs = { version = "^1.0.1", optional = true }
65
65
  fastapi = { version = "^0.111.0", optional = true }
66
66
  prometheus-fastapi-instrumentator = { version = "^6.1.0", optional = true }
67
67
  opentelemetry-instrumentation-fastapi = { version = "^0.46b0", optional = true }
68
-
68
+ fastapi-offline-docs = { version = "^1.0.1", optional = true }
69
69
 
70
70
  [tool.poetry.group.dev.dependencies]
71
71
  pytest = "^8.2.2"
@@ -79,11 +79,13 @@ redis = "^5.0.7"
79
79
  opentelemetry-instrumentation-redis = "^0.46b0"
80
80
  trio = "^0.26.0"
81
81
 
82
+
82
83
  [tool.poetry.extras]
83
84
  fastapi = [
84
85
  "fastapi",
85
86
  "opentelemetry-instrumentation-fastapi",
86
87
  "prometheus-fastapi-instrumentator",
88
+ "fastapi-offline-docs",
87
89
  ]
88
90
  litestar = ["litestar", "prometheus-client", "litestar-offline-docs"]
89
91
 
@@ -1,28 +0,0 @@
1
- from __future__ import annotations
2
- import typing
3
-
4
- import pydantic
5
-
6
- from microbootstrap.helpers import is_valid_path
7
- from microbootstrap.instruments.base import BaseInstrumentConfig, Instrument
8
-
9
-
10
- class PrometheusConfig(BaseInstrumentConfig):
11
- service_name: str = "micro-service"
12
-
13
- prometheus_metrics_path: str = "/metrics"
14
- prometheus_additional_params: dict[str, typing.Any] = pydantic.Field(default_factory=dict)
15
-
16
-
17
- class PrometheusInstrument(Instrument[PrometheusConfig]):
18
- instrument_name = "Prometheus"
19
- ready_condition = "Provide metrics_path for metrics exposure"
20
-
21
- def is_ready(self) -> bool:
22
- return bool(self.instrument_config.prometheus_metrics_path) and is_valid_path(
23
- self.instrument_config.prometheus_metrics_path,
24
- )
25
-
26
- @classmethod
27
- def get_config_type(cls) -> type[PrometheusConfig]:
28
- return PrometheusConfig