summaryrefslogtreecommitdiff
path: root/python-prometheus-flask-exporter.spec
diff options
context:
space:
mode:
Diffstat (limited to 'python-prometheus-flask-exporter.spec')
-rw-r--r--python-prometheus-flask-exporter.spec1547
1 files changed, 1547 insertions, 0 deletions
diff --git a/python-prometheus-flask-exporter.spec b/python-prometheus-flask-exporter.spec
new file mode 100644
index 0000000..2f9a3e4
--- /dev/null
+++ b/python-prometheus-flask-exporter.spec
@@ -0,0 +1,1547 @@
+%global _empty_manifest_terminate_build 0
+Name: python-prometheus-flask-exporter
+Version: 0.22.3
+Release: 1
+Summary: Prometheus metrics exporter for Flask
+License: MIT
+URL: https://github.com/rycus86/prometheus_flask_exporter
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/f5/a8/a6c0625cd1efc5f475ab8f3ca508eedcc3d199bfa9d390214406af37b144/prometheus_flask_exporter-0.22.3.tar.gz
+BuildArch: noarch
+
+Requires: python3-prometheus-client
+Requires: python3-flask
+
+%description
+# Prometheus Flask exporter
+
+[![PyPI](https://img.shields.io/pypi/v/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)
+[![PyPI](https://img.shields.io/pypi/pyversions/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)
+[![PyPI - Downloads](https://img.shields.io/pypi/dm/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)
+[![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)
+[![Code Climate](https://codeclimate.com/github/rycus86/prometheus_flask_exporter/badges/gpa.svg)](https://codeclimate.com/github/rycus86/prometheus_flask_exporter)
+[![Test & 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)
+
+This library provides HTTP request metrics to export into
+[Prometheus](https://prometheus.io/).
+It can also track method invocations using convenient functions.
+
+## Installing
+
+Install using [PIP](https://pip.pypa.io/en/stable/quickstart/):
+
+```bash
+pip install prometheus-flask-exporter
+```
+or paste it into requirements.txt:
+```
+# newest version
+prometheus-flask-exporter
+
+# or with specific version number
+prometheus-flask-exporter==0.22.3
+```
+and then install dependencies from requirements.txt file as usual:
+```
+pip install -r requirements.txt
+```
+
+
+## Usage
+
+```python
+from flask import Flask, request
+from prometheus_flask_exporter import PrometheusMetrics
+
+app = Flask(__name__)
+metrics = PrometheusMetrics(app)
+
+# static information as metric
+metrics.info('app_info', 'Application info', version='1.0.3')
+
+@app.route('/')
+def main():
+ pass # requests tracked by default
+
+@app.route('/skip')
+@metrics.do_not_track()
+def skip():
+ pass # default metrics are not collected
+
+@app.route('/<item_type>')
+@metrics.do_not_track()
+@metrics.counter('invocation_by_type', 'Number of invocations by type',
+ labels={'item_type': lambda: request.view_args['type']})
+def by_type(item_type):
+ pass # only the counter is collected, not the default metrics
+
+@app.route('/long-running')
+@metrics.gauge('in_progress', 'Long running requests in progress')
+def long_running():
+ pass
+
+@app.route('/status/<int:status>')
+@metrics.do_not_track()
+@metrics.summary('requests_by_status', 'Request latencies by status',
+ labels={'status': lambda r: r.status_code})
+@metrics.histogram('requests_by_status_and_path', 'Request latencies by status and path',
+ labels={'status': lambda r: r.status_code, 'path': lambda: request.path})
+def echo_status(status):
+ return 'Status: %s' % status, status
+```
+
+## Default metrics
+
+The following metrics are exported by default
+(unless the `export_defaults` is set to `False`).
+
+- `flask_http_request_duration_seconds` (Histogram)
+ Labels: `method`, `path` and `status`.
+ Flask HTTP request duration in seconds for all Flask requests.
+- `flask_http_request_total` (Counter)
+ Labels: `method` and `status`.
+ Total number of HTTP requests for all Flask requests.
+- `flask_http_request_exceptions_total` (Counter)
+ Labels: `method` and `status`.
+ Total number of uncaught exceptions when serving Flask requests.
+- `flask_exporter_info` (Gauge)
+ Information about the Prometheus Flask exporter itself (e.g. `version`).
+
+The prefix for the default metrics can be controlled by the `defaults_prefix` parameter.
+If you don't want to use any prefix, pass the `prometheus_flask_exporter.NO_PREFIX` value in.
+The 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.
+
+To register your own *default* metrics that will track all registered
+Flask view functions, use the `register_default` function.
+
+```python
+app = Flask(__name__)
+metrics = PrometheusMetrics(app)
+
+@app.route('/simple')
+def simple_get():
+ pass
+
+metrics.register_default(
+ metrics.counter(
+ 'by_path_counter', 'Request count by request paths',
+ labels={'path': lambda: request.path}
+ )
+)
+```
+
+*Note:* register your default metrics after all routes have been set up.
+Also note, that Gauge metrics registered as default will track the
+`/metrics` endpoint, and this can't be disabled at the moment.
+
+If you want to apply the same metric to multiple (but not all) endpoints,
+create its wrapper first, then add to each function.
+
+```python
+app = Flask(__name__)
+metrics = PrometheusMetrics(app)
+
+by_path_counter = metrics.counter(
+ 'by_path_counter', 'Request count by request paths',
+ labels={'path': lambda: request.path}
+)
+
+@app.route('/simple')
+@by_path_counter
+def simple_get():
+ pass
+
+@app.route('/plain')
+@by_path_counter
+def plain():
+ pass
+
+@app.route('/not/tracked/by/path')
+def not_tracked_by_path():
+ pass
+```
+
+You can avoid recording metrics on individual endpoints
+by decorating them with `@metrics.do_not_track()`, or use the
+`excluded_paths` argument when creating the `PrometheusMetrics` instance
+that takes a regular expression (either a single string, or a list) and
+matching paths will be excluded. These apply to both built-in and user-defined
+default metrics, unless you disable it by setting the `exclude_user_defaults`
+argument to `False`. If you have functions that are inherited or otherwise get
+metrics collected that you don't want, you can use `@metrics.exclude_all_metrics()`
+to exclude both default and non-default metrics being collected from it.
+
+## Configuration
+
+By default, the metrics are exposed on the same Flask application on the
+`/metrics` endpoint and using the core Prometheus registry.
+If this doesn't suit your needs, set the `path` argument to `None` and/or
+the `export_defaults` argument to `False` plus change the `registry`
+argument if needed.
+
+The `group_by` constructor argument controls what
+the default request duration metric is tracked by: endpoint (function)
+instead of URI path (the default). This parameter also accepts a function
+to extract the value from the request, or a name of a property of the request object.
+Examples:
+
+```python
+PrometheusMetrics(app, group_by='path') # the default
+PrometheusMetrics(app, group_by='endpoint') # by endpoint
+PrometheusMetrics(app, group_by='url_rule') # by URL rule
+
+def custom_rule(req): # the Flask request object
+ """ The name of the function becomes the label name. """
+ return '%s::%s' % (req.method, req.path)
+
+PrometheusMetrics(app, group_by=custom_rule) # by a function
+
+# Error: this is not supported:
+PrometheusMetrics(app, group_by=lambda r: r.path)
+```
+
+> The `group_by_endpoint` argument is deprecated since 0.4.0,
+> please use the new `group_by` argument.
+
+The `register_endpoint` allows exposing the metrics endpoint on a specific path.
+It also allows passing in a Flask application to register it on but defaults
+to the main one if not defined.
+
+Similarly, the `start_http_server` allows exposing the endpoint on an
+independent Flask application on a selected HTTP port.
+It also supports overriding the endpoint's path and the HTTP listen address.
+
+You can also set default labels to add to every request managed by
+a `PrometheusMetrics` instance, using the `default_labels` argument.
+This needs to be a dictionary, where each key will become a metric
+label name, and the values the label values.
+These can be constant values, or dynamic functions, see below in the
+[Labels](#Labels) section.
+
+> The `static_labels` argument is deprecated since 0.15.0,
+> please use the new `default_labels` argument.
+
+If you use another framework over Flask (perhaps
+[Connexion](https://connexion.readthedocs.io/)) then you might return
+responses from your endpoints that Flask can't deal with by default.
+If that is the case, you might need to pass in a `response_converter`
+that takes the returned object and should convert that to a Flask
+friendly response.
+See `ConnexionPrometheusMetrics` for an example.
+
+## Labels
+
+When defining labels for metrics on functions,
+the following values are supported in the dictionary:
+
+- A simple static value
+- A no-argument callable
+- A single argument callable that will receive the Flask response
+ as the argument
+
+Label values are evaluated within the request context.
+
+## Initial metric values
+_For more info see: https://github.com/prometheus/client_python#labels_
+
+Metrics without any labels will get an initial value.
+Metrics 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`)
+Metrics that have one or more callable-value labels will not have an initial value.
+
+## Application information
+
+The `PrometheusMetrics.info(..)` method provides a way to expose
+information as a `Gauge` metric, the application version for example.
+
+The metric is returned from the method to allow changing its value
+from the default `1`:
+
+```python
+metrics = PrometheusMetrics(app)
+info = metrics.info('dynamic_info', 'Something dynamic')
+...
+info.set(42.1)
+```
+
+## Examples
+
+See some simple examples visualized on a Grafana dashboard by running
+the demo in the [examples/sample-signals](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples/sample-signals) folder.
+
+![Example dashboard](https://github.com/rycus86/prometheus_flask_exporter/raw/master/examples/sample-signals/dashboard.png)
+
+## App Factory Pattern
+
+This 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.
+
+```python
+metrics = PrometheusMetrics.for_app_factory()
+# then later:
+metrics.init_app(app)
+```
+
+## Securing the metrics endpoint
+
+If you wish to have authentication (or any other special handling) on the metrics endpoint,
+you can use the `metrics_decorator` argument when creating the `PrometheusMetrics` instance.
+For example to integrate with [Flask-HTTPAuth](https://github.com/miguelgrinberg/Flask-HTTPAuth)
+use it like it's shown in the example below.
+
+```python
+app = Flask(__name__)
+auth = HTTPBasicAuth()
+metrics = PrometheusMetrics(app, metrics_decorator=auth.login_required)
+
+# ... other authentication setup like @auth.verify_password below
+```
+
+See a full example in the [examples/flask-httpauth](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples/flask-httpauth) folder.
+
+## Custom metrics endpoint
+
+You can also take full control of the metrics endpoint by generating its contents,
+and managing how it is exposed by yourself.
+
+```python
+app = Flask(__name__)
+# path=None to avoid registering a /metrics endpoint on the same Flask app
+metrics = PrometheusMetrics(app, path=None)
+
+# later ... generate the response (and its content type) to expose to Prometheus
+response_data, content_type = metrics.generate_metrics()
+```
+
+See the related conversation in [issue #135](https://github.com/rycus86/prometheus_flask_exporter/issues/135).
+
+## Debug mode
+
+Please note, that changes being live-reloaded, when running the Flask
+app with `debug=True`, are not going to be reflected in the metrics.
+See [https://github.com/rycus86/prometheus_flask_exporter/issues/4](https://github.com/rycus86/prometheus_flask_exporter/issues/4)
+for more details.
+
+Alternatively - since version `0.5.1` - if you set the `DEBUG_METRICS`
+environment variable, you will get metrics for the latest reloaded code.
+These will be exported on the main Flask app.
+Serving the metrics on a different port is not going to work
+most probably - e.g. `PrometheusMetrics.start_http_server(..)` is not
+expected to work.
+
+## WSGI
+
+Getting accurate metrics for WSGI apps might require a bit more setup.
+See a working sample app in the `examples` folder, and also the
+[prometheus_flask_exporter#5](https://github.com/rycus86/prometheus_flask_exporter/issues/5) issue.
+
+### Multiprocess applications
+
+For multiprocess applications (WSGI or otherwise), you can find some
+helper classes in the `prometheus_flask_exporter.multiprocess` module.
+These provide convenience wrappers for exposing metrics in an
+environment where multiple copies of the application will run on a single host.
+
+```python
+# an extension targeted at Gunicorn deployments
+from prometheus_flask_exporter.multiprocess import GunicornPrometheusMetrics
+
+app = Flask(__name__)
+metrics = GunicornPrometheusMetrics(app)
+
+# then in the Gunicorn config file:
+from prometheus_flask_exporter.multiprocess import GunicornPrometheusMetrics
+
+def when_ready(server):
+ GunicornPrometheusMetrics.start_http_server_when_ready(8080)
+
+def child_exit(server, worker):
+ GunicornPrometheusMetrics.mark_process_dead_on_child_exit(worker.pid)
+```
+
+Also see the `GunicornInternalPrometheusMetrics` class if you want to have
+the metrics HTTP endpoint exposed internally, on the same Flask application.
+
+```python
+# an extension targeted at Gunicorn deployments with an internal metrics endpoint
+from prometheus_flask_exporter.multiprocess import GunicornInternalPrometheusMetrics
+
+app = Flask(__name__)
+metrics = GunicornInternalPrometheusMetrics(app)
+
+# then in the Gunicorn config file:
+from prometheus_flask_exporter.multiprocess import GunicornInternalPrometheusMetrics
+
+def child_exit(server, worker):
+ GunicornInternalPrometheusMetrics.mark_process_dead_on_child_exit(worker.pid)
+```
+
+There's a small wrapper available for [Gunicorn](https://gunicorn.org/) and
+[uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/index.html), for everything
+else you can extend the `prometheus_flask_exporter.multiprocess.MultiprocessPrometheusMetrics` class
+and implement the `should_start_http_server` method at least.
+
+```python
+from prometheus_flask_exporter.multiprocess import MultiprocessPrometheusMetrics
+
+class MyMultiprocessMetrics(MultiprocessPrometheusMetrics):
+ def should_start_http_server(self):
+ return this_worker() == primary_worker()
+```
+
+This should return `True` on one process only, and the underlying
+[Prometheus client library](https://github.com/prometheus/client_python)
+will collect the metrics for all the forked children or siblings.
+
+An additional Flask extension for apps with `processes=N` and `threaded=False` exists
+with the `MultiprocessInternalPrometheusMetrics` class.
+
+```python
+from flask import Flask
+from prometheus_flask_exporter.multiprocess import MultiprocessInternalPrometheusMetrics
+
+app = Flask(__name__)
+metrics = MultiprocessInternalPrometheusMetrics(app)
+
+...
+
+if __name__ == '__main__':
+ app.run('0.0.0.0', 4000, processes=5, threaded=False)
+```
+
+__Note:__ this needs the `PROMETHEUS_MULTIPROC_DIR` environment variable
+to point to a valid, writable directory.
+
+You'll also have to call the `metrics.start_http_server()` function
+explicitly somewhere, and the `should_start_http_server` takes care of
+only starting it once.
+The [examples](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples) folder
+has some working examples on this.
+
+Please also note, that the Prometheus client library does not collect process level
+metrics, like memory, CPU and Python GC stats when multiprocessing is enabled.
+See the [prometheus_flask_exporter#18](https://github.com/rycus86/prometheus_flask_exporter/issues/18)
+issue for some more context and details.
+
+A final caveat is that the metrics HTTP server will listen on __any__ paths
+on the given HTTP port, not only on `/metrics`, and it is not implemented
+at the moment to be able to change this.
+
+### uWSGI lazy-apps
+
+When [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/) is configured
+to run with [lazy-apps]([lazy-apps](https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html#preforking-vs-lazy-apps-vs-lazy)),
+exposing the metrics endpoint on a separate HTTP server (and port) is not functioning yet.
+A workaround is to register the endpoint on the main Flask application.
+
+```python
+app = Flask(__name__)
+metrics = UWsgiPrometheusMetrics(app)
+metrics.register_endpoint('/metrics')
+# instead of metrics.start_http_server(port)
+```
+
+See [#31](https://github.com/rycus86/prometheus_flask_exporter/issues/31)
+for context, and please let me know if you know a better way!
+
+## Connexion integration
+
+The [Connexion](https://connexion.readthedocs.io/) library has some
+support to automatically deal with certain response types, for example
+dataclasses, which a plain Flask application would not accept.
+To ease the integration, you can use `ConnexionPrometheusMetrics` in
+place of `PrometheusMetrics` that has the `response_converter` set
+appropriately to be able to deal with whatever Connexion supports for
+Flask integrations.
+
+```python
+import connexion
+from prometheus_flask_exporter import ConnexionPrometheusMetrics
+
+app = connexion.App(__name__)
+metrics = ConnexionPrometheusMetrics(app)
+```
+
+See a working sample app in the `examples` folder, and also the
+[prometheus_flask_exporter#61](https://github.com/rycus86/prometheus_flask_exporter/issues/61) issue.
+
+There's a caveat about this integration, where any endpoints that
+do not return JSON responses need to be decorated with
+`@metrics.content_type('...')` as this integration would force them
+to be `application/json` otherwise.
+
+```python
+metrics = ConnexionPrometheusMetrics(app)
+
+@metrics.content_type('text/plain')
+def plain_response():
+ return 'plain text'
+```
+
+See the [prometheus_flask_exporter#64](https://github.com/rycus86/prometheus_flask_exporter/issues/64) issue for more details.
+
+## Flask-RESTful integration
+
+The [Flask-RESTful library](https://flask-restful.readthedocs.io/) has
+some custom response handling logic, which can be helpful in some cases.
+For example, returning `None` would fail on plain Flask, but it
+works on Flask-RESTful.
+To ease the integration, you can use `RESTfulPrometheusMetrics` in
+place of `PrometheusMetrics` that sets the `response_converter` to use
+the Flask-RESTful `API` response utilities.
+
+```python
+from flask import Flask
+from flask_restful import Api
+from prometheus_flask_exporter import RESTfulPrometheusMetrics
+
+app = Flask(__name__)
+restful_api = Api(app)
+metrics = RESTfulPrometheusMetrics(app, restful_api)
+```
+
+See a working sample app in the `examples` folder, and also the
+[prometheus_flask_exporter#62](https://github.com/rycus86/prometheus_flask_exporter/issues/62) issue.
+
+## License
+
+MIT
+
+
+%package -n python3-prometheus-flask-exporter
+Summary: Prometheus metrics exporter for Flask
+Provides: python-prometheus-flask-exporter
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-prometheus-flask-exporter
+# Prometheus Flask exporter
+
+[![PyPI](https://img.shields.io/pypi/v/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)
+[![PyPI](https://img.shields.io/pypi/pyversions/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)
+[![PyPI - Downloads](https://img.shields.io/pypi/dm/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)
+[![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)
+[![Code Climate](https://codeclimate.com/github/rycus86/prometheus_flask_exporter/badges/gpa.svg)](https://codeclimate.com/github/rycus86/prometheus_flask_exporter)
+[![Test & 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)
+
+This library provides HTTP request metrics to export into
+[Prometheus](https://prometheus.io/).
+It can also track method invocations using convenient functions.
+
+## Installing
+
+Install using [PIP](https://pip.pypa.io/en/stable/quickstart/):
+
+```bash
+pip install prometheus-flask-exporter
+```
+or paste it into requirements.txt:
+```
+# newest version
+prometheus-flask-exporter
+
+# or with specific version number
+prometheus-flask-exporter==0.22.3
+```
+and then install dependencies from requirements.txt file as usual:
+```
+pip install -r requirements.txt
+```
+
+
+## Usage
+
+```python
+from flask import Flask, request
+from prometheus_flask_exporter import PrometheusMetrics
+
+app = Flask(__name__)
+metrics = PrometheusMetrics(app)
+
+# static information as metric
+metrics.info('app_info', 'Application info', version='1.0.3')
+
+@app.route('/')
+def main():
+ pass # requests tracked by default
+
+@app.route('/skip')
+@metrics.do_not_track()
+def skip():
+ pass # default metrics are not collected
+
+@app.route('/<item_type>')
+@metrics.do_not_track()
+@metrics.counter('invocation_by_type', 'Number of invocations by type',
+ labels={'item_type': lambda: request.view_args['type']})
+def by_type(item_type):
+ pass # only the counter is collected, not the default metrics
+
+@app.route('/long-running')
+@metrics.gauge('in_progress', 'Long running requests in progress')
+def long_running():
+ pass
+
+@app.route('/status/<int:status>')
+@metrics.do_not_track()
+@metrics.summary('requests_by_status', 'Request latencies by status',
+ labels={'status': lambda r: r.status_code})
+@metrics.histogram('requests_by_status_and_path', 'Request latencies by status and path',
+ labels={'status': lambda r: r.status_code, 'path': lambda: request.path})
+def echo_status(status):
+ return 'Status: %s' % status, status
+```
+
+## Default metrics
+
+The following metrics are exported by default
+(unless the `export_defaults` is set to `False`).
+
+- `flask_http_request_duration_seconds` (Histogram)
+ Labels: `method`, `path` and `status`.
+ Flask HTTP request duration in seconds for all Flask requests.
+- `flask_http_request_total` (Counter)
+ Labels: `method` and `status`.
+ Total number of HTTP requests for all Flask requests.
+- `flask_http_request_exceptions_total` (Counter)
+ Labels: `method` and `status`.
+ Total number of uncaught exceptions when serving Flask requests.
+- `flask_exporter_info` (Gauge)
+ Information about the Prometheus Flask exporter itself (e.g. `version`).
+
+The prefix for the default metrics can be controlled by the `defaults_prefix` parameter.
+If you don't want to use any prefix, pass the `prometheus_flask_exporter.NO_PREFIX` value in.
+The 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.
+
+To register your own *default* metrics that will track all registered
+Flask view functions, use the `register_default` function.
+
+```python
+app = Flask(__name__)
+metrics = PrometheusMetrics(app)
+
+@app.route('/simple')
+def simple_get():
+ pass
+
+metrics.register_default(
+ metrics.counter(
+ 'by_path_counter', 'Request count by request paths',
+ labels={'path': lambda: request.path}
+ )
+)
+```
+
+*Note:* register your default metrics after all routes have been set up.
+Also note, that Gauge metrics registered as default will track the
+`/metrics` endpoint, and this can't be disabled at the moment.
+
+If you want to apply the same metric to multiple (but not all) endpoints,
+create its wrapper first, then add to each function.
+
+```python
+app = Flask(__name__)
+metrics = PrometheusMetrics(app)
+
+by_path_counter = metrics.counter(
+ 'by_path_counter', 'Request count by request paths',
+ labels={'path': lambda: request.path}
+)
+
+@app.route('/simple')
+@by_path_counter
+def simple_get():
+ pass
+
+@app.route('/plain')
+@by_path_counter
+def plain():
+ pass
+
+@app.route('/not/tracked/by/path')
+def not_tracked_by_path():
+ pass
+```
+
+You can avoid recording metrics on individual endpoints
+by decorating them with `@metrics.do_not_track()`, or use the
+`excluded_paths` argument when creating the `PrometheusMetrics` instance
+that takes a regular expression (either a single string, or a list) and
+matching paths will be excluded. These apply to both built-in and user-defined
+default metrics, unless you disable it by setting the `exclude_user_defaults`
+argument to `False`. If you have functions that are inherited or otherwise get
+metrics collected that you don't want, you can use `@metrics.exclude_all_metrics()`
+to exclude both default and non-default metrics being collected from it.
+
+## Configuration
+
+By default, the metrics are exposed on the same Flask application on the
+`/metrics` endpoint and using the core Prometheus registry.
+If this doesn't suit your needs, set the `path` argument to `None` and/or
+the `export_defaults` argument to `False` plus change the `registry`
+argument if needed.
+
+The `group_by` constructor argument controls what
+the default request duration metric is tracked by: endpoint (function)
+instead of URI path (the default). This parameter also accepts a function
+to extract the value from the request, or a name of a property of the request object.
+Examples:
+
+```python
+PrometheusMetrics(app, group_by='path') # the default
+PrometheusMetrics(app, group_by='endpoint') # by endpoint
+PrometheusMetrics(app, group_by='url_rule') # by URL rule
+
+def custom_rule(req): # the Flask request object
+ """ The name of the function becomes the label name. """
+ return '%s::%s' % (req.method, req.path)
+
+PrometheusMetrics(app, group_by=custom_rule) # by a function
+
+# Error: this is not supported:
+PrometheusMetrics(app, group_by=lambda r: r.path)
+```
+
+> The `group_by_endpoint` argument is deprecated since 0.4.0,
+> please use the new `group_by` argument.
+
+The `register_endpoint` allows exposing the metrics endpoint on a specific path.
+It also allows passing in a Flask application to register it on but defaults
+to the main one if not defined.
+
+Similarly, the `start_http_server` allows exposing the endpoint on an
+independent Flask application on a selected HTTP port.
+It also supports overriding the endpoint's path and the HTTP listen address.
+
+You can also set default labels to add to every request managed by
+a `PrometheusMetrics` instance, using the `default_labels` argument.
+This needs to be a dictionary, where each key will become a metric
+label name, and the values the label values.
+These can be constant values, or dynamic functions, see below in the
+[Labels](#Labels) section.
+
+> The `static_labels` argument is deprecated since 0.15.0,
+> please use the new `default_labels` argument.
+
+If you use another framework over Flask (perhaps
+[Connexion](https://connexion.readthedocs.io/)) then you might return
+responses from your endpoints that Flask can't deal with by default.
+If that is the case, you might need to pass in a `response_converter`
+that takes the returned object and should convert that to a Flask
+friendly response.
+See `ConnexionPrometheusMetrics` for an example.
+
+## Labels
+
+When defining labels for metrics on functions,
+the following values are supported in the dictionary:
+
+- A simple static value
+- A no-argument callable
+- A single argument callable that will receive the Flask response
+ as the argument
+
+Label values are evaluated within the request context.
+
+## Initial metric values
+_For more info see: https://github.com/prometheus/client_python#labels_
+
+Metrics without any labels will get an initial value.
+Metrics 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`)
+Metrics that have one or more callable-value labels will not have an initial value.
+
+## Application information
+
+The `PrometheusMetrics.info(..)` method provides a way to expose
+information as a `Gauge` metric, the application version for example.
+
+The metric is returned from the method to allow changing its value
+from the default `1`:
+
+```python
+metrics = PrometheusMetrics(app)
+info = metrics.info('dynamic_info', 'Something dynamic')
+...
+info.set(42.1)
+```
+
+## Examples
+
+See some simple examples visualized on a Grafana dashboard by running
+the demo in the [examples/sample-signals](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples/sample-signals) folder.
+
+![Example dashboard](https://github.com/rycus86/prometheus_flask_exporter/raw/master/examples/sample-signals/dashboard.png)
+
+## App Factory Pattern
+
+This 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.
+
+```python
+metrics = PrometheusMetrics.for_app_factory()
+# then later:
+metrics.init_app(app)
+```
+
+## Securing the metrics endpoint
+
+If you wish to have authentication (or any other special handling) on the metrics endpoint,
+you can use the `metrics_decorator` argument when creating the `PrometheusMetrics` instance.
+For example to integrate with [Flask-HTTPAuth](https://github.com/miguelgrinberg/Flask-HTTPAuth)
+use it like it's shown in the example below.
+
+```python
+app = Flask(__name__)
+auth = HTTPBasicAuth()
+metrics = PrometheusMetrics(app, metrics_decorator=auth.login_required)
+
+# ... other authentication setup like @auth.verify_password below
+```
+
+See a full example in the [examples/flask-httpauth](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples/flask-httpauth) folder.
+
+## Custom metrics endpoint
+
+You can also take full control of the metrics endpoint by generating its contents,
+and managing how it is exposed by yourself.
+
+```python
+app = Flask(__name__)
+# path=None to avoid registering a /metrics endpoint on the same Flask app
+metrics = PrometheusMetrics(app, path=None)
+
+# later ... generate the response (and its content type) to expose to Prometheus
+response_data, content_type = metrics.generate_metrics()
+```
+
+See the related conversation in [issue #135](https://github.com/rycus86/prometheus_flask_exporter/issues/135).
+
+## Debug mode
+
+Please note, that changes being live-reloaded, when running the Flask
+app with `debug=True`, are not going to be reflected in the metrics.
+See [https://github.com/rycus86/prometheus_flask_exporter/issues/4](https://github.com/rycus86/prometheus_flask_exporter/issues/4)
+for more details.
+
+Alternatively - since version `0.5.1` - if you set the `DEBUG_METRICS`
+environment variable, you will get metrics for the latest reloaded code.
+These will be exported on the main Flask app.
+Serving the metrics on a different port is not going to work
+most probably - e.g. `PrometheusMetrics.start_http_server(..)` is not
+expected to work.
+
+## WSGI
+
+Getting accurate metrics for WSGI apps might require a bit more setup.
+See a working sample app in the `examples` folder, and also the
+[prometheus_flask_exporter#5](https://github.com/rycus86/prometheus_flask_exporter/issues/5) issue.
+
+### Multiprocess applications
+
+For multiprocess applications (WSGI or otherwise), you can find some
+helper classes in the `prometheus_flask_exporter.multiprocess` module.
+These provide convenience wrappers for exposing metrics in an
+environment where multiple copies of the application will run on a single host.
+
+```python
+# an extension targeted at Gunicorn deployments
+from prometheus_flask_exporter.multiprocess import GunicornPrometheusMetrics
+
+app = Flask(__name__)
+metrics = GunicornPrometheusMetrics(app)
+
+# then in the Gunicorn config file:
+from prometheus_flask_exporter.multiprocess import GunicornPrometheusMetrics
+
+def when_ready(server):
+ GunicornPrometheusMetrics.start_http_server_when_ready(8080)
+
+def child_exit(server, worker):
+ GunicornPrometheusMetrics.mark_process_dead_on_child_exit(worker.pid)
+```
+
+Also see the `GunicornInternalPrometheusMetrics` class if you want to have
+the metrics HTTP endpoint exposed internally, on the same Flask application.
+
+```python
+# an extension targeted at Gunicorn deployments with an internal metrics endpoint
+from prometheus_flask_exporter.multiprocess import GunicornInternalPrometheusMetrics
+
+app = Flask(__name__)
+metrics = GunicornInternalPrometheusMetrics(app)
+
+# then in the Gunicorn config file:
+from prometheus_flask_exporter.multiprocess import GunicornInternalPrometheusMetrics
+
+def child_exit(server, worker):
+ GunicornInternalPrometheusMetrics.mark_process_dead_on_child_exit(worker.pid)
+```
+
+There's a small wrapper available for [Gunicorn](https://gunicorn.org/) and
+[uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/index.html), for everything
+else you can extend the `prometheus_flask_exporter.multiprocess.MultiprocessPrometheusMetrics` class
+and implement the `should_start_http_server` method at least.
+
+```python
+from prometheus_flask_exporter.multiprocess import MultiprocessPrometheusMetrics
+
+class MyMultiprocessMetrics(MultiprocessPrometheusMetrics):
+ def should_start_http_server(self):
+ return this_worker() == primary_worker()
+```
+
+This should return `True` on one process only, and the underlying
+[Prometheus client library](https://github.com/prometheus/client_python)
+will collect the metrics for all the forked children or siblings.
+
+An additional Flask extension for apps with `processes=N` and `threaded=False` exists
+with the `MultiprocessInternalPrometheusMetrics` class.
+
+```python
+from flask import Flask
+from prometheus_flask_exporter.multiprocess import MultiprocessInternalPrometheusMetrics
+
+app = Flask(__name__)
+metrics = MultiprocessInternalPrometheusMetrics(app)
+
+...
+
+if __name__ == '__main__':
+ app.run('0.0.0.0', 4000, processes=5, threaded=False)
+```
+
+__Note:__ this needs the `PROMETHEUS_MULTIPROC_DIR` environment variable
+to point to a valid, writable directory.
+
+You'll also have to call the `metrics.start_http_server()` function
+explicitly somewhere, and the `should_start_http_server` takes care of
+only starting it once.
+The [examples](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples) folder
+has some working examples on this.
+
+Please also note, that the Prometheus client library does not collect process level
+metrics, like memory, CPU and Python GC stats when multiprocessing is enabled.
+See the [prometheus_flask_exporter#18](https://github.com/rycus86/prometheus_flask_exporter/issues/18)
+issue for some more context and details.
+
+A final caveat is that the metrics HTTP server will listen on __any__ paths
+on the given HTTP port, not only on `/metrics`, and it is not implemented
+at the moment to be able to change this.
+
+### uWSGI lazy-apps
+
+When [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/) is configured
+to run with [lazy-apps]([lazy-apps](https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html#preforking-vs-lazy-apps-vs-lazy)),
+exposing the metrics endpoint on a separate HTTP server (and port) is not functioning yet.
+A workaround is to register the endpoint on the main Flask application.
+
+```python
+app = Flask(__name__)
+metrics = UWsgiPrometheusMetrics(app)
+metrics.register_endpoint('/metrics')
+# instead of metrics.start_http_server(port)
+```
+
+See [#31](https://github.com/rycus86/prometheus_flask_exporter/issues/31)
+for context, and please let me know if you know a better way!
+
+## Connexion integration
+
+The [Connexion](https://connexion.readthedocs.io/) library has some
+support to automatically deal with certain response types, for example
+dataclasses, which a plain Flask application would not accept.
+To ease the integration, you can use `ConnexionPrometheusMetrics` in
+place of `PrometheusMetrics` that has the `response_converter` set
+appropriately to be able to deal with whatever Connexion supports for
+Flask integrations.
+
+```python
+import connexion
+from prometheus_flask_exporter import ConnexionPrometheusMetrics
+
+app = connexion.App(__name__)
+metrics = ConnexionPrometheusMetrics(app)
+```
+
+See a working sample app in the `examples` folder, and also the
+[prometheus_flask_exporter#61](https://github.com/rycus86/prometheus_flask_exporter/issues/61) issue.
+
+There's a caveat about this integration, where any endpoints that
+do not return JSON responses need to be decorated with
+`@metrics.content_type('...')` as this integration would force them
+to be `application/json` otherwise.
+
+```python
+metrics = ConnexionPrometheusMetrics(app)
+
+@metrics.content_type('text/plain')
+def plain_response():
+ return 'plain text'
+```
+
+See the [prometheus_flask_exporter#64](https://github.com/rycus86/prometheus_flask_exporter/issues/64) issue for more details.
+
+## Flask-RESTful integration
+
+The [Flask-RESTful library](https://flask-restful.readthedocs.io/) has
+some custom response handling logic, which can be helpful in some cases.
+For example, returning `None` would fail on plain Flask, but it
+works on Flask-RESTful.
+To ease the integration, you can use `RESTfulPrometheusMetrics` in
+place of `PrometheusMetrics` that sets the `response_converter` to use
+the Flask-RESTful `API` response utilities.
+
+```python
+from flask import Flask
+from flask_restful import Api
+from prometheus_flask_exporter import RESTfulPrometheusMetrics
+
+app = Flask(__name__)
+restful_api = Api(app)
+metrics = RESTfulPrometheusMetrics(app, restful_api)
+```
+
+See a working sample app in the `examples` folder, and also the
+[prometheus_flask_exporter#62](https://github.com/rycus86/prometheus_flask_exporter/issues/62) issue.
+
+## License
+
+MIT
+
+
+%package help
+Summary: Development documents and examples for prometheus-flask-exporter
+Provides: python3-prometheus-flask-exporter-doc
+%description help
+# Prometheus Flask exporter
+
+[![PyPI](https://img.shields.io/pypi/v/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)
+[![PyPI](https://img.shields.io/pypi/pyversions/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)
+[![PyPI - Downloads](https://img.shields.io/pypi/dm/prometheus-flask-exporter.svg)](https://pypi.python.org/pypi/prometheus-flask-exporter)
+[![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)
+[![Code Climate](https://codeclimate.com/github/rycus86/prometheus_flask_exporter/badges/gpa.svg)](https://codeclimate.com/github/rycus86/prometheus_flask_exporter)
+[![Test & 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)
+
+This library provides HTTP request metrics to export into
+[Prometheus](https://prometheus.io/).
+It can also track method invocations using convenient functions.
+
+## Installing
+
+Install using [PIP](https://pip.pypa.io/en/stable/quickstart/):
+
+```bash
+pip install prometheus-flask-exporter
+```
+or paste it into requirements.txt:
+```
+# newest version
+prometheus-flask-exporter
+
+# or with specific version number
+prometheus-flask-exporter==0.22.3
+```
+and then install dependencies from requirements.txt file as usual:
+```
+pip install -r requirements.txt
+```
+
+
+## Usage
+
+```python
+from flask import Flask, request
+from prometheus_flask_exporter import PrometheusMetrics
+
+app = Flask(__name__)
+metrics = PrometheusMetrics(app)
+
+# static information as metric
+metrics.info('app_info', 'Application info', version='1.0.3')
+
+@app.route('/')
+def main():
+ pass # requests tracked by default
+
+@app.route('/skip')
+@metrics.do_not_track()
+def skip():
+ pass # default metrics are not collected
+
+@app.route('/<item_type>')
+@metrics.do_not_track()
+@metrics.counter('invocation_by_type', 'Number of invocations by type',
+ labels={'item_type': lambda: request.view_args['type']})
+def by_type(item_type):
+ pass # only the counter is collected, not the default metrics
+
+@app.route('/long-running')
+@metrics.gauge('in_progress', 'Long running requests in progress')
+def long_running():
+ pass
+
+@app.route('/status/<int:status>')
+@metrics.do_not_track()
+@metrics.summary('requests_by_status', 'Request latencies by status',
+ labels={'status': lambda r: r.status_code})
+@metrics.histogram('requests_by_status_and_path', 'Request latencies by status and path',
+ labels={'status': lambda r: r.status_code, 'path': lambda: request.path})
+def echo_status(status):
+ return 'Status: %s' % status, status
+```
+
+## Default metrics
+
+The following metrics are exported by default
+(unless the `export_defaults` is set to `False`).
+
+- `flask_http_request_duration_seconds` (Histogram)
+ Labels: `method`, `path` and `status`.
+ Flask HTTP request duration in seconds for all Flask requests.
+- `flask_http_request_total` (Counter)
+ Labels: `method` and `status`.
+ Total number of HTTP requests for all Flask requests.
+- `flask_http_request_exceptions_total` (Counter)
+ Labels: `method` and `status`.
+ Total number of uncaught exceptions when serving Flask requests.
+- `flask_exporter_info` (Gauge)
+ Information about the Prometheus Flask exporter itself (e.g. `version`).
+
+The prefix for the default metrics can be controlled by the `defaults_prefix` parameter.
+If you don't want to use any prefix, pass the `prometheus_flask_exporter.NO_PREFIX` value in.
+The 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.
+
+To register your own *default* metrics that will track all registered
+Flask view functions, use the `register_default` function.
+
+```python
+app = Flask(__name__)
+metrics = PrometheusMetrics(app)
+
+@app.route('/simple')
+def simple_get():
+ pass
+
+metrics.register_default(
+ metrics.counter(
+ 'by_path_counter', 'Request count by request paths',
+ labels={'path': lambda: request.path}
+ )
+)
+```
+
+*Note:* register your default metrics after all routes have been set up.
+Also note, that Gauge metrics registered as default will track the
+`/metrics` endpoint, and this can't be disabled at the moment.
+
+If you want to apply the same metric to multiple (but not all) endpoints,
+create its wrapper first, then add to each function.
+
+```python
+app = Flask(__name__)
+metrics = PrometheusMetrics(app)
+
+by_path_counter = metrics.counter(
+ 'by_path_counter', 'Request count by request paths',
+ labels={'path': lambda: request.path}
+)
+
+@app.route('/simple')
+@by_path_counter
+def simple_get():
+ pass
+
+@app.route('/plain')
+@by_path_counter
+def plain():
+ pass
+
+@app.route('/not/tracked/by/path')
+def not_tracked_by_path():
+ pass
+```
+
+You can avoid recording metrics on individual endpoints
+by decorating them with `@metrics.do_not_track()`, or use the
+`excluded_paths` argument when creating the `PrometheusMetrics` instance
+that takes a regular expression (either a single string, or a list) and
+matching paths will be excluded. These apply to both built-in and user-defined
+default metrics, unless you disable it by setting the `exclude_user_defaults`
+argument to `False`. If you have functions that are inherited or otherwise get
+metrics collected that you don't want, you can use `@metrics.exclude_all_metrics()`
+to exclude both default and non-default metrics being collected from it.
+
+## Configuration
+
+By default, the metrics are exposed on the same Flask application on the
+`/metrics` endpoint and using the core Prometheus registry.
+If this doesn't suit your needs, set the `path` argument to `None` and/or
+the `export_defaults` argument to `False` plus change the `registry`
+argument if needed.
+
+The `group_by` constructor argument controls what
+the default request duration metric is tracked by: endpoint (function)
+instead of URI path (the default). This parameter also accepts a function
+to extract the value from the request, or a name of a property of the request object.
+Examples:
+
+```python
+PrometheusMetrics(app, group_by='path') # the default
+PrometheusMetrics(app, group_by='endpoint') # by endpoint
+PrometheusMetrics(app, group_by='url_rule') # by URL rule
+
+def custom_rule(req): # the Flask request object
+ """ The name of the function becomes the label name. """
+ return '%s::%s' % (req.method, req.path)
+
+PrometheusMetrics(app, group_by=custom_rule) # by a function
+
+# Error: this is not supported:
+PrometheusMetrics(app, group_by=lambda r: r.path)
+```
+
+> The `group_by_endpoint` argument is deprecated since 0.4.0,
+> please use the new `group_by` argument.
+
+The `register_endpoint` allows exposing the metrics endpoint on a specific path.
+It also allows passing in a Flask application to register it on but defaults
+to the main one if not defined.
+
+Similarly, the `start_http_server` allows exposing the endpoint on an
+independent Flask application on a selected HTTP port.
+It also supports overriding the endpoint's path and the HTTP listen address.
+
+You can also set default labels to add to every request managed by
+a `PrometheusMetrics` instance, using the `default_labels` argument.
+This needs to be a dictionary, where each key will become a metric
+label name, and the values the label values.
+These can be constant values, or dynamic functions, see below in the
+[Labels](#Labels) section.
+
+> The `static_labels` argument is deprecated since 0.15.0,
+> please use the new `default_labels` argument.
+
+If you use another framework over Flask (perhaps
+[Connexion](https://connexion.readthedocs.io/)) then you might return
+responses from your endpoints that Flask can't deal with by default.
+If that is the case, you might need to pass in a `response_converter`
+that takes the returned object and should convert that to a Flask
+friendly response.
+See `ConnexionPrometheusMetrics` for an example.
+
+## Labels
+
+When defining labels for metrics on functions,
+the following values are supported in the dictionary:
+
+- A simple static value
+- A no-argument callable
+- A single argument callable that will receive the Flask response
+ as the argument
+
+Label values are evaluated within the request context.
+
+## Initial metric values
+_For more info see: https://github.com/prometheus/client_python#labels_
+
+Metrics without any labels will get an initial value.
+Metrics 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`)
+Metrics that have one or more callable-value labels will not have an initial value.
+
+## Application information
+
+The `PrometheusMetrics.info(..)` method provides a way to expose
+information as a `Gauge` metric, the application version for example.
+
+The metric is returned from the method to allow changing its value
+from the default `1`:
+
+```python
+metrics = PrometheusMetrics(app)
+info = metrics.info('dynamic_info', 'Something dynamic')
+...
+info.set(42.1)
+```
+
+## Examples
+
+See some simple examples visualized on a Grafana dashboard by running
+the demo in the [examples/sample-signals](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples/sample-signals) folder.
+
+![Example dashboard](https://github.com/rycus86/prometheus_flask_exporter/raw/master/examples/sample-signals/dashboard.png)
+
+## App Factory Pattern
+
+This 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.
+
+```python
+metrics = PrometheusMetrics.for_app_factory()
+# then later:
+metrics.init_app(app)
+```
+
+## Securing the metrics endpoint
+
+If you wish to have authentication (or any other special handling) on the metrics endpoint,
+you can use the `metrics_decorator` argument when creating the `PrometheusMetrics` instance.
+For example to integrate with [Flask-HTTPAuth](https://github.com/miguelgrinberg/Flask-HTTPAuth)
+use it like it's shown in the example below.
+
+```python
+app = Flask(__name__)
+auth = HTTPBasicAuth()
+metrics = PrometheusMetrics(app, metrics_decorator=auth.login_required)
+
+# ... other authentication setup like @auth.verify_password below
+```
+
+See a full example in the [examples/flask-httpauth](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples/flask-httpauth) folder.
+
+## Custom metrics endpoint
+
+You can also take full control of the metrics endpoint by generating its contents,
+and managing how it is exposed by yourself.
+
+```python
+app = Flask(__name__)
+# path=None to avoid registering a /metrics endpoint on the same Flask app
+metrics = PrometheusMetrics(app, path=None)
+
+# later ... generate the response (and its content type) to expose to Prometheus
+response_data, content_type = metrics.generate_metrics()
+```
+
+See the related conversation in [issue #135](https://github.com/rycus86/prometheus_flask_exporter/issues/135).
+
+## Debug mode
+
+Please note, that changes being live-reloaded, when running the Flask
+app with `debug=True`, are not going to be reflected in the metrics.
+See [https://github.com/rycus86/prometheus_flask_exporter/issues/4](https://github.com/rycus86/prometheus_flask_exporter/issues/4)
+for more details.
+
+Alternatively - since version `0.5.1` - if you set the `DEBUG_METRICS`
+environment variable, you will get metrics for the latest reloaded code.
+These will be exported on the main Flask app.
+Serving the metrics on a different port is not going to work
+most probably - e.g. `PrometheusMetrics.start_http_server(..)` is not
+expected to work.
+
+## WSGI
+
+Getting accurate metrics for WSGI apps might require a bit more setup.
+See a working sample app in the `examples` folder, and also the
+[prometheus_flask_exporter#5](https://github.com/rycus86/prometheus_flask_exporter/issues/5) issue.
+
+### Multiprocess applications
+
+For multiprocess applications (WSGI or otherwise), you can find some
+helper classes in the `prometheus_flask_exporter.multiprocess` module.
+These provide convenience wrappers for exposing metrics in an
+environment where multiple copies of the application will run on a single host.
+
+```python
+# an extension targeted at Gunicorn deployments
+from prometheus_flask_exporter.multiprocess import GunicornPrometheusMetrics
+
+app = Flask(__name__)
+metrics = GunicornPrometheusMetrics(app)
+
+# then in the Gunicorn config file:
+from prometheus_flask_exporter.multiprocess import GunicornPrometheusMetrics
+
+def when_ready(server):
+ GunicornPrometheusMetrics.start_http_server_when_ready(8080)
+
+def child_exit(server, worker):
+ GunicornPrometheusMetrics.mark_process_dead_on_child_exit(worker.pid)
+```
+
+Also see the `GunicornInternalPrometheusMetrics` class if you want to have
+the metrics HTTP endpoint exposed internally, on the same Flask application.
+
+```python
+# an extension targeted at Gunicorn deployments with an internal metrics endpoint
+from prometheus_flask_exporter.multiprocess import GunicornInternalPrometheusMetrics
+
+app = Flask(__name__)
+metrics = GunicornInternalPrometheusMetrics(app)
+
+# then in the Gunicorn config file:
+from prometheus_flask_exporter.multiprocess import GunicornInternalPrometheusMetrics
+
+def child_exit(server, worker):
+ GunicornInternalPrometheusMetrics.mark_process_dead_on_child_exit(worker.pid)
+```
+
+There's a small wrapper available for [Gunicorn](https://gunicorn.org/) and
+[uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/index.html), for everything
+else you can extend the `prometheus_flask_exporter.multiprocess.MultiprocessPrometheusMetrics` class
+and implement the `should_start_http_server` method at least.
+
+```python
+from prometheus_flask_exporter.multiprocess import MultiprocessPrometheusMetrics
+
+class MyMultiprocessMetrics(MultiprocessPrometheusMetrics):
+ def should_start_http_server(self):
+ return this_worker() == primary_worker()
+```
+
+This should return `True` on one process only, and the underlying
+[Prometheus client library](https://github.com/prometheus/client_python)
+will collect the metrics for all the forked children or siblings.
+
+An additional Flask extension for apps with `processes=N` and `threaded=False` exists
+with the `MultiprocessInternalPrometheusMetrics` class.
+
+```python
+from flask import Flask
+from prometheus_flask_exporter.multiprocess import MultiprocessInternalPrometheusMetrics
+
+app = Flask(__name__)
+metrics = MultiprocessInternalPrometheusMetrics(app)
+
+...
+
+if __name__ == '__main__':
+ app.run('0.0.0.0', 4000, processes=5, threaded=False)
+```
+
+__Note:__ this needs the `PROMETHEUS_MULTIPROC_DIR` environment variable
+to point to a valid, writable directory.
+
+You'll also have to call the `metrics.start_http_server()` function
+explicitly somewhere, and the `should_start_http_server` takes care of
+only starting it once.
+The [examples](https://github.com/rycus86/prometheus_flask_exporter/tree/master/examples) folder
+has some working examples on this.
+
+Please also note, that the Prometheus client library does not collect process level
+metrics, like memory, CPU and Python GC stats when multiprocessing is enabled.
+See the [prometheus_flask_exporter#18](https://github.com/rycus86/prometheus_flask_exporter/issues/18)
+issue for some more context and details.
+
+A final caveat is that the metrics HTTP server will listen on __any__ paths
+on the given HTTP port, not only on `/metrics`, and it is not implemented
+at the moment to be able to change this.
+
+### uWSGI lazy-apps
+
+When [uWSGI](https://uwsgi-docs.readthedocs.io/en/latest/) is configured
+to run with [lazy-apps]([lazy-apps](https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html#preforking-vs-lazy-apps-vs-lazy)),
+exposing the metrics endpoint on a separate HTTP server (and port) is not functioning yet.
+A workaround is to register the endpoint on the main Flask application.
+
+```python
+app = Flask(__name__)
+metrics = UWsgiPrometheusMetrics(app)
+metrics.register_endpoint('/metrics')
+# instead of metrics.start_http_server(port)
+```
+
+See [#31](https://github.com/rycus86/prometheus_flask_exporter/issues/31)
+for context, and please let me know if you know a better way!
+
+## Connexion integration
+
+The [Connexion](https://connexion.readthedocs.io/) library has some
+support to automatically deal with certain response types, for example
+dataclasses, which a plain Flask application would not accept.
+To ease the integration, you can use `ConnexionPrometheusMetrics` in
+place of `PrometheusMetrics` that has the `response_converter` set
+appropriately to be able to deal with whatever Connexion supports for
+Flask integrations.
+
+```python
+import connexion
+from prometheus_flask_exporter import ConnexionPrometheusMetrics
+
+app = connexion.App(__name__)
+metrics = ConnexionPrometheusMetrics(app)
+```
+
+See a working sample app in the `examples` folder, and also the
+[prometheus_flask_exporter#61](https://github.com/rycus86/prometheus_flask_exporter/issues/61) issue.
+
+There's a caveat about this integration, where any endpoints that
+do not return JSON responses need to be decorated with
+`@metrics.content_type('...')` as this integration would force them
+to be `application/json` otherwise.
+
+```python
+metrics = ConnexionPrometheusMetrics(app)
+
+@metrics.content_type('text/plain')
+def plain_response():
+ return 'plain text'
+```
+
+See the [prometheus_flask_exporter#64](https://github.com/rycus86/prometheus_flask_exporter/issues/64) issue for more details.
+
+## Flask-RESTful integration
+
+The [Flask-RESTful library](https://flask-restful.readthedocs.io/) has
+some custom response handling logic, which can be helpful in some cases.
+For example, returning `None` would fail on plain Flask, but it
+works on Flask-RESTful.
+To ease the integration, you can use `RESTfulPrometheusMetrics` in
+place of `PrometheusMetrics` that sets the `response_converter` to use
+the Flask-RESTful `API` response utilities.
+
+```python
+from flask import Flask
+from flask_restful import Api
+from prometheus_flask_exporter import RESTfulPrometheusMetrics
+
+app = Flask(__name__)
+restful_api = Api(app)
+metrics = RESTfulPrometheusMetrics(app, restful_api)
+```
+
+See a working sample app in the `examples` folder, and also the
+[prometheus_flask_exporter#62](https://github.com/rycus86/prometheus_flask_exporter/issues/62) issue.
+
+## License
+
+MIT
+
+
+%prep
+%autosetup -n prometheus-flask-exporter-0.22.3
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-prometheus-flask-exporter -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Mon Apr 10 2023 Python_Bot <Python_Bot@openeuler.org> - 0.22.3-1
+- Package Spec generated