From e180b11a96bba59a46c9d8fff33d620085c0004b Mon Sep 17 00:00:00 2001 From: Viktor Adam Date: Wed, 4 Dec 2019 21:46:46 +1100 Subject: [PATCH] Introduce exclude_all_metrics and restore do_not_track behavior to only exclude defaults --- README.md | 5 ++++- prometheus_flask_exporter/__init__.py | 22 +++++++++++++++++--- setup.py | 4 ++-- tests/test_defaults.py | 29 +++++++++++++++++++++++++-- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d4e4a69..512a919 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,10 @@ 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. +matching paths will be excluded. 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 diff --git a/prometheus_flask_exporter/__init__.py b/prometheus_flask_exporter/__init__.py index 2f5a093..6e4f0d5 100644 --- a/prometheus_flask_exporter/__init__.py +++ b/prometheus_flask_exporter/__init__.py @@ -324,7 +324,7 @@ def before_request(): request.prom_start_time = default_timer() def after_request(response): - if hasattr(request, 'prom_do_not_track'): + if hasattr(request, 'prom_do_not_track') or hasattr(request, 'prom_exclude_all'): return response if self.excluded_paths: @@ -541,7 +541,7 @@ def func(*args, **kwargs): exception = ex response = make_response('Exception: %s' % ex, 500) - if hasattr(request, 'prom_do_not_track'): + if hasattr(request, 'prom_exclude_all'): if metric and revert_when_not_tracked: # special handling for Gauge metrics revert_when_not_tracked(metric) @@ -606,6 +606,22 @@ def func(*args, **kwargs): return decorator + @staticmethod + def exclude_all_metrics(): + """ + Decorator to skip all metrics collection for the method. + """ + + def decorator(f): + @wraps(f) + def func(*args, **kwargs): + request.prom_exclude_all = True + return f(*args, **kwargs) + + return func + + return decorator + def info(self, name, description, labelnames=None, labelvalues=None, **labels): """ Report any information as a Prometheus metric. @@ -669,4 +685,4 @@ def _is_string(value): return isinstance(value, str) # python3 -__version__ = '0.11.0' +__version__ = '0.12.0' diff --git a/setup.py b/setup.py index bcae112..42d4589 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name='prometheus_flask_exporter', packages=['prometheus_flask_exporter'], - version='0.11.0', + version='0.12.0', description='Prometheus metrics exporter for Flask', long_description=long_description, long_description_content_type='text/markdown', @@ -14,7 +14,7 @@ author='Viktor Adam', author_email='rycus86@gmail.com', url='https://github.com/rycus86/prometheus_flask_exporter', - download_url='https://github.com/rycus86/prometheus_flask_exporter/archive/0.11.0.tar.gz', + download_url='https://github.com/rycus86/prometheus_flask_exporter/archive/0.12.0.tar.gz', keywords=['prometheus', 'flask', 'monitoring', 'exporter'], classifiers=[ 'Development Status :: 4 - Beta', diff --git a/tests/test_defaults.py b/tests/test_defaults.py index 43d5081..f600402 100644 --- a/tests/test_defaults.py +++ b/tests/test_defaults.py @@ -109,13 +109,38 @@ def test(): ('method', 'GET'), ('path', '/skip'), ('status', 200) ) - def test_do_not_track_wrapping(self): + def test_do_not_track_only_excludes_defaults(self): + metrics = self.metrics() + + @self.app.route('/skip/defaults') + @metrics.counter('cnt_before', 'Counter before') + @metrics.do_not_track() + @metrics.counter('cnt_after', 'Counter after') + def test(): + return 'OK' + + self.client.get('/skip/defaults') + self.client.get('/skip/defaults') + + self.assertAbsent( + 'flask_http_request_total', + ('method', 'GET'), ('status', 200) + ) + self.assertAbsent( + 'flask_http_request_duration_seconds_count', + ('method', 'GET'), ('path', '/skip/defaults'), ('status', 200) + ) + + self.assertMetric('cnt_before_total', 2.0) + self.assertMetric('cnt_after_total', 2.0) + + def test_exclude_all_wrapping(self): metrics = self.metrics() @self.app.route('/skip') @metrics.gauge('gauge_before', 'Gauge before') @metrics.counter('cnt_before', 'Counter before') - @metrics.do_not_track() + @metrics.exclude_all_metrics() @metrics.counter('cnt_after', 'Counter after') @metrics.gauge('gauge_after', 'Gauge after') def test():