Adding metrics for request timings. (#1190)
This commit is contained in:
parent
a9baaf4da4
commit
12622d5847
|
@ -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 import factory
|
||||||
from lemur.extensions import metrics
|
from lemur.extensions import metrics
|
||||||
|
@ -73,17 +74,6 @@ def configure_hook(app):
|
||||||
"""
|
"""
|
||||||
from flask import jsonify
|
from flask import jsonify
|
||||||
from werkzeug.exceptions import HTTPException
|
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)
|
@app.errorhandler(Exception)
|
||||||
def handle_error(e):
|
def handle_error(e):
|
||||||
|
@ -93,3 +83,29 @@ def configure_hook(app):
|
||||||
|
|
||||||
app.logger.exception(e)
|
app.logger.exception(e)
|
||||||
return jsonify(error=str(e)), code
|
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
|
||||||
|
|
|
@ -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
|
|
|
@ -26,3 +26,6 @@ sentry = Sentry()
|
||||||
|
|
||||||
from blinker import Namespace
|
from blinker import Namespace
|
||||||
signals = Namespace()
|
signals = Namespace()
|
||||||
|
|
||||||
|
from flask_cors import CORS
|
||||||
|
cors = CORS()
|
||||||
|
|
|
@ -21,7 +21,7 @@ from flask import Flask
|
||||||
|
|
||||||
from lemur.certificates.hooks import activate_debug_dump
|
from lemur.certificates.hooks import activate_debug_dump
|
||||||
from lemur.common.health import mod as health
|
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 = (
|
DEFAULT_BLUEPRINTS = (
|
||||||
|
@ -124,6 +124,8 @@ def configure_extensions(app):
|
||||||
smtp_mail.init_app(app)
|
smtp_mail.init_app(app)
|
||||||
metrics.init_app(app)
|
metrics.init_app(app)
|
||||||
sentry.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):
|
def configure_blueprints(app, blueprints):
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
asn1crypto==0.24.0 # via cryptography
|
asn1crypto==0.24.0 # via cryptography
|
||||||
attrs==17.4.0 # via pytest
|
attrs==17.4.0 # via pytest
|
||||||
aws-xray-sdk==0.95 # via moto
|
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
|
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
|
certifi==2018.1.18 # via requests
|
||||||
cffi==1.11.5 # via cryptography
|
cffi==1.11.5 # via cryptography
|
||||||
chardet==3.0.4 # via requests
|
chardet==3.0.4 # via requests
|
||||||
|
@ -42,10 +42,10 @@ pyaml==17.12.1 # via moto
|
||||||
pycparser==2.18 # via cffi
|
pycparser==2.18 # via cffi
|
||||||
pyflakes==1.6.0
|
pyflakes==1.6.0
|
||||||
pytest-flask==0.10.0
|
pytest-flask==0.10.0
|
||||||
pytest-mock==1.8.0
|
pytest-mock==1.9.0
|
||||||
pytest==3.5.0
|
pytest==3.5.0
|
||||||
python-dateutil==2.6.1 # via botocore, faker, freezegun, moto
|
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
|
pyyaml==3.12 # via pyaml
|
||||||
requests-mock==1.4.0
|
requests-mock==1.4.0
|
||||||
requests==2.18.4 # via aws-xray-sdk, docker, moto, requests-mock
|
requests==2.18.4 # via aws-xray-sdk, docker, moto, requests-mock
|
||||||
|
|
|
@ -11,6 +11,7 @@ Flask-RESTful==0.3.6
|
||||||
Flask-Script==2.0.6
|
Flask-Script==2.0.6
|
||||||
Flask-SQLAlchemy
|
Flask-SQLAlchemy
|
||||||
Flask==0.12
|
Flask==0.12
|
||||||
|
Flask-Cors
|
||||||
future
|
future
|
||||||
gunicorn
|
gunicorn
|
||||||
inflection
|
inflection
|
||||||
|
|
|
@ -12,13 +12,14 @@ arrow==0.12.1
|
||||||
asn1crypto==0.24.0 # via cryptography
|
asn1crypto==0.24.0 # via cryptography
|
||||||
bcrypt==3.1.4 # via flask-bcrypt, paramiko
|
bcrypt==3.1.4 # via flask-bcrypt, paramiko
|
||||||
blinker==1.4 # via flask-mail, flask-principal, raven
|
blinker==1.4 # via flask-mail, flask-principal, raven
|
||||||
boto3==1.7.2
|
boto3==1.7.3
|
||||||
botocore==1.10.2 # via boto3, s3transfer
|
botocore==1.10.3 # via boto3, s3transfer
|
||||||
cffi==1.11.5 # via bcrypt, cryptography, pynacl
|
cffi==1.11.5 # via bcrypt, cryptography, pynacl
|
||||||
click==6.7 # via flask
|
click==6.7 # via flask
|
||||||
cryptography==2.2.2
|
cryptography==2.2.2
|
||||||
docutils==0.14 # via botocore
|
docutils==0.14 # via botocore
|
||||||
flask-bcrypt==0.7.1
|
flask-bcrypt==0.7.1
|
||||||
|
flask-cors==3.0.3
|
||||||
flask-mail==0.9.1
|
flask-mail==0.9.1
|
||||||
flask-migrate==2.1.1
|
flask-migrate==2.1.1
|
||||||
flask-principal==0.4.0
|
flask-principal==0.4.0
|
||||||
|
@ -55,7 +56,7 @@ pyrfc3339==1.0 # via acme
|
||||||
python-dateutil==2.6.1 # via alembic, arrow, botocore
|
python-dateutil==2.6.1 # via alembic, arrow, botocore
|
||||||
python-editor==1.0.3 # via alembic
|
python-editor==1.0.3 # via alembic
|
||||||
python-ldap==3.0.0
|
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
|
raven[flask]==6.6.0
|
||||||
requests[security]==2.11.1
|
requests[security]==2.11.1
|
||||||
retrying==1.3.3
|
retrying==1.3.3
|
||||||
|
|
Loading…
Reference in New Issue