Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Fix servlet metric names #5734

Merged
merged 10 commits into from
Jul 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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):
JorikSchellekens marked this conversation as resolved.
Show resolved Hide resolved
"""
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()
JorikSchellekens marked this conversation as resolved.
Show resolved Hide resolved

# 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