For observability purpose in the tornado OpenTelemetry instrumentation we would like to get a templated path that led to an handler, e.g. with the following code:
class StoryHandler(RequestHandler):
def get(self, story_id):
self.write("this is story %s" % story_id)
app = Application([
url(r"/story/([0-9]+)", StoryHandler, name="story")
])
We would like to being able to build something like /story/<story_id> starting from an handler instance, but let's ignore the regexp pattern to name problem and just think on how to get the rule. ATM I've drafted the following code:
from __future__ import annotations
from typing import Any
from tornado.routing import Router
from tornado.web import RequestHandler
from tornado import httputil
# Distinguishes "keep scanning sibling rules" from "matched a branch we can't
# inspect further, so stop and report no reliable result".
_NOT_FOUND = object()
def find_matched_rule(handler: RequestHandler):
result = _find_rule(
handler.application.default_router,
handler.request,
handler.__class__,
)
return None if result is _NOT_FOUND else result
def _find_rule(router: Any, request: httputil.HTTPServerRequest, handler_class: type[RequestHandler]):
rules = getattr(router, "rules", None)
if rules is None:
# Opaque custom router; cannot inspect reliably.
return _NOT_FOUND
for rule in rules:
params = rule.matcher.match(request)
if params is None:
continue
target = getattr(rule, "target", None)
if _is_handler_target(target):
if target is handler_class:
return rule
# A different handler matched first, so Tornado would stop here too.
return _NOT_FOUND
if hasattr(target, "rules"):
nested = _find_rule(target, request, handler_class)
if nested is None:
# Nested router did not resolve anything; keep scanning siblings.
continue
return nested
if isinstance(target, Router):
# Custom nested router matched, but we cannot see inside it.
return _NOT_FOUND
# Callable / connection delegate / other terminal target.
return _NOT_FOUND
return None
def _is_handler_target(target: Any) -> bool:
return isinstance(target, type) and issubclass(target, RequestHandler)
So wondering if we're missing something or maybe we can get some help from tornado itself like a reference to the matched url in the handler. Thanks!
For observability purpose in the tornado OpenTelemetry instrumentation we would like to get a templated path that led to an handler, e.g. with the following code:
We would like to being able to build something like
/story/<story_id>starting from an handler instance, but let's ignore the regexp pattern to name problem and just think on how to get the rule. ATM I've drafted the following code:So wondering if we're missing something or maybe we can get some help from tornado itself like a reference to the matched url in the handler. Thanks!