Wrap API and registry requests with common metric timings
Record response times, codes, and rollup non-2XX responses.
This commit is contained in:
parent
b04c190ca0
commit
b483209862
4 changed files with 48 additions and 4 deletions
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from app import app
|
from app import app, metric_queue
|
||||||
from flask import Blueprint, request, make_response, jsonify, session
|
from flask import Blueprint, request, make_response, jsonify, session
|
||||||
from flask.ext.restful import Resource, abort, Api, reqparse
|
from flask.ext.restful import Resource, abort, Api, reqparse
|
||||||
from flask.ext.restful.utils.cors import crossdomain
|
from flask.ext.restful.utils.cors import crossdomain
|
||||||
|
@ -20,6 +20,7 @@ from auth.auth_context import get_authenticated_user, get_validated_oauth_token
|
||||||
from auth.auth import process_oauth
|
from auth.auth import process_oauth
|
||||||
from endpoints.csrf import csrf_protect
|
from endpoints.csrf import csrf_protect
|
||||||
from endpoints.decorators import check_anon_protection
|
from endpoints.decorators import check_anon_protection
|
||||||
|
from util.saas.metricqueue import time_decorator
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
@ -28,7 +29,7 @@ api = Api()
|
||||||
api.init_app(api_bp)
|
api.init_app(api_bp)
|
||||||
api.decorators = [csrf_protect,
|
api.decorators = [csrf_protect,
|
||||||
crossdomain(origin='*', headers=['Authorization', 'Content-Type']),
|
crossdomain(origin='*', headers=['Authorization', 'Content-Type']),
|
||||||
process_oauth]
|
process_oauth, time_decorator(api_bp.name, metric_queue)]
|
||||||
|
|
||||||
|
|
||||||
class ApiException(Exception):
|
class ApiException(Exception):
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
from flask import Blueprint, make_response
|
from flask import Blueprint, make_response
|
||||||
|
|
||||||
|
from app import metric_queue
|
||||||
from endpoints.decorators import anon_protect, anon_allowed
|
from endpoints.decorators import anon_protect, anon_allowed
|
||||||
|
from util.saas.metricqueue import time_blueprint
|
||||||
|
|
||||||
|
|
||||||
v1_bp = Blueprint('v1', __name__)
|
v1_bp = Blueprint('v1', __name__)
|
||||||
|
|
||||||
|
time_blueprint(v1_bp, metric_queue)
|
||||||
|
|
||||||
# Note: This is *not* part of the Docker index spec. This is here for our own health check,
|
# Note: This is *not* part of the Docker index spec. This is here for our own health check,
|
||||||
# since we have nginx handle the _ping below.
|
# since we have nginx handle the _ping below.
|
||||||
|
|
|
@ -7,6 +7,7 @@ from flask import Blueprint, make_response, url_for, request
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
|
|
||||||
|
from app import metric_queue
|
||||||
from endpoints.decorators import anon_protect, anon_allowed
|
from endpoints.decorators import anon_protect, anon_allowed
|
||||||
from auth.jwt_auth import process_jwt_auth
|
from auth.jwt_auth import process_jwt_auth
|
||||||
from auth.auth_context import get_grant_user_context
|
from auth.auth_context import get_grant_user_context
|
||||||
|
@ -14,12 +15,13 @@ from auth.permissions import (ReadRepositoryPermission, ModifyRepositoryPermissi
|
||||||
AdministerRepositoryPermission)
|
AdministerRepositoryPermission)
|
||||||
from data import model
|
from data import model
|
||||||
from util.http import abort
|
from util.http import abort
|
||||||
|
from util.saas.metricqueue import time_blueprint
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
v2_bp = Blueprint('v2', __name__)
|
v2_bp = Blueprint('v2', __name__)
|
||||||
|
|
||||||
|
time_blueprint(v2_bp, metric_queue)
|
||||||
|
|
||||||
def _require_repo_permission(permission_class, allow_public=False):
|
def _require_repo_permission(permission_class, allow_public=False):
|
||||||
def wrapper(func):
|
def wrapper(func):
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
import logging
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
from functools import wraps
|
||||||
from Queue import Queue, Full
|
from Queue import Queue, Full
|
||||||
|
|
||||||
|
from flask import g, request
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -16,4 +20,38 @@ class MetricQueue(object):
|
||||||
logger.error('Metric queue full')
|
logger.error('Metric queue full')
|
||||||
|
|
||||||
def get(self):
|
def get(self):
|
||||||
return self._queue.get()
|
v = self._queue.get()
|
||||||
|
return v
|
||||||
|
|
||||||
|
def time_blueprint(bp, metric_queue):
|
||||||
|
bp.before_request(time_before_request)
|
||||||
|
bp.after_request(time_after_request(bp.name, metric_queue))
|
||||||
|
|
||||||
|
def time_before_request():
|
||||||
|
g._start = time.time()
|
||||||
|
|
||||||
|
def time_after_request(name, metric_queue):
|
||||||
|
def f(r):
|
||||||
|
start = getattr(g, '_start', None)
|
||||||
|
if start is None:
|
||||||
|
return r
|
||||||
|
dur = time.time() - start
|
||||||
|
dims = dimensions={'endpoint': request.endpoint}
|
||||||
|
metric_queue.put('ResponseTime', dur, dimensions=dims, unit='Seconds')
|
||||||
|
metric_queue.put('ResponseCode', r.status_code, dimensions=dims)
|
||||||
|
if r.status_code < 200 or r.status_code >= 300:
|
||||||
|
metric_queue.put('Non200Response', 1, dimensions={'name': name})
|
||||||
|
return r
|
||||||
|
return f
|
||||||
|
|
||||||
|
def time_decorator(name, metric_queue):
|
||||||
|
after = time_after_request(name, metric_queue)
|
||||||
|
def decorator(func):
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
time_before_request()
|
||||||
|
rv = func(*args, **kwargs)
|
||||||
|
after(rv)
|
||||||
|
return rv
|
||||||
|
return wrapper
|
||||||
|
return decorator
|
||||||
|
|
Reference in a new issue