Repository: rycus86/prometheus_flask_exporter

Issue:
Metrics per view function name instead of URL path?
A new set of metrics for each path makes for a very noisy export, in our case. There could be literally thousands of paths.

Would it be possible to support tracking by the name of the function handling the request, rather than the path? Similar to what [django-prometheus](https://github.com/korfuri/django-prometheus) does.

So that the code:

``` python3
metrics = prometheus_flask_exporter.PrometheusMetrics(app)

@route('/<page_name>')
def process_page(page_name):
    # ...
```

Instead of outputting:

```
flask_http_request_duration_seconds_bucket{le="0.005",method="GET",path="/page1",status="200"} 0.0
flask_http_request_duration_seconds_bucket{le="+Inf",method="GET",path="/page1",status="200"} 1.0
...
flask_http_request_duration_seconds_bucket{le="0.005",method="GET",path="/page2",status="200"} 0.0
flask_http_request_duration_seconds_bucket{le="+Inf",method="GET",path="/page2",status="200"} 1.0
```

Would output:

```
flask_http_request_duration_seconds_bucket{le="0.005",method="GET",function="process_page",status="200"} 0.0
flask_http_request_duration_seconds_bucket{le="+Inf",method="GET",function="process_page",status="200"} 2.0
```


Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/15710711/badge)](https://coveralls.io/builds/15710711)

Coverage remained the same at 100.0% when pulling **f887e22fe5c9aed9da558d290b6cf42f6eec51b1 on nottrobin:group-by-endpoint** into **9e3c9a64250b8f8c3d900b48970c21107048fe47 on rycus86:master**.

nottrobin: Added test for the new `group_by_endpoint` option.

Patch:
diff --git a/prometheus_flask_exporter/__init__.py b/prometheus_flask_exporter/__init__.py
index cc1498b..365a63b 100644
--- a/prometheus_flask_exporter/__init__.py
+++ b/prometheus_flask_exporter/__init__.py
@@ -64,7 +64,7 @@ class PrometheusMetrics(object):
     """
 
     def __init__(self, app, path='/metrics', export_defaults=True,
-                 buckets=None, registry=DEFAULT_REGISTRY):
+                 buckets=None, registry=DEFAULT_REGISTRY, group_by_endpoint=False):
         """
         Create a new Prometheus metrics export configuration.
 
@@ -78,6 +78,7 @@ class PrometheusMetrics(object):
         """
 
         self.app = app
+        self.group_by = 'endpoint' if group_by_endpoint else 'path'
         self.registry = registry
         self.version = __version__
 
@@ -149,7 +150,7 @@ class PrometheusMetrics(object):
         histogram = Histogram(
             'flask_http_request_duration_seconds',
             'Flask HTTP request duration in seconds',
-            ('method', 'path', 'status'),
+            ('method', self.group_by, 'status'),
             registry=self.registry,
             **buckets_as_kwargs
         )
@@ -175,10 +176,12 @@ class PrometheusMetrics(object):
                 return response
 
             total_time = max(default_timer() - request.prom_start_time, 0)
+
             histogram.labels(
-                request.method, request.path, response.status_code
+                request.method,
+                getattr(request, self.group_by),
+                response.status_code
             ).observe(total_time)
-
             counter.labels(request.method, response.status_code).inc()
 
             return response


Test patch:
diff --git a/tests/test_defaults.py b/tests/test_defaults.py
index be6aec2..203a497 100644
--- a/tests/test_defaults.py
+++ b/tests/test_defaults.py
@@ -148,6 +148,34 @@ class DefaultsTest(BaseTestCase):
             endpoint='/metrics'
         )
 
+    def test_group_by_endpoint(self):
+        self.metrics(group_by_endpoint=True)
+
+        @self.app.route('/<url>')
+        def a_test_endpoint(url):
+            return url + ' is OK'
+
+        self.client.get('/test')
+        self.client.get('/test2')
+        self.client.get('/test3')
+
+        self.assertMetric(
+            'flask_http_request_duration_seconds_bucket', '3.0',
+            ('endpoint', 'a_test_endpoint'), ('status', 200),
+            ('le', '+Inf'),('method', 'GET'),
+            endpoint='/metrics'
+        )
+        self.assertMetric(
+            'flask_http_request_duration_seconds_count', '3.0',
+            ('endpoint', 'a_test_endpoint'), ('status', 200), ('method', 'GET'),
+            endpoint='/metrics'
+        )
+        self.assertAbsent(
+            'flask_http_request_duration_seconds_bucket',
+            ('path', '/test'),
+            endpoint='/metrics'
+        )
+
     def test_non_automatic_endpoint_registration(self):
         metrics = self.metrics(path=None)