Prometheus integration for Starlette.

Overview

Starlette Prometheus

Build Status codecov Package Version PyPI Version

Introduction

Prometheus integration for Starlette.

Requirements

  • Python 3.6+
  • Starlette 0.9+

Installation

$ pip install starlette-prometheus

Usage

A complete example that exposes prometheus metrics endpoint under /metrics/ path.

from starlette.applications import Starlette
from starlette_prometheus import metrics, PrometheusMiddleware

app = Starlette()

app.add_middleware(PrometheusMiddleware)
app.add_route("/metrics/", metrics)

Metrics for paths that do not match any Starlette route can be filtered by passing filter_unhandled_paths=True argument to add_middleware method.

Contributing

This project is absolutely open to contributions so if you have a nice idea, create an issue to let the community discuss it.

Comments
  • Releasing new version with updated prometheus-client dep?

    Releasing new version with updated prometheus-client dep?

    Hello! I have a deps conflict due to the fact that current version fron pypi 0.7.0 is still list prometheus-client dep as <8.0 in poetry, but another package needs prometheus-client >=8.0. I see that updated dependency is already merged since august, is it possible to release something like v0.7.1 with this dependency?

    opened by DMantis 4
  • Detail how to interact with visualizations of Prometheus

    Detail how to interact with visualizations of Prometheus

    I'm a new user to Starlette, and looking to monitor some Gunicorn processes for my Starlette server. This library looks promising, and I've successfully integrated and viewed the plain text stats at /metrics.

    However, I'd like a better visualization of these performance metrics. I've looked at integrating Grafana, but am having difficulty (https://prometheus.io/docs/visualization/grafana/ looks promising).

    I'm looking for the most basic level of monitoring; the console templates at https://prometheus.io/docs/visualization/consoles/ look promising.

    It'd be really nice to have the following:

    • A couple sentences describing the configuration that Grafana needs to use starlette-prometheus (which I suspect is just prometheus).
    • Basic integration with visualizations. I'd like to see some basics graphs of the stats at /metrics with a simple HTML page. I think I'd like to see an interface like this:
    from starlette.applications import Starlette
    from starlette_prometheus import metrics, metric_viz, PrometheusMiddleware
    
    app = Starlette()
    app.add_middleware(PrometheusMiddleware)
    app.add_route("/metrics/", metrics)
    app.add_route("/metric-viz/", metric_viz)
    
    opened by stsievert 4
  • [FEATURE] Path template instead of actual path in metrics

    [FEATURE] Path template instead of actual path in metrics

    Hi, there!

    Thanks for a great middleware! I've been using it a while and now I want to show response time by url in grafana. It works good with regular paths, like /users, but not with templated paths like /users/{id} because in /metrics they appear as actual paths (/users/1, /users/2, etc...)

    I've made a quick pull request https://github.com/perdy/starlette-prometheus/pull/6 for this. Let me know what you think of this idea and feel free to decline it if anything

    opened by unmade 4
  • [FEATURE] Group unhandled paths

    [FEATURE] Group unhandled paths

    In order to reduce cardinality of prometheus metrics and labels, this pull request adds an option to group all metrics that do not match any route.

    This solves the problem of random path requests generating unwanted metrics (each requested path generates around 23 lines of metrics), which could potentially be a big issue if exposed to the internet.

    opened by tsotnikov 3
  • Record exceptions as 500 responses

    Record exceptions as 500 responses

    This way it will be possible to count the number of 5xx responses with: sum(rate(starlette_responses_total{status_code=~"50."}[1m])) query.

    Fixes https://github.com/perdy/starlette-prometheus/issues/21

    released 
    opened by matino 2
  • Error when raising exception in FastAPI: UnboundLocalError: local variable 'status_code' referenced before assignment

    Error when raising exception in FastAPI: UnboundLocalError: local variable 'status_code' referenced before assignment

    Hi,

    I'm seeing an issue with FastAPI, where I am raising an exception in a route handler. I've created a small reproducer:

    from fastapi import FastAPI
    from starlette.middleware import Middleware
    from starlette_prometheus import PrometheusMiddleware
    
    
    middleware = [
        Middleware(PrometheusMiddleware)
    ]
    
    app = FastAPI(middleware=middleware)
    
    @app.get("/")
    def read_root():
        raise ValueError("Test error")
        # return {"Hello": "World"}
    

    Here's the output from running the reproducer and calling it with curl localhost:8000/:

    output
    $ uvicorn example:app                             
    INFO:     Started server process [5099]
    INFO:     Waiting for application startup.
    INFO:     Application startup complete.
    INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
    ERROR:    Exception in ASGI application
    Traceback (most recent call last):
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/uvicorn/protocols/http/h11_impl.py", line 373, in run_asgi
        result = await app(self.scope, self.receive, self.send)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
        return await self.app(scope, receive, send)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/fastapi/applications.py", line 208, in __call__
        await super().__call__(scope, receive, send)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/applications.py", line 112, in __call__
        await self.middleware_stack(scope, receive, send)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
        await self.app(scope, receive, _send)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/middleware/base.py", line 57, in __call__
        task_group.cancel_scope.cancel()
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/anyio/_backends/_asyncio.py", line 572, in __aexit__
        raise ExceptionGroup(exceptions)
    anyio._backends._asyncio.ExceptionGroup: 2 exceptions were raised in the task group:
    ----------------------------
    Traceback (most recent call last):
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/middleware/base.py", line 30, in coro
        await self.app(scope, request.receive, send_stream.send)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/exceptions.py", line 82, in __call__
        raise exc
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/exceptions.py", line 71, in __call__
        await self.app(scope, receive, sender)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/routing.py", line 656, in __call__
        await route.handle(scope, receive, send)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/routing.py", line 259, in handle
        await self.app(scope, receive, send)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/routing.py", line 61, in app
        response = await func(request)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/fastapi/routing.py", line 226, in app
        raw_response = await run_endpoint_function(
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/fastapi/routing.py", line 161, in run_endpoint_function
        return await run_in_threadpool(dependant.call, **values)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/concurrency.py", line 39, in run_in_threadpool
        return await anyio.to_thread.run_sync(func, *args)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/anyio/to_thread.py", line 28, in run_sync
        return await get_asynclib().run_sync_in_worker_thread(func, *args, cancellable=cancellable,
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/anyio/_backends/_asyncio.py", line 818, in run_sync_in_worker_thread
        return await future
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/anyio/_backends/_asyncio.py", line 754, in run
        result = context.run(func, *args)
      File "./example.py", line 14, in read_root
        raise ValueError("Test error")
    ValueError: Test error
    ----------------------------
    Traceback (most recent call last):
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette_prometheus/middleware.py", line 53, in dispatch
        response = await call_next(request)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/middleware/base.py", line 35, in call_next
        message = await recv_stream.receive()
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/anyio/streams/memory.py", line 89, in receive
        await receive_event.wait()
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/anyio/_backends/_asyncio.py", line 1655, in wait
        await checkpoint()
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/anyio/_backends/_asyncio.py", line 440, in checkpoint
        await sleep(0)
      File "/Users/krisb/.pyenv/versions/3.8.9/lib/python3.8/asyncio/tasks.py", line 644, in sleep
        await __sleep0()
      File "/Users/krisb/.pyenv/versions/3.8.9/lib/python3.8/asyncio/tasks.py", line 638, in __sleep0
        yield
    asyncio.exceptions.CancelledError
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette/middleware/base.py", line 55, in __call__
        response = await self.dispatch_func(request, call_next)
      File "/Users/krisb/Code/temp/starlette-prometheus-repro/.venv/lib/python3.8/site-packages/starlette_prometheus/middleware.py", line 65, in dispatch
        RESPONSES.labels(method=method, path_template=path_template, status_code=status_code).inc()
    UnboundLocalError: local variable 'status_code' referenced before assignment
    
    `pip freeze` output
    anyio==3.4.0
    asgiref==3.4.1
    click==8.0.3
    fastapi==0.70.1
    h11==0.12.0
    idna==3.3
    prometheus-client==0.11.0
    pydantic==1.9.0
    sniffio==1.2.0
    starlette==0.16.0
    starlette-prometheus==0.8.0
    typing-extensions==4.0.1
    uvicorn==0.16.0
    

    It seems like starlette has started raising asyncio.exceptions.CancelledError, which is not based on Exception caught here

    https://github.com/perdy/starlette-prometheus/blob/672ffc363041924956e2cbc7c07bea6ec0dbd5a5/starlette_prometheus/middleware.py#L54

    but rather BaseException.

    I believe this was introduced in version 0.15.0 of Starlette, in PR https://github.com/encode/starlette/pull/1157.

    I've tried to change the exception catching to include both – i.e. except (Exception, asyncio.exceptions.CancelledError), this seems to revert the behavior to the expected.

    opened by kbakk 1
  • Fix:

    Fix: "UnboundLocalError: local variable 'status_code' referenced before assignment"

    Not all of the errors thrown by asyncio inherit from Exception. I was throwing an exception in a route to test my sentry intergration and it threw a asyncio.exceptions.CancelledError which inherits from BaseException (see https://github.com/python/cpython/blob/3.9/Lib/asyncio/exceptions.py#L9)

    opened by InsidersByte 1
  • How do i disable logging for specific path

    How do i disable logging for specific path

    I am using PrometheusMiddleware from starlette_prometheus ever second or the, it keeps generating log, this grows the log file.

    How do i disable this log, this specific?

    INFO:     127.0.0.1:57304 - "GET /metrics HTTP/1.1" 200 OK
    INFO:     127.0.0.1:57310 - "GET /metrics HTTP/1.1" 200 OK
    INFO:     127.0.0.1:57304 - "GET /metrics HTTP/1.1" 200 OK
    INFO:     127.0.0.1:57310 - "GET /metrics HTTP/1.1" 200 OK
    INFO:     127.0.0.1:57304 - "GET /metrics HTTP/1.1" 200 OK
    INFO:     127.0.0.1:57310 - "GET /metrics HTTP/1.1" 200 OK
    INFO:     127.0.0.1:57304 - "GET /metrics HTTP/1.1" 200 OK
    INFO:     127.0.0.1:57310 - "GET /metrics HTTP/1.1" 200 OK
    ............several  million times .............................
    INFO:     127.0.0.1:57310 - "GET /metrics HTTP/1.1" 200 OK
    
    opened by Delvify 1
  • WIP: Add test for prometheus_multiproc_dir

    WIP: Add test for prometheus_multiproc_dir

    I was wondering if we could add a test for the situation in which the environment variable prometheus_multiproc_dir is set, thus reaching 100% coverage. The problem is that we get a status code 200 OK, but the content of the response is empty. It would be nice if you have suggestions on how to correctly mock the processing using the prometheus_multiproc_dir. Many thanks and best regards.

    opened by vreyespue 1
  • Make module PEP 561 compatible.

    Make module PEP 561 compatible.

    Add py.typed to indicate that the project has inline type hints. This allows mypy to successfully import and use the type hints provided by the module.

    released 
    opened by trevora 1
  • Fix duplicated charset in the content-type header

    Fix duplicated charset in the content-type header

    The CONTENT_TYPE_LATEST constant from the prometheus_client already contains not only media type but also charset value. On the other hand, starlette adds charset value to a value passed as media_type (related place in code).

    This causes charset value duplication like: text/plain; version=0.0.4; charset=utf-8; charset=utf-8.

    released 
    opened by denysxftr 1
  • Bump certifi from 2021.10.8 to 2022.12.7

    Bump certifi from 2021.10.8 to 2022.12.7

    Bumps certifi from 2021.10.8 to 2022.12.7.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Setting requests in progress multiprocess mode as livesum

    Setting requests in progress multiprocess mode as livesum

    By default it was by pid, this could generate a lot of metrics in case of many workers and multiprocess. This can overtime stack as worker processes can restart and leak metrics like this. With this change, this would remove the pid and the metric will be the same regardless of the multiprocess context

    opened by rbizos 0
  • Revamp implementation without BaseHTTPMiddleware

    Revamp implementation without BaseHTTPMiddleware

    Hello there 👋

    Because of the numerous limitations of the BaseHTTPMiddleware class provided by Starlette, the Starlette dev' team is about to deprecate it and encourage people to write "pure" ASGI middlewares. In particular, one of this limitation causes the issue #33 here.

    This PR is an attempt at converting the existing middleware without BaseHTTPMiddleware. The resulting code is quite similar, the only "tricky" thing is the part where we wrap the send function with our own; as it's the common way to do in ASGI.

    All existing tests are passing.

    I would be glad to discuss it and make all changes needed so we can integrate this new approach in the library.

    Cheers!

    opened by frankie567 2
  • Submounted routes use incorrect path in labels

    Submounted routes use incorrect path in labels

    When submounting routes, rather than the full path template being used, only the mount prefix is used.

    Running the following app:

    from starlette.applications import Starlette
    from starlette.middleware import Middleware
    from starlette.responses import Response
    from starlette.routing import Mount, Route
    from starlette_prometheus import PrometheusMiddleware, metrics
    
    
    async def foo(request):
        return Response()
    
    
    async def bar_baz(request):
        return Response()
    
    
    routes = [
        Route("/foo", foo),
        Mount("/bar", Route("/baz", bar_baz)),
        Route("/metrics", metrics),
    ]
    middleware = [Middleware(PrometheusMiddleware)]
    app = Starlette(routes=routes, middleware=middleware)
    

    Then making the following requests:

    $ curl localhost:8000/foo
    $ curl localhost:8000/bar/baz
    $ curl localhost:8000/metrics
    

    Gives the following output (I only included one metric as an example, but it's the same for all of them). Note the label for the request to localhost:8000/bar/baz has a path label of /bar.

    starlette_requests_total{method="GET",path_template="/foo"} 1.0
    starlette_requests_total{method="GET",path_template="/bar"} 1.0
    starlette_requests_total{method="GET",path_template="/metrics"} 1.0
    
    opened by ter0 2
  • respect PROMETHEUS_MULTIPROC_DIR in example metrics view

    respect PROMETHEUS_MULTIPROC_DIR in example metrics view

    Hey

    Since prometheus_client:0.10.x deprecated prometheus_multiproc_dir in favor of PROMETHEUS_MULTIPROC_DIR. So I updated the example metrics view to also respect PROMETHEUS_MULTIPROC_DIR - wdyt?

    opened by celloni 0
Releases(v0.9.0)
Owner
José Antonio Perdiguero
Artificial Intelligence Engineer & Software Architect
José Antonio Perdiguero
Stac-fastapi built on Tile38 and Redis to support caching

stac-fastapi-caching Stac-fastapi built on Tile38 to support caching. This code is built on top of stac-fastapi-elasticsearch 0.1.0 with pyle38, a Pyt

Jonathan Healy 4 Apr 11, 2022
Regex Converter for Flask URL Routes

Flask-Reggie Enable Regex Routes within Flask Installation pip install flask-reggie Configuration To enable regex routes within your application from

Rhys Elsmore 48 Mar 07, 2022
fastapi-admin2 is an upgraded fastapi-admin, that supports ORM dialects, true Dependency Injection and extendability

FastAPI2 Admin Introduction fastapi-admin2 is an upgraded fastapi-admin, that supports ORM dialects, true Dependency Injection and extendability. Now

Glib 14 Dec 05, 2022
A Python framework to build Slack apps in a flash with the latest platform features.

Bolt for Python A Python framework to build Slack apps in a flash with the latest platform features. Read the getting started guide and look at our co

SlackAPI 684 Jan 09, 2023
User authentication fastapi with python

user-authentication-fastapi Authentication API Development Setup environment You should create a virtual environment and activate it: virtualenv venv

Sabir Hussain 3 Mar 03, 2022
Cookiecutter API for creating Custom Skills for Azure Search using Python and Docker

cookiecutter-spacy-fastapi Python cookiecutter API for quick deployments of spaCy models with FastAPI Azure Search The API interface is compatible wit

Microsoft 379 Jan 03, 2023
An extension library for FastAPI framework

FastLab An extension library for FastAPI framework Features Logging Models Utils Routers Installation use pip to install the package: pip install fast

Tezign Lab 10 Jul 11, 2022
A FastAPI Plug-In to support authentication authorization using the Microsoft Authentication Library (MSAL)

FastAPI/MSAL - MSAL (Microsoft Authentication Library) plugin for FastAPI FastAPI - https://github.com/tiangolo/fastapi FastAPI is a modern, fast (hig

Dudi Levy 15 Jul 20, 2022
A basic JSON-RPC implementation for your Flask-powered sites

Flask JSON-RPC A basic JSON-RPC implementation for your Flask-powered sites. Some reasons you might want to use: Simple, powerful, flexible and python

Cenobit Technologies 273 Dec 01, 2022
Cube-CRUD is a simple example of a REST API CRUD in a context of rubik's cube review service.

Cube-CRUD is a simple example of a REST API CRUD in a context of rubik's cube review service. It uses Sqlalchemy ORM to manage the connection and database operations.

Sebastian Andrade 1 Dec 11, 2021
A rate limiter for Starlette and FastAPI

SlowApi A rate limiting library for Starlette and FastAPI adapted from flask-limiter. Note: this is alpha quality code still, the API may change, and

Laurent Savaete 562 Jan 01, 2023
A minimum reproducible repository for embedding panel in FastAPI

FastAPI-Panel A minimum reproducible repository for embedding panel in FastAPI Follow either This Tutorial or These steps below ↓↓↓ Clone the reposito

Tyler Houssian 15 Sep 22, 2022
FastAPI Socket.io with first-class documentation using AsyncAPI

fastapi-sio Socket.io FastAPI integration library with first-class documentation using AsyncAPI The usage of the library is very familiar to the exper

Marián Hlaváč 9 Jan 02, 2023
Prometheus exporter for metrics from the MyAudi API

Prometheus Audi Exporter This Prometheus exporter exports metrics that it fetches from the MyAudi API. Usage Checkout submodules Install dependencies

Dieter Maes 7 Dec 19, 2022
OpenAPI for Todolist RESTful API

swagger-client OpenAPI for Todolist RESTful API This Python package is automatically generated by the Swagger Codegen project: API version: 1 Package

Iko Afianando 1 Dec 19, 2021
This code generator creates FastAPI app from an openapi file.

fastapi-code-generator This code generator creates FastAPI app from an openapi file. This project is an experimental phase. fastapi-code-generator use

Koudai Aono 632 Jan 05, 2023
Fastapi-ml-template - Fastapi ml template with python

FastAPI ML Template Run Web API Local $ sh run.sh # poetry run uvicorn app.mai

Yuki Okuda 29 Nov 20, 2022
LuSyringe is a documentation injection tool for your classes when using Fast API

LuSyringe LuSyringe is a documentation injection tool for your classes when using Fast API Benefits The main benefit is being able to separate your bu

Enzo Ferrari 2 Sep 06, 2021
Twitter API monitor with fastAPI + MongoDB

Twitter API monitor with fastAPI + MongoDB You need to have a file .env with the following variables: DB_URL="mongodb+srv://mongodb_path" DB_URL2=

Leonardo Ferreira 3 Apr 08, 2022
Generate modern Python clients from OpenAPI

openapi-python-client Generate modern Python clients from OpenAPI 3.x documents. This generator does not support OpenAPI 2.x FKA Swagger. If you need

Triax Technologies 558 Jan 07, 2023