{"id":13634248,"url":"https://github.com/rycus86/prometheus_flask_exporter","last_synced_at":"2025-05-13T21:12:44.026Z","repository":{"id":38428586,"uuid":"111846233","full_name":"rycus86/prometheus_flask_exporter","owner":"rycus86","description":"Prometheus exporter for Flask applications","archived":false,"fork":false,"pushed_at":"2025-03-25T22:15:44.000Z","size":4292,"stargazers_count":667,"open_issues_count":41,"forks_count":162,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-11T17:37:38.147Z","etag":null,"topics":["flask","metrics","prometheus-exporter"],"latest_commit_sha":null,"homepage":"https://pypi.python.org/pypi/prometheus-flask-exporter","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rycus86.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-11-23T20:04:19.000Z","updated_at":"2025-05-05T16:37:19.000Z","dependencies_parsed_at":"2023-01-21T01:15:58.191Z","dependency_job_id":"738a239d-9b08-4159-9cbf-29c02b0c6065","html_url":"https://github.com/rycus86/prometheus_flask_exporter","commit_stats":{"total_commits":218,"total_committers":27,"mean_commits":8.074074074074074,"dds":0.3348623853211009,"last_synced_commit":"9e20f3fbb381d81de93c19afaaffdcec139aebfa"},"previous_names":[],"tags_count":83,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rycus86%2Fprometheus_flask_exporter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rycus86%2Fprometheus_flask_exporter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rycus86%2Fprometheus_flask_exporter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rycus86%2Fprometheus_flask_exporter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rycus86","download_url":"https://codeload.github.com/rycus86/prometheus_flask_exporter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253833722,"owners_count":21971473,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flask","metrics","prometheus-exporter"],"created_at":"2024-08-01T23:01:00.009Z","updated_at":"2025-05-13T21:12:39.006Z","avatar_url":"https://github.com/rycus86.png","language":"Python","funding_links":[],"categories":["Python","Monitoring"],"sub_categories":[],"readme":"# Prometheus Flask exporter\n\n[![PyPI](https://img.shields.io/pypi/v/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)\n[![PyPI](https://img.shields.io/pypi/pyversions/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)\n[![PyPI - Downloads](https://img.shields.io/pypi/dm/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)\n[![Coverage Status](https://coveralls.io/repos/github/rycus86/prometheus_flask_exporter/badge.svg?branch=master)](https://coveralls.io/github/rycus86/prometheus_flask_exporter?branch=master)\n[![Code Climate](https://codeclimate.com/github/rycus86/prometheus_flask_exporter/badges/gpa.svg)](https://codeclimate.com/github/rycus86/prometheus_flask_exporter)\n[![Test \u0026 publish package](https://github.com/rycus86/prometheus_flask_exporter/actions/workflows/test-and-publish.yml/badge.svg)](https://github.com/rycus86/prometheus_flask_exporter/actions/workflows/test-and-publish.yml)\n\nThis library provides HTTP request metrics to export into\n[Prometheus](https://prometheus.io/).\nIt can also track method invocations using convenient functions.\n\n## Installing\n\nInstall using [PIP](https://pip.pypa.io/en/stable/quickstart/):\n\n```bash\npip install prometheus-flask-exporter\n```\nor paste it into requirements.txt:\n```\n# newest version\nprometheus-flask-exporter\n\n# or with specific version number\nprometheus-flask-exporter==0.23.2\n```\nand then install dependencies from requirements.txt file as usual:\n```\npip install -r requirements.txt\n```\n\n\n## Usage\n\n```python\nfrom flask import Flask, request\nfrom prometheus_flask_exporter import PrometheusMetrics\n\napp = Flask(__name__)\nmetrics = PrometheusMetrics(app)\n\n# static information as metric\nmetrics.info('app_info', 'Application info', version='1.0.3')\n\n@app.route('/')\ndef main():\n    pass  # requests tracked by default\n\n@app.route('/skip')\n@metrics.do_not_track()\ndef skip():\n    pass  # default metrics are not collected\n\n@app.route('/\u003citem_type\u003e')\n@metrics.do_not_track()\n@metrics.counter('invocation_by_type', 'Number of invocations by type',\n         labels={'item_type': lambda: request.view_args['type']})\ndef by_type(item_type):\n    pass  # only the counter is collected, not the default metrics\n\n@app.route('/long-running')\n@metrics.gauge('in_progress', 'Long running requests in progress')\ndef long_running():\n    pass\n\n@app.route('/status/\u003cint:status\u003e')\n@metrics.do_not_track()\n@metrics.summary('requests_by_status', 'Request latencies by status',\n                 labels={'status': lambda r: r.status_code})\n@metrics.histogram('requests_by_status_and_path', 'Request latencies by status and path',\n                   labels={'status': lambda r: r.status_code, 'path': lambda: request.path})\ndef echo_status(status):\n    return 'Status: %s' % status, status\n```\n\n## Default metrics\n\nThe following metrics are exported by default\n(unless the `export_defaults` is set to `False`).\n\n- `flask_http_request_duration_seconds` (Histogram)\n  Labels: `method`, `path` and `status`.\n  Flask HTTP request duration in seconds for all Flask requests.\n- `flask_http_request_total` (Counter)\n  Labels: `method` and `status`.\n  Total number of HTTP requests for all Flask requests.\n- `flask_http_request_exceptions_total` (Counter)\n  Labels: `method` and `status`.\n  Total number of uncaught exceptions when serving Flask requests.\n- `flask_exporter_info` (Gauge)\n  Information about the Prometheus Flask exporter itself (e.g. `version`).\n\nThe prefix for the default metrics can be controlled by the `defaults_prefix` parameter.\nIf you don't want to use any prefix, pass the `prometheus_flask_exporter.NO_PREFIX` value in.\nThe buckets on the default request latency histogram can be changed by the `buckets` parameter, and if using a summary for them is more appropriate for your use case, then use the `default_latency_as_histogram=False` parameter.\n\nTo register your own *default* metrics that will track all registered\nFlask view functions, use the `register_default` function.\n\n```python\napp = Flask(__name__)\nmetrics = PrometheusMetrics(app)\n\n@app.route('/simple')\ndef simple_get():\n    pass\n    \nmetrics.register_default(\n    metrics.counter(\n        'by_path_counter', 'Request count by request paths',\n        labels={'path': lambda: request.path}\n    )\n)\n```\n\n*Note:* register your default metrics after all routes have been set up.\nAlso note, that Gauge metrics registered as default will track the\n`/metrics` endpoint, and this can't be disabled at the moment.\n\nIf you want to apply the same metric to multiple (but not all) endpoints,\ncreate its wrapper first, then add to each function.\n\n```python\napp = Flask(__name__)\nmetrics = PrometheusMetrics(app)\n\nby_path_counter = metrics.counter(\n    'by_path_counter', 'Request count by request paths',\n    labels={'path': lambda: request.path}\n)\n\n@app.route('/simple')\n@by_path_counter\ndef simple_get():\n    pass\n    \n@app.route('/plain')\n@by_path_counter\ndef plain():\n    pass\n    \n@app.route('/not/tracked/by/path')\ndef not_tracked_by_path():\n    pass\n```\n\nYou can avoid recording metrics on individual endpoints\nby decorating them with `@metrics.do_not_track()`, or use the \n`excluded_paths` argument when creating the `PrometheusMetrics` instance\nthat takes a regular expression (either a single string, or a list) and\nmatching paths will be excluded. These apply to both built-in and user-defined\ndefault metrics, unless you disable it by setting the `exclude_user_defaults`\nargument to `False`. If you have functions that are inherited or otherwise get\nmetrics collected that you don't want, you can use `@metrics.exclude_all_metrics()`\nto exclude both default and non-default metrics being collected from it.\n\n## Configuration\n\nBy default, the metrics are exposed on the same Flask application on the\n`/metrics` endpoint and using the core Prometheus registry.\nIf this doesn't suit your needs, set the `path` argument to `None` and/or\nthe `export_defaults` argument to `False` plus change the `registry`\nargument if needed.\n\nThe `group_by` constructor argument controls what\nthe default request duration metric is tracked by: endpoint (function)\ninstead of URI path (the default). This parameter also accepts a function\nto extract the value from the request, or a name of a property of the request object.\nExamples:\n\n```python\nPrometheusMetrics(app, group_by='path')         # the default\nPrometheusMetrics(app, group_by='endpoint')     # by endpoint\nPrometheusMetrics(app, group_by='url_rule')     # by URL rule\n\ndef custom_rule(req):  # the Flask request object\n    \"\"\" The name of the function becomes the label name. \"\"\"\n    return '%s::%s' % (req.method, req.path)\n\nPrometheusMetrics(app, group_by=custom_rule)    # by a function\n\n# Error: this is not supported:\nPrometheusMetrics(app, group_by=lambda r: r.path)\n```\n\n\u003e The `group_by_endpoint` argument is deprecated since 0.4.0,\n\u003e please use the new `group_by` argument.\n\nThe `register_endpoint` allows exposing the metrics endpoint on a specific path.\nIt also allows passing in a Flask application to register it on but defaults\nto the main one if not defined.\n\nSimilarly, the `start_http_server` allows exposing the endpoint on an\nindependent Flask application on a selected HTTP port.\nIt also supports overriding the endpoint's path and the HTTP listen address.\n\nYou can also set default labels to add to every request managed by\na `PrometheusMetrics` instance, using the `default_labels` argument.\nThis needs to be a dictionary, where each key will become a metric\nlabel name, and the values the label values.\nThese can be constant values, or dynamic functions, see below in the\n[Labels](#Labels) section.\n\n\u003e The `static_labels` argument is deprecated since 0.15.0,\n\u003e please use the new `default_labels` argument.\n\nIf you use another framework over Flask (perhaps\n[Connexion](https://connexion.readthedocs.io/)) then you might return\nresponses from your endpoints that Flask can't deal with by default.\nIf that is the case, you might need to pass in a `response_converter`\nthat takes the returned object and should convert that to a Flask\nfriendly response.\nSee `ConnexionPrometheusMetrics` for an example.\n\n## Labels\n\nWhen defining labels for metrics on functions,\nthe following values are supported in the dictionary:\n\n- A simple static value\n- A no-argument callable\n- A single argument callable that will receive the Flask response\n  as the argument\n\nLabel values are evaluated within the request context.\n\n## Initial metric values\n_For more info see: https://github.com/prometheus/client_python#labels_\n\nMetrics without any labels will get an initial value.\nMetrics that only have static-value labels will also have an initial value. (except when they are created with the option `initial_value_when_only_static_labels=False`)\nMetrics that have one or more callable-value labels will not have an initial value.\n\n## Application information\n\nThe `PrometheusMetrics.info(..)` method provides a way to expose\ninformation as a `Gauge` metric, the application version for example.\n\nThe metric is returned from the method to allow changing its value\nfrom the default `1`:\n\n```python\nmetrics = PrometheusMetrics(app)\ninfo = metrics.info('dynamic_info', 'Something dynamic')\n...\ninfo.set(42.1)\n```\n\n## Examples\n\nSee some simple examples visualized on a Grafana dashboard by running\nthe demo in the [examples/sample-signals](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples/sample-signals) folder.\n\n![Example dashboard](https://github.com/rycus86/prometheus_flask_exporter/raw/master/examples/sample-signals/dashboard.png)\n\n## App Factory Pattern\n\nThis library also supports the Flask [app factory pattern](http://flask.pocoo.org/docs/1.0/patterns/appfactories/). Use the `init_app` method to attach the library to one or more application objects. Note, that to use this mode, you'll need to use the `for_app_factory()` class method to create the `metrics` instance, or pass in `None` for the `app` in the constructor.\n\n```python\nmetrics = PrometheusMetrics.for_app_factory()\n# then later:\nmetrics.init_app(app)\n```\n\n## Securing the metrics endpoint\n\nIf you wish to have authentication (or any other special handling) on the metrics endpoint,\nyou can use the `metrics_decorator` argument when creating the `PrometheusMetrics` instance.\nFor example to integrate with [Flask-HTTPAuth](https://github.com/miguelgrinberg/Flask-HTTPAuth)\nuse it like it's shown in the example below.\n\n```python\napp = Flask(__name__)\nauth = HTTPBasicAuth()\nmetrics = PrometheusMetrics(app, metrics_decorator=auth.login_required)\n\n# ... other authentication setup like @auth.verify_password below\n```\n\nSee a full example in the [examples/flask-httpauth](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples/flask-httpauth) folder.\n\n## Custom metrics endpoint\n\nYou can also take full control of the metrics endpoint by generating its contents,\nand managing how it is exposed by yourself.\n\n```python\napp = Flask(__name__)\n# path=None to avoid registering a /metrics endpoint on the same Flask app\nmetrics = PrometheusMetrics(app, path=None)\n\n# later ... generate the response (and its content type) to expose to Prometheus\nresponse_data, content_type = metrics.generate_metrics()\n```\n\nSee the related conversation in [issue #135](https://github.com/rycus86/prometheus_flask_exporter/issues/135).\n\n## Debug mode\n\nPlease note, that changes being live-reloaded, when running the Flask\napp with `debug=True`, are not going to be reflected in the metrics.\nSee [https://github.com/rycus86/prometheus_flask_exporter/issues/4](https://github.com/rycus86/prometheus_flask_exporter/issues/4)\nfor more details.\n\nAlternatively - since version `0.5.1` - if you set the `DEBUG_METRICS`\nenvironment variable, you will get metrics for the latest reloaded code.\nThese will be exported on the main Flask app.\nServing the metrics on a different port is not going to work\nmost probably - e.g. `PrometheusMetrics.start_http_server(..)` is not\nexpected to work.\n\n## WSGI\n\nGetting accurate metrics for WSGI apps might require a bit more setup.\nSee a working sample app in the `examples` folder, and also the\n[prometheus_flask_exporter#5](https://github.com/rycus86/prometheus_flask_exporter/issues/5) issue.\n\n### Multiprocess applications\n\nFor multiprocess applications (WSGI or otherwise), you can find some\nhelper classes in the `prometheus_flask_exporter.multiprocess` module.\nThese provide convenience wrappers for exposing metrics in an\nenvironment where multiple copies of the application will run on a single host.\n\n```python\n# an extension targeted at Gunicorn deployments\nfrom prometheus_flask_exporter.multiprocess import GunicornPrometheusMetrics\n\napp = Flask(__name__)\nmetrics = GunicornPrometheusMetrics(app)\n\n# then in the Gunicorn config file:\nfrom prometheus_flask_exporter.multiprocess import GunicornPrometheusMetrics\n\ndef when_ready(server):\n    GunicornPrometheusMetrics.start_http_server_when_ready(8080)\n\ndef child_exit(server, worker):\n    GunicornPrometheusMetrics.mark_process_dead_on_child_exit(worker.pid)\n```\n\nAlso see the `GunicornInternalPrometheusMetrics` class if you want to have\nthe metrics HTTP endpoint exposed internally, on the same Flask application.\n\n```python\n# an extension targeted at Gunicorn deployments with an internal metrics endpoint\nfrom prometheus_flask_exporter.multiprocess import GunicornInternalPrometheusMetrics\n\napp = Flask(__name__)\nmetrics = GunicornInternalPrometheusMetrics(app)\n\n# then in the Gunicorn config file:\nfrom prometheus_flask_exporter.multiprocess import GunicornInternalPrometheusMetrics\n\ndef child_exit(server, worker):\n    GunicornInternalPrometheusMetrics.mark_process_dead_on_child_exit(worker.pid)\n```\n\nThere's a small wrapper available for [Gunicorn](https://gunicorn.org/) and\n[uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/index.html), for everything\nelse you can extend the `prometheus_flask_exporter.multiprocess.MultiprocessPrometheusMetrics` class\nand implement the `should_start_http_server` method at least.\n\n```python\nfrom prometheus_flask_exporter.multiprocess import MultiprocessPrometheusMetrics\n\nclass MyMultiprocessMetrics(MultiprocessPrometheusMetrics):\n    def should_start_http_server(self):\n        return this_worker() == primary_worker()\n```\n\nThis should return `True` on one process only, and the underlying\n[Prometheus client library](https://github.com/prometheus/client_python)\nwill collect the metrics for all the forked children or siblings.\n\nAn additional Flask extension for apps with `processes=N` and `threaded=False` exists\nwith the `MultiprocessInternalPrometheusMetrics` class.\n\n```python\nfrom flask import Flask\nfrom prometheus_flask_exporter.multiprocess import MultiprocessInternalPrometheusMetrics\n\napp = Flask(__name__)\nmetrics = MultiprocessInternalPrometheusMetrics(app)\n\n...\n\nif __name__ == '__main__':\n    app.run('0.0.0.0', 4000, processes=5, threaded=False)\n```\n\n__Note:__ this needs the `PROMETHEUS_MULTIPROC_DIR` environment variable\nto point to a valid, writable directory.\n\nYou'll also have to call the `metrics.start_http_server()` function\nexplicitly somewhere, and the `should_start_http_server` takes care of\nonly starting it once.\nThe [examples](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples) folder\nhas some working examples on this.\n\nPlease also note, that the Prometheus client library does not collect process level\nmetrics, like memory, CPU and Python GC stats when multiprocessing is enabled.\nSee the [prometheus_flask_exporter#18](https://github.com/rycus86/prometheus_flask_exporter/issues/18)\nissue for some more context and details.\n\nA final caveat is that the metrics HTTP server will listen on __any__ paths\non the given HTTP port, not only on `/metrics`, and it is not implemented\nat the moment to be able to change this.\n\n### uWSGI lazy-apps\n\nWhen [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/) is configured \nto run with [lazy-apps]([lazy-apps](https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html#preforking-vs-lazy-apps-vs-lazy)),\nexposing the metrics endpoint on a separate HTTP server (and port) is not functioning yet.\nA workaround is to register the endpoint on the main Flask application.\n\n```python\napp = Flask(__name__)\nmetrics = UWsgiPrometheusMetrics(app)\nmetrics.register_endpoint('/metrics')\n# instead of metrics.start_http_server(port)\n```\n\nSee [#31](https://github.com/rycus86/prometheus_flask_exporter/issues/31)\nfor context, and please let me know if you know a better way!\n\n## Connexion integration\n\nThe [Connexion](https://connexion.readthedocs.io/) library has some\nsupport to automatically deal with certain response types, for example\ndataclasses, which a plain Flask application would not accept.\nTo ease the integration, you can use `ConnexionPrometheusMetrics` in\nplace of `PrometheusMetrics` that has the `response_converter` set\nappropriately to be able to deal with whatever Connexion supports for\nFlask integrations.\n\n```python\nimport connexion\nfrom prometheus_flask_exporter import ConnexionPrometheusMetrics\n\napp = connexion.App(__name__)\nmetrics = ConnexionPrometheusMetrics(app)\n```\n\nSee a working sample app in the `examples` folder, and also the\n[prometheus_flask_exporter#61](https://github.com/rycus86/prometheus_flask_exporter/issues/61) issue. \n\nThere's a caveat about this integration, where any endpoints that\ndo not return JSON responses need to be decorated with\n`@metrics.content_type('...')` as this integration would force them\nto be `application/json` otherwise.\n\n```python\nmetrics = ConnexionPrometheusMetrics(app)\n\n@metrics.content_type('text/plain')\ndef plain_response():\n    return 'plain text'\n```\n\nSee the [prometheus_flask_exporter#64](https://github.com/rycus86/prometheus_flask_exporter/issues/64) issue for more details.\n\n## Flask-RESTful integration\n\nThe [Flask-RESTful library](https://flask-restful.readthedocs.io/) has\nsome custom response handling logic, which can be helpful in some cases.\nFor example, returning `None` would fail on plain Flask, but it\nworks on Flask-RESTful.\nTo ease the integration, you can use `RESTfulPrometheusMetrics` in\nplace of `PrometheusMetrics` that sets the `response_converter` to use\nthe Flask-RESTful `API` response utilities.\n\n```python\nfrom flask import Flask\nfrom flask_restful import Api\nfrom prometheus_flask_exporter import RESTfulPrometheusMetrics\n\napp = Flask(__name__)\nrestful_api = Api(app)\nmetrics = RESTfulPrometheusMetrics(app, restful_api)\n```\n\nSee a working sample app in the `examples` folder, and also the\n[prometheus_flask_exporter#62](https://github.com/rycus86/prometheus_flask_exporter/issues/62) issue.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frycus86%2Fprometheus_flask_exporter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frycus86%2Fprometheus_flask_exporter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frycus86%2Fprometheus_flask_exporter/lists"}