This repository was archived by the owner on Sep 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add middlewares and one specific to expose
/metrics
endpoint for pr…
…ometheus (#629) did this in spare time instead of #591 using https://github.com/trallnag/prometheus-fastapi-instrumentator these middlewares can be enabled via CLI if referenced by their `type` ClassVar: ``` $ mlem --tb serve fastapi --model ../emoji/lyrics2emoji --middlewares.0 prometheus_fastapi ``` --------- Co-authored-by: mike0sv <[email protected]>
- Loading branch information
Showing
12 changed files
with
275 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
"""Instrumenting FastAPI app to expose metrics for prometheus | ||
Extension type: middleware | ||
Exposes /metrics endpoint | ||
""" | ||
from typing import ClassVar, List, Optional | ||
|
||
from fastapi import FastAPI | ||
from prometheus_fastapi_instrumentator import Instrumentator | ||
|
||
from mlem.contrib.fastapi import FastAPIMiddleware | ||
from mlem.utils.importing import import_string_with_local | ||
from mlem.utils.module import get_object_requirements | ||
|
||
|
||
class PrometheusFastAPIMiddleware(FastAPIMiddleware): | ||
"""Middleware for FastAPI server that exposes /metrics endpoint to be scraped by Prometheus""" | ||
|
||
type: ClassVar = "prometheus_fastapi" | ||
|
||
metrics: List[str] = [] | ||
"""Instrumentator instance to use. If not provided, a new one will be created""" | ||
instrumentator_cache: Optional[Instrumentator] = None | ||
|
||
class Config: | ||
arbitrary_types_allowed = True | ||
exclude = {"instrumentator_cache"} | ||
|
||
@property | ||
def instrumentator(self): | ||
if self.instrumentator_cache is None: | ||
self.instrumentator_cache = self.get_instrumentator() | ||
return self.instrumentator_cache | ||
|
||
def on_app_init(self, app: FastAPI): | ||
@app.on_event("startup") | ||
async def _startup(): | ||
self.instrumentator.expose(app) | ||
|
||
def on_init(self): | ||
pass | ||
|
||
def on_request(self, request): | ||
return request | ||
|
||
def on_response(self, request, response): | ||
return response | ||
|
||
def get_instrumentator(self): | ||
instrumentator = Instrumentator() | ||
for metric in self._iter_metric_objects(): | ||
# todo: check object type | ||
instrumentator.add(metric) | ||
return instrumentator | ||
|
||
def _iter_metric_objects(self): | ||
for metric in self.metrics: | ||
# todo: meaningful error on import error | ||
yield import_string_with_local(metric) | ||
|
||
def get_requirements(self): | ||
reqs = super().get_requirements() | ||
for metric in self._iter_metric_objects(): | ||
reqs += get_object_requirements(metric) | ||
return reqs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
from abc import abstractmethod | ||
from typing import ClassVar, List | ||
|
||
from pydantic import BaseModel | ||
|
||
from mlem.core.base import MlemABC | ||
from mlem.core.requirements import Requirements, WithRequirements | ||
|
||
|
||
class Middleware(MlemABC, WithRequirements): | ||
abs_name: ClassVar = "middleware" | ||
|
||
class Config: | ||
type_root = True | ||
|
||
@abstractmethod | ||
def on_init(self): | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def on_request(self, request): | ||
raise NotImplementedError | ||
|
||
@abstractmethod | ||
def on_response(self, request, response): | ||
raise NotImplementedError | ||
|
||
|
||
class Middlewares(BaseModel): | ||
__root__: List[Middleware] = [] | ||
"""Middlewares to add to server""" | ||
|
||
def on_init(self): | ||
for middleware in self.__root__: | ||
middleware.on_init() | ||
|
||
def on_request(self, request): | ||
for middleware in self.__root__: | ||
request = middleware.on_request(request) | ||
return request | ||
|
||
def on_response(self, request, response): | ||
for middleware in reversed(self.__root__): | ||
response = middleware.on_response(request, response) | ||
return response | ||
|
||
def get_requirements(self) -> Requirements: | ||
reqs = Requirements.new() | ||
for m in self.__root__: | ||
reqs += m.get_requirements() | ||
return reqs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.