From 58ab99d74bc386b30c57a8616fb9e4749a448b36 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Mon, 15 Jun 2020 16:19:00 +0100 Subject: [PATCH] add more prometheus metrics Two new metrics: auth_db_connection_duration_seconds (histogram) wraps the first DB call of post notifications. This includes waiting to get a connection from the pool, and also making the actual request to the db to retrieve the service and api keys. (i'm not sure there's an easy way to separate these two things) post_notification_json_parse_duration_seconds wraps parsing the v2 post notifications json parsing and schema validation. Shouldn't include any async code --- app/authentication/auth.py | 9 +++++++- app/v2/notifications/post_notifications.py | 26 ++++++++++++++-------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/app/authentication/auth.py b/app/authentication/auth.py index 02ae025bf..1b7a286ac 100644 --- a/app/authentication/auth.py +++ b/app/authentication/auth.py @@ -6,12 +6,18 @@ from notifications_python_client.errors import ( from notifications_utils import request_helper from sqlalchemy.exc import DataError from sqlalchemy.orm.exc import NoResultFound +from gds_metrics import Histogram from app.dao.services_dao import dao_fetch_service_by_id_with_api_keys GENERAL_TOKEN_ERROR_MESSAGE = 'Invalid token: make sure your API token matches the example at https://docs.notifications.service.gov.uk/rest-api.html#authorisation-header' # noqa +AUTH_DB_CONNECTION_DURATION_SECONDS = Histogram( + 'auth_db_connection_duration_seconds', + 'Time taken to get DB connection and fetch service from database', +) + class AuthError(Exception): def __init__(self, message, code, service_id=None, api_key_id=None): @@ -87,7 +93,8 @@ def requires_auth(): issuer = __get_token_issuer(auth_token) # ie the `iss` claim which should be a service ID try: - service = dao_fetch_service_by_id_with_api_keys(issuer) + with AUTH_DB_CONNECTION_DURATION_SECONDS.time(): + service = dao_fetch_service_by_id_with_api_keys(issuer) except DataError: raise AuthError("Invalid token: service id is not the right data type", 403) except NoResultFound: diff --git a/app/v2/notifications/post_notifications.py b/app/v2/notifications/post_notifications.py index ed7db67e5..25bb10582 100644 --- a/app/v2/notifications/post_notifications.py +++ b/app/v2/notifications/post_notifications.py @@ -7,6 +7,7 @@ from boto.exception import SQSError from flask import request, jsonify, current_app, abort from notifications_utils.postal_address import PostalAddress from notifications_utils.recipients import try_validate_and_format_phone_number +from gds_metrics import Histogram from app import ( api_user, @@ -74,6 +75,12 @@ from app.v2.notifications.notification_schemas import ( from app.v2.utils import get_valid_json +POST_NOTIFICATION_JSON_PARSE_DURATION_SECONDS = Histogram( + 'post_notification_json_parse_duration_seconds', + 'Time taken to parse and validate post request json', +) + + @v2_notification_blueprint.route('/{}'.format(LETTER_TYPE), methods=['POST']) def post_precompiled_letter_notification(): request_json = get_valid_json() @@ -116,16 +123,17 @@ def post_precompiled_letter_notification(): @v2_notification_blueprint.route('/', methods=['POST']) def post_notification(notification_type): - request_json = get_valid_json() + with POST_NOTIFICATION_JSON_PARSE_DURATION_SECONDS.time(): + request_json = get_valid_json() - if notification_type == EMAIL_TYPE: - form = validate(request_json, post_email_request) - elif notification_type == SMS_TYPE: - form = validate(request_json, post_sms_request) - elif notification_type == LETTER_TYPE: - form = validate(request_json, post_letter_request) - else: - abort(404) + if notification_type == EMAIL_TYPE: + form = validate(request_json, post_email_request) + elif notification_type == SMS_TYPE: + form = validate(request_json, post_sms_request) + elif notification_type == LETTER_TYPE: + form = validate(request_json, post_letter_request) + else: + abort(404) check_service_has_permission(notification_type, authenticated_service.permissions)