Skip to content

Commit

Permalink
Fix servlet metric names (matrix-org#5734)
Browse files Browse the repository at this point in the history
* Fix servlet metric names

Co-Authored-By: Richard van der Hoff <[email protected]>

* Remove redundant check

* Cover all return paths
  • Loading branch information
JorikSchellekens authored Jul 24, 2019
1 parent 8b0d5b1 commit cf2972c
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 31 deletions.
1 change: 1 addition & 0 deletions changelog.d/5734.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix a regression introduced in v1.2.0rc1 which led to incorrect labels on some prometheus metrics.
4 changes: 3 additions & 1 deletion synapse/federation/transport/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,9 @@ def register(self, server):
if code is None:
continue

server.register_paths(method, (pattern,), self._wrap(code))
server.register_paths(
method, (pattern,), self._wrap(code), self.__class__.__name__
)


class FederationSendServlet(BaseFederationServlet):
Expand Down
41 changes: 28 additions & 13 deletions synapse/http/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,9 @@ class JsonResource(HttpServer, resource.Resource):

isLeaf = True

_PathEntry = collections.namedtuple("_PathEntry", ["pattern", "callback"])
_PathEntry = collections.namedtuple(
"_PathEntry", ["pattern", "callback", "servlet_classname"]
)

def __init__(self, hs, canonical_json=True):
resource.Resource.__init__(self)
Expand All @@ -255,12 +257,28 @@ def __init__(self, hs, canonical_json=True):
self.path_regexs = {}
self.hs = hs

def register_paths(self, method, path_patterns, callback):
def register_paths(self, method, path_patterns, callback, servlet_classname):
"""
Registers a request handler against a regular expression. Later request URLs are
checked against these regular expressions in order to identify an appropriate
handler for that request.
Args:
method (str): GET, POST etc
path_patterns (Iterable[str]): A list of regular expressions to which
the request URLs are compared.
callback (function): The handler for the request. Usually a Servlet
servlet_classname (str): The name of the handler to be used in prometheus
and opentracing logs.
"""
method = method.encode("utf-8") # method is bytes on py3
for path_pattern in path_patterns:
logger.debug("Registering for %s %s", method, path_pattern.pattern)
self.path_regexs.setdefault(method, []).append(
self._PathEntry(path_pattern, callback)
self._PathEntry(path_pattern, callback, servlet_classname)
)

def render(self, request):
Expand All @@ -275,13 +293,9 @@ async def _async_render(self, request):
This checks if anyone has registered a callback for that method and
path.
"""
callback, group_dict = self._get_handler_for_request(request)
callback, servlet_classname, group_dict = self._get_handler_for_request(request)

servlet_instance = getattr(callback, "__self__", None)
if servlet_instance is not None:
servlet_classname = servlet_instance.__class__.__name__
else:
servlet_classname = "%r" % callback
# Make sure we have a name for this handler in prometheus.
request.request_metrics.name = servlet_classname

# Now trigger the callback. If it returns a response, we send it
Expand Down Expand Up @@ -311,7 +325,8 @@ def _get_handler_for_request(self, request):
request (twisted.web.http.Request):
Returns:
Tuple[Callable, dict[unicode, unicode]]: callback method, and the
Tuple[Callable, str, dict[unicode, unicode]]: callback method, the
label to use for that method in prometheus metrics, and the
dict mapping keys to path components as specified in the
handler's path match regexp.
Expand All @@ -320,18 +335,18 @@ def _get_handler_for_request(self, request):
None, or a tuple of (http code, response body).
"""
if request.method == b"OPTIONS":
return _options_handler, {}
return _options_handler, "options_request_handler", {}

# Loop through all the registered callbacks to check if the method
# and path regex match
for path_entry in self.path_regexs.get(request.method, []):
m = path_entry.pattern.match(request.path.decode("ascii"))
if m:
# We found a match!
return path_entry.callback, m.groupdict()
return path_entry.callback, path_entry.servlet_classname, m.groupdict()

# Huh. No one wanted to handle that? Fiiiiiine. Send 400.
return _unrecognised_request_handler, {}
return _unrecognised_request_handler, "unrecognised_request_handler", {}

def _send_response(
self, request, code, response_json_object, response_code_message=None
Expand Down
4 changes: 3 additions & 1 deletion synapse/http/servlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,13 @@ def register(self, http_server):

for method in ("GET", "PUT", "POST", "OPTIONS", "DELETE"):
if hasattr(self, "on_%s" % (method,)):
servlet_classname = self.__class__.__name__
method_handler = getattr(self, "on_%s" % (method,))
http_server.register_paths(
method,
patterns,
trace_servlet(self.__class__.__name__, method_handler),
trace_servlet(servlet_classname, method_handler),
servlet_classname,
)

else:
Expand Down
2 changes: 1 addition & 1 deletion synapse/replication/http/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def register(self, http_server):
args = "/".join("(?P<%s>[^/]+)" % (arg,) for arg in url_args)
pattern = re.compile("^/_synapse/replication/%s/%s$" % (self.NAME, args))

http_server.register_paths(method, [pattern], handler)
http_server.register_paths(method, [pattern], handler, self.__class__.__name__)

def _cached_handler(self, request, txn_id, **kwargs):
"""Called on new incoming requests when caching is enabled. Checks
Expand Down
9 changes: 7 additions & 2 deletions synapse/rest/admin/server_notice_servlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,14 @@ def __init__(self, hs):

def register(self, json_resource):
PATTERN = "^/_synapse/admin/v1/send_server_notice"
json_resource.register_paths("POST", (re.compile(PATTERN + "$"),), self.on_POST)
json_resource.register_paths(
"PUT", (re.compile(PATTERN + "/(?P<txn_id>[^/]*)$"),), self.on_PUT
"POST", (re.compile(PATTERN + "$"),), self.on_POST, self.__class__.__name__
)
json_resource.register_paths(
"PUT",
(re.compile(PATTERN + "/(?P<txn_id>[^/]*)$"),),
self.on_PUT,
self.__class__.__name__,
)

@defer.inlineCallbacks
Expand Down
37 changes: 30 additions & 7 deletions synapse/rest/client/v1/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,17 @@ def register(self, http_server):
register_txn_path(self, PATTERNS, http_server)
# define CORS for all of /rooms in RoomCreateRestServlet for simplicity
http_server.register_paths(
"OPTIONS", client_patterns("/rooms(?:/.*)?$", v1=True), self.on_OPTIONS
"OPTIONS",
client_patterns("/rooms(?:/.*)?$", v1=True),
self.on_OPTIONS,
self.__class__.__name__,
)
# define CORS for /createRoom[/txnid]
http_server.register_paths(
"OPTIONS", client_patterns("/createRoom(?:/.*)?$", v1=True), self.on_OPTIONS
"OPTIONS",
client_patterns("/createRoom(?:/.*)?$", v1=True),
self.on_OPTIONS,
self.__class__.__name__,
)

def on_PUT(self, request, txn_id):
Expand Down Expand Up @@ -116,16 +122,28 @@ def register(self, http_server):
)

http_server.register_paths(
"GET", client_patterns(state_key, v1=True), self.on_GET
"GET",
client_patterns(state_key, v1=True),
self.on_GET,
self.__class__.__name__,
)
http_server.register_paths(
"PUT", client_patterns(state_key, v1=True), self.on_PUT
"PUT",
client_patterns(state_key, v1=True),
self.on_PUT,
self.__class__.__name__,
)
http_server.register_paths(
"GET", client_patterns(no_state_key, v1=True), self.on_GET_no_state_key
"GET",
client_patterns(no_state_key, v1=True),
self.on_GET_no_state_key,
self.__class__.__name__,
)
http_server.register_paths(
"PUT", client_patterns(no_state_key, v1=True), self.on_PUT_no_state_key
"PUT",
client_patterns(no_state_key, v1=True),
self.on_PUT_no_state_key,
self.__class__.__name__,
)

def on_GET_no_state_key(self, request, room_id, event_type):
Expand Down Expand Up @@ -845,18 +863,23 @@ def register_txn_path(servlet, regex_string, http_server, with_get=False):
with_get: True to also register respective GET paths for the PUTs.
"""
http_server.register_paths(
"POST", client_patterns(regex_string + "$", v1=True), servlet.on_POST
"POST",
client_patterns(regex_string + "$", v1=True),
servlet.on_POST,
servlet.__class__.__name__,
)
http_server.register_paths(
"PUT",
client_patterns(regex_string + "/(?P<txn_id>[^/]*)$", v1=True),
servlet.on_PUT,
servlet.__class__.__name__,
)
if with_get:
http_server.register_paths(
"GET",
client_patterns(regex_string + "/(?P<txn_id>[^/]*)$", v1=True),
servlet.on_GET,
servlet.__class__.__name__,
)


Expand Down
2 changes: 2 additions & 0 deletions synapse/rest/client/v2_alpha/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ def register(self, http_server):
"POST",
client_patterns(self.PATTERN + "$", releases=()),
self.on_PUT_or_POST,
self.__class__.__name__,
)
http_server.register_paths(
"PUT",
client_patterns(self.PATTERN + "/(?P<txn_id>[^/]*)$", releases=()),
self.on_PUT,
self.__class__.__name__,
)

def on_PUT(self, request, *args, **kwargs):
Expand Down
21 changes: 16 additions & 5 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,10 @@ def _callback(request, **kwargs):

res = JsonResource(self.homeserver)
res.register_paths(
"GET", [re.compile("^/_matrix/foo/(?P<room_id>[^/]*)$")], _callback
"GET",
[re.compile("^/_matrix/foo/(?P<room_id>[^/]*)$")],
_callback,
"test_servlet",
)

request, channel = make_request(
Expand All @@ -82,7 +85,9 @@ def _callback(request, **kwargs):
raise Exception("boo")

res = JsonResource(self.homeserver)
res.register_paths("GET", [re.compile("^/_matrix/foo$")], _callback)
res.register_paths(
"GET", [re.compile("^/_matrix/foo$")], _callback, "test_servlet"
)

request, channel = make_request(self.reactor, b"GET", b"/_matrix/foo")
render(request, res, self.reactor)
Expand All @@ -105,7 +110,9 @@ def _callback(request, **kwargs):
return make_deferred_yieldable(d)

res = JsonResource(self.homeserver)
res.register_paths("GET", [re.compile("^/_matrix/foo$")], _callback)
res.register_paths(
"GET", [re.compile("^/_matrix/foo$")], _callback, "test_servlet"
)

request, channel = make_request(self.reactor, b"GET", b"/_matrix/foo")
render(request, res, self.reactor)
Expand All @@ -122,7 +129,9 @@ def _callback(request, **kwargs):
raise SynapseError(403, "Forbidden!!one!", Codes.FORBIDDEN)

res = JsonResource(self.homeserver)
res.register_paths("GET", [re.compile("^/_matrix/foo$")], _callback)
res.register_paths(
"GET", [re.compile("^/_matrix/foo$")], _callback, "test_servlet"
)

request, channel = make_request(self.reactor, b"GET", b"/_matrix/foo")
render(request, res, self.reactor)
Expand All @@ -143,7 +152,9 @@ def _callback(request, **kwargs):
self.fail("shouldn't ever get here")

res = JsonResource(self.homeserver)
res.register_paths("GET", [re.compile("^/_matrix/foo$")], _callback)
res.register_paths(
"GET", [re.compile("^/_matrix/foo$")], _callback, "test_servlet"
)

request, channel = make_request(self.reactor, b"GET", b"/_matrix/foobar")
render(request, res, self.reactor)
Expand Down
2 changes: 1 addition & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,7 @@ def trigger(

raise KeyError("No event can handle %s" % path)

def register_paths(self, method, path_patterns, callback):
def register_paths(self, method, path_patterns, callback, servlet_name):
for path_pattern in path_patterns:
self.callbacks.append((method, path_pattern, callback))

Expand Down

0 comments on commit cf2972c

Please sign in to comment.