Adding metrics for request timings. (#1190)

This commit is contained in:
kevgliss 2018-04-10 15:55:02 -07:00 committed by GitHub
parent a9baaf4da4
commit 12622d5847
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 43 additions and 76 deletions

View File

@ -8,7 +8,8 @@
"""
from __future__ import absolute_import, division, print_function
import time
from flask import g, request
from lemur import factory
from lemur.extensions import metrics
@ -73,17 +74,6 @@ def configure_hook(app):
"""
from flask import jsonify
from werkzeug.exceptions import HTTPException
from lemur.decorators import crossdomain
if app.config.get('CORS'):
@app.after_request
@crossdomain(origin=u"http://localhost:3000", methods=['PUT', 'HEAD', 'GET', 'POST', 'OPTIONS', 'DELETE'])
def after(response):
return response
@app.after_request
def log_status(response):
metrics.send('status_code_{}'.format(response.status_code), 'counter', 1)
return response
@app.errorhandler(Exception)
def handle_error(e):
@ -93,3 +83,29 @@ def configure_hook(app):
app.logger.exception(e)
return jsonify(error=str(e)), code
@app.before_request
def before_request():
g.request_start_time = time.time()
@app.after_request
def after_request(response):
# Return early if we don't have the start time
if not hasattr(g, 'request_start_time'):
return response
# Get elapsed time in milliseconds
elapsed = time.time() - g.request_start_time
elapsed = int(round(1000 * elapsed))
# Collect request/response tags
tags = {
'endpoint': request.endpoint,
'request_method': request.method.lower(),
'status_code': response.status_code
}
# Record our response time metric
metrics.send('response_time', 'TIMER', elapsed, metric_tags=tags)
metrics.send('status_code_{}'.format(response.status_code), 'counter', 1)
return response

View File

@ -1,56 +0,0 @@
"""
.. module: lemur.decorators
:copyright: (c) 2015 by Netflix Inc., see AUTHORS for more
:license: Apache, see LICENSE for more details.
"""
from builtins import str
from datetime import timedelta
from flask import make_response, request, current_app
from functools import update_wrapper
# this is only used for dev
def crossdomain(origin=None, methods=None, headers=None,
max_age=21600, attach_to_all=True,
automatic_options=True): # pragma: no cover
if methods is not None:
methods = ', '.join(sorted(x.upper() for x in methods))
if headers is not None and not isinstance(headers, str):
headers = ', '.join(x.upper() for x in headers)
if not isinstance(origin, str):
origin = ', '.join(origin)
if isinstance(max_age, timedelta):
max_age = max_age.total_seconds()
def get_methods():
if methods is not None:
return methods
options_resp = current_app.make_default_options_response()
return options_resp.headers['allow']
def decorator(f):
def wrapped_function(*args, **kwargs):
if automatic_options and request.method == 'OPTIONS':
resp = current_app.make_default_options_response()
else:
resp = make_response(f(*args, **kwargs))
if not attach_to_all and request.method != 'OPTIONS':
return resp
h = resp.headers
h['Access-Control-Allow-Origin'] = origin
h['Access-Control-Allow-Methods'] = get_methods()
h['Access-Control-Max-Age'] = str(max_age)
h['Access-Control-Allow-Headers'] = "Origin, X-Requested-With, Content-Type, Accept, Authorization "
h['Access-Control-Allow-Credentials'] = 'true'
return resp
f.provide_automatic_options = False
return update_wrapper(wrapped_function, f)
return decorator

View File

@ -26,3 +26,6 @@ sentry = Sentry()
from blinker import Namespace
signals = Namespace()
from flask_cors import CORS
cors = CORS()

View File

@ -21,7 +21,7 @@ from flask import Flask
from lemur.certificates.hooks import activate_debug_dump
from lemur.common.health import mod as health
from lemur.extensions import db, migrate, principal, smtp_mail, metrics, sentry
from lemur.extensions import db, migrate, principal, smtp_mail, metrics, sentry, cors
DEFAULT_BLUEPRINTS = (
@ -124,6 +124,8 @@ def configure_extensions(app):
smtp_mail.init_app(app)
metrics.init_app(app)
sentry.init_app(app)
app.config['CORS_HEADERS'] = 'Content-Type'
cors.init_app(app, resources=r'/api/*', headers='Content-Type', origin='*', supports_credentials=True)
def configure_blueprints(app, blueprints):

View File

@ -7,9 +7,9 @@
asn1crypto==0.24.0 # via cryptography
attrs==17.4.0 # via pytest
aws-xray-sdk==0.95 # via moto
boto3==1.7.2 # via moto
boto3==1.7.3 # via moto
boto==2.48.0 # via moto
botocore==1.10.2 # via boto3, moto, s3transfer
botocore==1.10.3 # via boto3, moto, s3transfer
certifi==2018.1.18 # via requests
cffi==1.11.5 # via cryptography
chardet==3.0.4 # via requests
@ -42,10 +42,10 @@ pyaml==17.12.1 # via moto
pycparser==2.18 # via cffi
pyflakes==1.6.0
pytest-flask==0.10.0
pytest-mock==1.8.0
pytest-mock==1.9.0
pytest==3.5.0
python-dateutil==2.6.1 # via botocore, faker, freezegun, moto
pytz==2018.3 # via moto
pytz==2018.4 # via moto
pyyaml==3.12 # via pyaml
requests-mock==1.4.0
requests==2.18.4 # via aws-xray-sdk, docker, moto, requests-mock

View File

@ -11,6 +11,7 @@ Flask-RESTful==0.3.6
Flask-Script==2.0.6
Flask-SQLAlchemy
Flask==0.12
Flask-Cors
future
gunicorn
inflection

View File

@ -12,13 +12,14 @@ arrow==0.12.1
asn1crypto==0.24.0 # via cryptography
bcrypt==3.1.4 # via flask-bcrypt, paramiko
blinker==1.4 # via flask-mail, flask-principal, raven
boto3==1.7.2
botocore==1.10.2 # via boto3, s3transfer
boto3==1.7.3
botocore==1.10.3 # via boto3, s3transfer
cffi==1.11.5 # via bcrypt, cryptography, pynacl
click==6.7 # via flask
cryptography==2.2.2
docutils==0.14 # via botocore
flask-bcrypt==0.7.1
flask-cors==3.0.3
flask-mail==0.9.1
flask-migrate==2.1.1
flask-principal==0.4.0
@ -55,7 +56,7 @@ pyrfc3339==1.0 # via acme
python-dateutil==2.6.1 # via alembic, arrow, botocore
python-editor==1.0.3 # via alembic
python-ldap==3.0.0
pytz==2018.3 # via acme, flask-restful, pyrfc3339
pytz==2018.4 # via acme, flask-restful, pyrfc3339
raven[flask]==6.6.0
requests[security]==2.11.1
retrying==1.3.3