diff --git a/synapse/http/server.py b/synapse/http/server.py
index b82196fd5e..29241fa145 100644
--- a/synapse/http/server.py
+++ b/synapse/http/server.py
@@ -74,7 +74,12 @@ response_db_txn_duration = metrics.register_distribution(
_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
and exception handling.
@@ -96,6 +101,10 @@ def request_handler(request_handler):
global _next_request_id
request_id = "%s-%s" % (request.method, _next_request_id)
_next_request_id += 1
+ if report_metrics:
+ request_metrics = RequestMetrics()
+ request_metrics.start(self.clock)
+
with LoggingContext(request_id) as request_context:
request_context.request = request_id
with request.processing():
@@ -133,6 +142,14 @@ def request_handler(request_handler):
},
send_cors=True
)
+ finally:
+ try:
+ if report_metrics:
+ request_metrics.stop(
+ self.clock, request, self.__class__.__name__
+ )
+ except:
+ pass
return wrapped_request_handler
@@ -197,19 +214,23 @@ class JsonResource(HttpServer, resource.Resource):
self._async_render(request)
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
def _async_render(self, 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
path.
"""
- start = self.clock.time_msec()
if request.method == "OPTIONS":
self._send_response(request, 200, {})
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
# and path regex match
@@ -241,40 +262,7 @@ class JsonResource(HttpServer, resource.Resource):
self._send_response(request, code, response)
try:
- 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
- )
+ request_metrics.stop(self.clock, request, servlet_classname)
except:
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):
"""Redirects the root '/' path to another path."""
diff --git a/synapse/replication/pusher_resource.py b/synapse/replication/pusher_resource.py
index b87026d79a..9b01ab3c13 100644
--- a/synapse/replication/pusher_resource.py
+++ b/synapse/replication/pusher_resource.py
@@ -31,12 +31,13 @@ class PusherResource(Resource):
self.version_string = hs.version_string
self.store = hs.get_datastore()
self.notifier = hs.get_notifier()
+ self.clock = hs.get_clock()
def render_POST(self, request):
self._async_render_POST(request)
return NOT_DONE_YET
- @request_handler
+ @request_handler()
@defer.inlineCallbacks
def _async_render_POST(self, request):
content = parse_json_object_from_request(request)
diff --git a/synapse/replication/resource.py b/synapse/replication/resource.py
index 149fc4c650..ff78c60f13 100644
--- a/synapse/replication/resource.py
+++ b/synapse/replication/resource.py
@@ -112,6 +112,7 @@ class ReplicationResource(Resource):
self.presence_handler = hs.get_handlers().presence_handler
self.typing_handler = hs.get_handlers().typing_notification_handler
self.notifier = hs.notifier
+ self.clock = hs.get_clock()
self.putChild("remove_pushers", PusherResource(hs))
@@ -139,7 +140,7 @@ class ReplicationResource(Resource):
state_token,
))
- @request_handler
+ @request_handler()
@defer.inlineCallbacks
def _async_render_GET(self, request):
limit = parse_integer(request, "limit", 100)
diff --git a/synapse/rest/key/v1/server_key_resource.py b/synapse/rest/key/v1/server_key_resource.py
index 3db3838b7e..bd4fea5774 100644
--- a/synapse/rest/key/v1/server_key_resource.py
+++ b/synapse/rest/key/v1/server_key_resource.py
@@ -49,7 +49,6 @@ class LocalKey(Resource):
"""
def __init__(self, hs):
- self.hs = hs
self.version_string = hs.version_string
self.response_body = encode_canonical_json(
self.response_json_object(hs.config)
diff --git a/synapse/rest/key/v2/remote_key_resource.py b/synapse/rest/key/v2/remote_key_resource.py
index 9552016fec..7209d5a37d 100644
--- a/synapse/rest/key/v2/remote_key_resource.py
+++ b/synapse/rest/key/v2/remote_key_resource.py
@@ -97,7 +97,7 @@ class RemoteKey(Resource):
self.async_render_GET(request)
return NOT_DONE_YET
- @request_handler
+ @request_handler()
@defer.inlineCallbacks
def async_render_GET(self, request):
if len(request.postpath) == 1:
@@ -122,7 +122,7 @@ class RemoteKey(Resource):
self.async_render_POST(request)
return NOT_DONE_YET
- @request_handler
+ @request_handler()
@defer.inlineCallbacks
def async_render_POST(self, request):
content = parse_json_object_from_request(request)
diff --git a/synapse/rest/media/v1/download_resource.py b/synapse/rest/media/v1/download_resource.py
index 510884262c..9f69620772 100644
--- a/synapse/rest/media/v1/download_resource.py
+++ b/synapse/rest/media/v1/download_resource.py
@@ -36,12 +36,13 @@ class DownloadResource(Resource):
self.server_name = hs.hostname
self.store = hs.get_datastore()
self.version_string = hs.version_string
+ self.clock = hs.get_clock()
def render_GET(self, request):
self._async_render_GET(request)
return NOT_DONE_YET
- @request_handler
+ @request_handler()
@defer.inlineCallbacks
def _async_render_GET(self, request):
server_name, media_id, name = parse_media_id(request)
diff --git a/synapse/rest/media/v1/preview_url_resource.py b/synapse/rest/media/v1/preview_url_resource.py
index 69327ac493..dc1e5fbdb3 100644
--- a/synapse/rest/media/v1/preview_url_resource.py
+++ b/synapse/rest/media/v1/preview_url_resource.py
@@ -74,7 +74,7 @@ class PreviewUrlResource(Resource):
self._async_render_GET(request)
return NOT_DONE_YET
- @request_handler
+ @request_handler()
@defer.inlineCallbacks
def _async_render_GET(self, request):
diff --git a/synapse/rest/media/v1/thumbnail_resource.py b/synapse/rest/media/v1/thumbnail_resource.py
index 234dd4261c..0b9e1de1a7 100644
--- a/synapse/rest/media/v1/thumbnail_resource.py
+++ b/synapse/rest/media/v1/thumbnail_resource.py
@@ -39,12 +39,13 @@ class ThumbnailResource(Resource):
self.dynamic_thumbnails = hs.config.dynamic_thumbnails
self.server_name = hs.hostname
self.version_string = hs.version_string
+ self.clock = hs.get_clock()
def render_GET(self, request):
self._async_render_GET(request)
return NOT_DONE_YET
- @request_handler
+ @request_handler()
@defer.inlineCallbacks
def _async_render_GET(self, request):
server_name, media_id, _ = parse_media_id(request)
diff --git a/synapse/rest/media/v1/upload_resource.py b/synapse/rest/media/v1/upload_resource.py
index 299e1f6e56..b716d1d892 100644
--- a/synapse/rest/media/v1/upload_resource.py
+++ b/synapse/rest/media/v1/upload_resource.py
@@ -41,6 +41,7 @@ class UploadResource(Resource):
self.auth = hs.get_auth()
self.max_upload_size = hs.config.max_upload_size
self.version_string = hs.version_string
+ self.clock = hs.get_clock()
def render_POST(self, request):
self._async_render_POST(request)
@@ -50,7 +51,7 @@ class UploadResource(Resource):
respond_with_json(request, 200, {}, send_cors=True)
return NOT_DONE_YET
- @request_handler
+ @request_handler()
@defer.inlineCallbacks
def _async_render_POST(self, request):
requester = yield self.auth.get_user_by_req(request)
|