Merge pull request #756 from matrix-org/markjh/more_metrics
Report per request metrics for all of the things using request_handler
This commit is contained in:
commit
1c188cf73c
|
@ -74,7 +74,12 @@ response_db_txn_duration = metrics.register_distribution(
|
||||||
_next_request_id = 0
|
_next_request_id = 0
|
||||||
|
|
||||||
|
|
||||||
def request_handler(request_handler):
|
def request_handler(report_metrics=True):
|
||||||
|
"""Decorator for ``wrap_request_handler``"""
|
||||||
|
return lambda request_handler: wrap_request_handler(request_handler, report_metrics)
|
||||||
|
|
||||||
|
|
||||||
|
def wrap_request_handler(request_handler, report_metrics):
|
||||||
"""Wraps a method that acts as a request handler with the necessary logging
|
"""Wraps a method that acts as a request handler with the necessary logging
|
||||||
and exception handling.
|
and exception handling.
|
||||||
|
|
||||||
|
@ -96,6 +101,10 @@ def request_handler(request_handler):
|
||||||
global _next_request_id
|
global _next_request_id
|
||||||
request_id = "%s-%s" % (request.method, _next_request_id)
|
request_id = "%s-%s" % (request.method, _next_request_id)
|
||||||
_next_request_id += 1
|
_next_request_id += 1
|
||||||
|
if report_metrics:
|
||||||
|
request_metrics = RequestMetrics()
|
||||||
|
request_metrics.start(self.clock)
|
||||||
|
|
||||||
with LoggingContext(request_id) as request_context:
|
with LoggingContext(request_id) as request_context:
|
||||||
request_context.request = request_id
|
request_context.request = request_id
|
||||||
with request.processing():
|
with request.processing():
|
||||||
|
@ -133,6 +142,14 @@ def request_handler(request_handler):
|
||||||
},
|
},
|
||||||
send_cors=True
|
send_cors=True
|
||||||
)
|
)
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
if report_metrics:
|
||||||
|
request_metrics.stop(
|
||||||
|
self.clock, request, self.__class__.__name__
|
||||||
|
)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
return wrapped_request_handler
|
return wrapped_request_handler
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,19 +214,23 @@ class JsonResource(HttpServer, resource.Resource):
|
||||||
self._async_render(request)
|
self._async_render(request)
|
||||||
return server.NOT_DONE_YET
|
return server.NOT_DONE_YET
|
||||||
|
|
||||||
@request_handler
|
# Disable metric reporting because _async_render does its own metrics.
|
||||||
|
# It does its own metric reporting because _async_render dispatches to
|
||||||
|
# a callback and it's the class name of that callback we want to report
|
||||||
|
# against rather than the JsonResource itself.
|
||||||
|
@request_handler(report_metrics=False)
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _async_render(self, request):
|
def _async_render(self, request):
|
||||||
""" This gets called from render() every time someone sends us a request.
|
""" This gets called from render() every time someone sends us a request.
|
||||||
This checks if anyone has registered a callback for that method and
|
This checks if anyone has registered a callback for that method and
|
||||||
path.
|
path.
|
||||||
"""
|
"""
|
||||||
start = self.clock.time_msec()
|
|
||||||
if request.method == "OPTIONS":
|
if request.method == "OPTIONS":
|
||||||
self._send_response(request, 200, {})
|
self._send_response(request, 200, {})
|
||||||
return
|
return
|
||||||
|
|
||||||
start_context = LoggingContext.current_context()
|
request_metrics = RequestMetrics()
|
||||||
|
request_metrics.start(self.clock)
|
||||||
|
|
||||||
# Loop through all the registered callbacks to check if the method
|
# Loop through all the registered callbacks to check if the method
|
||||||
# and path regex match
|
# and path regex match
|
||||||
|
@ -241,40 +262,7 @@ class JsonResource(HttpServer, resource.Resource):
|
||||||
self._send_response(request, code, response)
|
self._send_response(request, code, response)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
context = LoggingContext.current_context()
|
request_metrics.stop(self.clock, request, servlet_classname)
|
||||||
|
|
||||||
tag = ""
|
|
||||||
if context:
|
|
||||||
tag = context.tag
|
|
||||||
|
|
||||||
if context != start_context:
|
|
||||||
logger.warn(
|
|
||||||
"Context have unexpectedly changed %r, %r",
|
|
||||||
context, self.start_context
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
incoming_requests_counter.inc(request.method, servlet_classname, tag)
|
|
||||||
|
|
||||||
response_timer.inc_by(
|
|
||||||
self.clock.time_msec() - start, request.method,
|
|
||||||
servlet_classname, tag
|
|
||||||
)
|
|
||||||
|
|
||||||
ru_utime, ru_stime = context.get_resource_usage()
|
|
||||||
|
|
||||||
response_ru_utime.inc_by(
|
|
||||||
ru_utime, request.method, servlet_classname, tag
|
|
||||||
)
|
|
||||||
response_ru_stime.inc_by(
|
|
||||||
ru_stime, request.method, servlet_classname, tag
|
|
||||||
)
|
|
||||||
response_db_txn_count.inc_by(
|
|
||||||
context.db_txn_count, request.method, servlet_classname, tag
|
|
||||||
)
|
|
||||||
response_db_txn_duration.inc_by(
|
|
||||||
context.db_txn_duration, request.method, servlet_classname, tag
|
|
||||||
)
|
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -307,6 +295,48 @@ class JsonResource(HttpServer, resource.Resource):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class RequestMetrics(object):
|
||||||
|
def start(self, clock):
|
||||||
|
self.start = clock.time_msec()
|
||||||
|
self.start_context = LoggingContext.current_context()
|
||||||
|
|
||||||
|
def stop(self, clock, request, servlet_classname):
|
||||||
|
context = LoggingContext.current_context()
|
||||||
|
|
||||||
|
tag = ""
|
||||||
|
if context:
|
||||||
|
tag = context.tag
|
||||||
|
|
||||||
|
if context != start_context:
|
||||||
|
logger.warn(
|
||||||
|
"Context have unexpectedly changed %r, %r",
|
||||||
|
context, self.start_context
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
incoming_requests_counter.inc(request.method, servlet_classname, tag)
|
||||||
|
|
||||||
|
response_timer.inc_by(
|
||||||
|
self.clock.time_msec() - start, request.method,
|
||||||
|
servlet_classname, tag
|
||||||
|
)
|
||||||
|
|
||||||
|
ru_utime, ru_stime = context.get_resource_usage()
|
||||||
|
|
||||||
|
response_ru_utime.inc_by(
|
||||||
|
ru_utime, request.method, servlet_classname, tag
|
||||||
|
)
|
||||||
|
response_ru_stime.inc_by(
|
||||||
|
ru_stime, request.method, servlet_classname, tag
|
||||||
|
)
|
||||||
|
response_db_txn_count.inc_by(
|
||||||
|
context.db_txn_count, request.method, servlet_classname, tag
|
||||||
|
)
|
||||||
|
response_db_txn_duration.inc_by(
|
||||||
|
context.db_txn_duration, request.method, servlet_classname, tag
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RootRedirect(resource.Resource):
|
class RootRedirect(resource.Resource):
|
||||||
"""Redirects the root '/' path to another path."""
|
"""Redirects the root '/' path to another path."""
|
||||||
|
|
||||||
|
|
|
@ -31,12 +31,13 @@ class PusherResource(Resource):
|
||||||
self.version_string = hs.version_string
|
self.version_string = hs.version_string
|
||||||
self.store = hs.get_datastore()
|
self.store = hs.get_datastore()
|
||||||
self.notifier = hs.get_notifier()
|
self.notifier = hs.get_notifier()
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
|
||||||
def render_POST(self, request):
|
def render_POST(self, request):
|
||||||
self._async_render_POST(request)
|
self._async_render_POST(request)
|
||||||
return NOT_DONE_YET
|
return NOT_DONE_YET
|
||||||
|
|
||||||
@request_handler
|
@request_handler()
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _async_render_POST(self, request):
|
def _async_render_POST(self, request):
|
||||||
content = parse_json_object_from_request(request)
|
content = parse_json_object_from_request(request)
|
||||||
|
|
|
@ -112,6 +112,7 @@ class ReplicationResource(Resource):
|
||||||
self.presence_handler = hs.get_handlers().presence_handler
|
self.presence_handler = hs.get_handlers().presence_handler
|
||||||
self.typing_handler = hs.get_handlers().typing_notification_handler
|
self.typing_handler = hs.get_handlers().typing_notification_handler
|
||||||
self.notifier = hs.notifier
|
self.notifier = hs.notifier
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
|
||||||
self.putChild("remove_pushers", PusherResource(hs))
|
self.putChild("remove_pushers", PusherResource(hs))
|
||||||
|
|
||||||
|
@ -139,7 +140,7 @@ class ReplicationResource(Resource):
|
||||||
state_token,
|
state_token,
|
||||||
))
|
))
|
||||||
|
|
||||||
@request_handler
|
@request_handler()
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _async_render_GET(self, request):
|
def _async_render_GET(self, request):
|
||||||
limit = parse_integer(request, "limit", 100)
|
limit = parse_integer(request, "limit", 100)
|
||||||
|
|
|
@ -49,7 +49,6 @@ class LocalKey(Resource):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, hs):
|
def __init__(self, hs):
|
||||||
self.hs = hs
|
|
||||||
self.version_string = hs.version_string
|
self.version_string = hs.version_string
|
||||||
self.response_body = encode_canonical_json(
|
self.response_body = encode_canonical_json(
|
||||||
self.response_json_object(hs.config)
|
self.response_json_object(hs.config)
|
||||||
|
|
|
@ -97,7 +97,7 @@ class RemoteKey(Resource):
|
||||||
self.async_render_GET(request)
|
self.async_render_GET(request)
|
||||||
return NOT_DONE_YET
|
return NOT_DONE_YET
|
||||||
|
|
||||||
@request_handler
|
@request_handler()
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def async_render_GET(self, request):
|
def async_render_GET(self, request):
|
||||||
if len(request.postpath) == 1:
|
if len(request.postpath) == 1:
|
||||||
|
@ -122,7 +122,7 @@ class RemoteKey(Resource):
|
||||||
self.async_render_POST(request)
|
self.async_render_POST(request)
|
||||||
return NOT_DONE_YET
|
return NOT_DONE_YET
|
||||||
|
|
||||||
@request_handler
|
@request_handler()
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def async_render_POST(self, request):
|
def async_render_POST(self, request):
|
||||||
content = parse_json_object_from_request(request)
|
content = parse_json_object_from_request(request)
|
||||||
|
|
|
@ -36,12 +36,13 @@ class DownloadResource(Resource):
|
||||||
self.server_name = hs.hostname
|
self.server_name = hs.hostname
|
||||||
self.store = hs.get_datastore()
|
self.store = hs.get_datastore()
|
||||||
self.version_string = hs.version_string
|
self.version_string = hs.version_string
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
|
||||||
def render_GET(self, request):
|
def render_GET(self, request):
|
||||||
self._async_render_GET(request)
|
self._async_render_GET(request)
|
||||||
return NOT_DONE_YET
|
return NOT_DONE_YET
|
||||||
|
|
||||||
@request_handler
|
@request_handler()
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _async_render_GET(self, request):
|
def _async_render_GET(self, request):
|
||||||
server_name, media_id, name = parse_media_id(request)
|
server_name, media_id, name = parse_media_id(request)
|
||||||
|
|
|
@ -74,7 +74,7 @@ class PreviewUrlResource(Resource):
|
||||||
self._async_render_GET(request)
|
self._async_render_GET(request)
|
||||||
return NOT_DONE_YET
|
return NOT_DONE_YET
|
||||||
|
|
||||||
@request_handler
|
@request_handler()
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _async_render_GET(self, request):
|
def _async_render_GET(self, request):
|
||||||
|
|
||||||
|
|
|
@ -39,12 +39,13 @@ class ThumbnailResource(Resource):
|
||||||
self.dynamic_thumbnails = hs.config.dynamic_thumbnails
|
self.dynamic_thumbnails = hs.config.dynamic_thumbnails
|
||||||
self.server_name = hs.hostname
|
self.server_name = hs.hostname
|
||||||
self.version_string = hs.version_string
|
self.version_string = hs.version_string
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
|
||||||
def render_GET(self, request):
|
def render_GET(self, request):
|
||||||
self._async_render_GET(request)
|
self._async_render_GET(request)
|
||||||
return NOT_DONE_YET
|
return NOT_DONE_YET
|
||||||
|
|
||||||
@request_handler
|
@request_handler()
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _async_render_GET(self, request):
|
def _async_render_GET(self, request):
|
||||||
server_name, media_id, _ = parse_media_id(request)
|
server_name, media_id, _ = parse_media_id(request)
|
||||||
|
|
|
@ -41,6 +41,7 @@ class UploadResource(Resource):
|
||||||
self.auth = hs.get_auth()
|
self.auth = hs.get_auth()
|
||||||
self.max_upload_size = hs.config.max_upload_size
|
self.max_upload_size = hs.config.max_upload_size
|
||||||
self.version_string = hs.version_string
|
self.version_string = hs.version_string
|
||||||
|
self.clock = hs.get_clock()
|
||||||
|
|
||||||
def render_POST(self, request):
|
def render_POST(self, request):
|
||||||
self._async_render_POST(request)
|
self._async_render_POST(request)
|
||||||
|
@ -50,7 +51,7 @@ class UploadResource(Resource):
|
||||||
respond_with_json(request, 200, {}, send_cors=True)
|
respond_with_json(request, 200, {}, send_cors=True)
|
||||||
return NOT_DONE_YET
|
return NOT_DONE_YET
|
||||||
|
|
||||||
@request_handler
|
@request_handler()
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _async_render_POST(self, request):
|
def _async_render_POST(self, request):
|
||||||
requester = yield self.auth.get_user_by_req(request)
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
|
Loading…
Reference in New Issue