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.
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/PKG-INFO +85 -32
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/README.md +83 -31
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/__init__.py +5 -3
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/bootstrappers/base.py +16 -13
- microbootstrap-0.3.0/microbootstrap/bootstrappers/fastapi.py +115 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/bootstrappers/litestar.py +18 -22
- microbootstrap-0.3.0/microbootstrap/config/fastapi.py +66 -0
- microbootstrap-0.3.0/microbootstrap/config/litestar.py +14 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/granian_server.py +3 -3
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/instrument_box.py +8 -7
- microbootstrap-0.3.0/microbootstrap/instruments/prometheus_instrument.py +40 -0
- microbootstrap-0.3.0/microbootstrap/py.typed +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/settings.py +32 -10
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/pyproject.toml +4 -2
- microbootstrap-0.2.3/microbootstrap/instruments/prometheus_instrument.py +0 -28
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/bootstrappers/__init__.py +0 -0
- {microbootstrap-0.2.3/microbootstrap/instruments → microbootstrap-0.3.0/microbootstrap/config}/__init__.py +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/console_writer.py +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/exceptions.py +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/helpers.py +0 -0
- {microbootstrap-0.2.3/microbootstrap/middlewares → microbootstrap-0.3.0/microbootstrap/instruments}/__init__.py +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/base.py +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/cors_instrument.py +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/logging_instrument.py +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/opentelemetry_instrument.py +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/sentry_instrument.py +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/swagger_instrument.py +0 -0
- /microbootstrap-0.2.3/microbootstrap/py.typed → /microbootstrap-0.3.0/microbootstrap/middlewares/__init__.py +0 -0
- {microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/middlewares/fastapi.py +0 -0
- {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.
|
|
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
|
|
129
|
+
$ poetry add microbootstrap -E fastapi
|
|
121
130
|
```
|
|
122
131
|
|
|
123
132
|
For pip:
|
|
124
133
|
|
|
125
134
|
```bash
|
|
126
|
-
$ pip install microbootstrap[
|
|
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 `
|
|
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 `
|
|
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(
|
|
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.
|
|
218
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
210
219
|
|
|
211
220
|
|
|
212
|
-
class ServiceSettings(
|
|
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.
|
|
251
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
243
252
|
|
|
244
253
|
|
|
245
|
-
class YourSettings(
|
|
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
|
-
|
|
264
|
-
|
|
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.
|
|
308
|
+
from microbootstrap.settings import LitestarSettings
|
|
268
309
|
|
|
269
310
|
|
|
270
|
-
class
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
339
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
298
340
|
from microbootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrumentor
|
|
299
341
|
|
|
300
342
|
|
|
301
|
-
class YourSettings(
|
|
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
|
-
|
|
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.
|
|
380
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
328
381
|
|
|
329
382
|
|
|
330
|
-
class YourSettings(
|
|
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
|
-
|
|
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.
|
|
406
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
354
407
|
|
|
355
408
|
|
|
356
|
-
class YourSettings(
|
|
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.
|
|
432
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
380
433
|
|
|
381
434
|
|
|
382
|
-
class YourSettings(
|
|
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(
|
|
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
|
|
81
|
+
$ poetry add microbootstrap -E fastapi
|
|
74
82
|
```
|
|
75
83
|
|
|
76
84
|
For pip:
|
|
77
85
|
|
|
78
86
|
```bash
|
|
79
|
-
$ pip install microbootstrap[
|
|
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 `
|
|
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 `
|
|
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(
|
|
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.
|
|
170
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
163
171
|
|
|
164
172
|
|
|
165
|
-
class ServiceSettings(
|
|
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.
|
|
203
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
196
204
|
|
|
197
205
|
|
|
198
|
-
class YourSettings(
|
|
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
|
-
|
|
217
|
-
|
|
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.
|
|
260
|
+
from microbootstrap.settings import LitestarSettings
|
|
221
261
|
|
|
222
262
|
|
|
223
|
-
class
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
291
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
251
292
|
from microbootstrap.instruments.opentelemetry_instrument import OpenTelemetryInstrumentor
|
|
252
293
|
|
|
253
294
|
|
|
254
|
-
class YourSettings(
|
|
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
|
-
|
|
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.
|
|
332
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
281
333
|
|
|
282
334
|
|
|
283
|
-
class YourSettings(
|
|
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
|
-
|
|
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.
|
|
358
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
307
359
|
|
|
308
360
|
|
|
309
|
-
class YourSettings(
|
|
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.
|
|
384
|
+
from microbootstrap.settings import BaseServiceSettings
|
|
333
385
|
|
|
334
386
|
|
|
335
|
-
class YourSettings(
|
|
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(
|
|
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
|
|
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
|
-
"
|
|
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
|
-
|
|
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, "
|
|
34
|
-
self.
|
|
35
|
-
self.
|
|
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.
|
|
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, "
|
|
67
|
-
cls.
|
|
68
|
-
return cls.
|
|
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 =
|
|
72
|
-
for instrument in self.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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 =
|
|
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
|
|
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:
|
|
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.
|
|
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__:
|
|
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
|
-
|
|
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
|
-
|
|
41
|
+
self.__instruments__ = list(
|
|
41
42
|
filter(
|
|
42
43
|
lambda instrument: instrument.get_config_type() is not instrument_class.get_config_type(),
|
|
43
|
-
|
|
44
|
+
self.__instruments__,
|
|
44
45
|
),
|
|
45
46
|
)
|
|
46
|
-
|
|
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
|
|
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="
|
|
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
|
|
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(
|
|
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.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/logging_instrument.py
RENAMED
|
File without changes
|
{microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/opentelemetry_instrument.py
RENAMED
|
File without changes
|
{microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/sentry_instrument.py
RENAMED
|
File without changes
|
{microbootstrap-0.2.3 → microbootstrap-0.3.0}/microbootstrap/instruments/swagger_instrument.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|