-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #223 from release-engineering/prometheus-metrics
Add metrics for request latency and count
- Loading branch information
Showing
5 changed files
with
114 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# SPDX-License-Identifier: GPL-3.0+ | ||
|
||
from __future__ import unicode_literals | ||
|
||
import time | ||
|
||
from flask import Response, Blueprint, request | ||
import prometheus_client | ||
|
||
|
||
REQUEST_COUNT = prometheus_client.Counter( | ||
'request_count', 'App Request Count', | ||
['app_name', 'method', 'endpoint', 'query_string', 'http_status']) | ||
|
||
REQUEST_LATENCY = prometheus_client.Histogram( | ||
'request_latency_seconds', 'Request latency', | ||
['app_name', 'endpoint', 'query_string']) | ||
|
||
|
||
def start_request_timer(): | ||
"""Start the request timer.""" | ||
request.start_time = time.time() | ||
|
||
|
||
def stop_request_timer(response): | ||
""" | ||
Stop the request timer. | ||
:param flask.Response response: the Flask response to stop the timer on | ||
:return: the Flask response | ||
:rtype: flask.Response | ||
""" | ||
resp_time = time.time() - request.start_time | ||
REQUEST_LATENCY.labels( | ||
'estuary-api', request.path, request.query_string.decode('utf-8')).observe(resp_time) | ||
return response | ||
|
||
|
||
def record_request_metadata(response): | ||
""" | ||
Record metadata about the request. | ||
:param flask.Response response: the Flask response to record metadata about | ||
:return: the Flask response | ||
:rtype: flask.Response | ||
""" | ||
REQUEST_COUNT.labels( | ||
'estuary-api', request.method, request.path, request.query_string, | ||
response.status_code).inc() | ||
return response | ||
|
||
|
||
def configure_monitoring(app): | ||
"""Configure monitoring on the Flask app. | ||
:param flask.Flask app: the Flask application to configure | ||
""" | ||
app.before_request(start_request_timer) | ||
app.after_request(stop_request_timer) | ||
app.after_request(record_request_metadata) | ||
|
||
|
||
monitoring_api = Blueprint('monitoring', __name__) | ||
|
||
|
||
@monitoring_api.route('/metrics') | ||
def metrics(): | ||
""" | ||
Display Prometheus metrics about the app. | ||
:rtype: flask.Response | ||
""" | ||
return Response( | ||
prometheus_client.generate_latest(), | ||
content_type=prometheus_client.CONTENT_TYPE_LATEST) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# SPDX-License-Identifier: GPL-3.0+ | ||
|
||
from __future__ import unicode_literals | ||
|
||
|
||
def test_monitoring(client): | ||
"""Test the Prometheus metrics endpoint is working.""" | ||
# First request something even if it doesn't exist to generate a metric | ||
client.get('/api/v1/story/containeradvisory/123123123?fallback=advisory') | ||
# Then check the metrics | ||
rv = client.get('/monitoring/metrics') | ||
assert rv.status_code == 200 | ||
rv_data = rv.data.decode('utf-8') | ||
for le in ('0.005', '0.01', '0.025', '0.05', '0.075', '0.1', '0.25', '0.5', '0.75', '1.0', | ||
'2.5', '5.0', '7.5', '10.0', '+Inf'): | ||
expected = ( | ||
'request_latency_seconds_bucket{{app_name="estuary-api",endpoint="/api/v1/story/' | ||
'containeradvisory/123123123",le="{}",query_string="fallback=advisory"}}'.format(le)) | ||
assert expected in rv_data | ||
expected = ('request_latency_seconds_count{app_name="estuary-api",endpoint="/api/v1/story/' | ||
'containeradvisory/123123123",query_string="fallback=advisory"}') | ||
assert expected in rv_data | ||
expected = ('request_latency_seconds_sum{app_name="estuary-api",endpoint="/api/v1/story/' | ||
'containeradvisory/123123123",query_string="fallback=advisory"}') | ||
assert expected in rv_data |