监控和日志记录

为了更好地监控应用程序的性能并及时排查问题,蝙蝠侠希望拥有一份规范的访问日志——每个请求一行,记录请求方法、路径、状态码以及耗时。

Robyn 构建在 Python 标准的 logging 模块之上,因此你可以用两个中间件来组装请求/访问日志:一个 before_request 钩子用于启动计时器,一个 after_request 钩子在响应就绪后输出日志行。after_request 钩子可以同时接收 requestresponse,这正是你同时记录路径与状态码所需要的。而且由于 Robyn 在 before_request、处理器和 after_request 钩子之间共享 contextvars 上下文,使用 ContextVar 来存放开始时间会非常整洁。

请求 / 访问日志

import logging
import time
from contextvars import ContextVar

from robyn import Request, Response

# 专用于访问日志的 logger。它会继承 Robyn 的日志配置,
# 因此请将级别保持在 INFO 或更低(使用 `--log-level WARN` 运行会隐藏这些日志)。
logging.basicConfig(level=logging.INFO)
access_logger = logging.getLogger("robyn.access")

_request_start: ContextVar[float] = ContextVar("request_start")


@app.before_request()
def start_timer(request: Request):
    _request_start.set(time.perf_counter())
    return request


@app.after_request()
def log_request(request: Request, response: Response):
    start = _request_start.get(None)
    duration_ms = (time.perf_counter() - start) * 1000 if start is not None else 0.0
    access_logger.info(
        "%s %s -> %s (%.2fms)",
        request.method,
        request.url.path,
        response.status_code,
        duration_ms,
    )
    return response

将这两个钩子注册为全局钩子后,每个请求都会产生如下一行日志:

INFO:robyn.access:GET /crimes -> 200 (1.83ms)

几点值得注意:

  • 双参数的 after_request(request, response) 签名让你能在拿到响应的同时访问请求。如果你只需要响应,单参数的 after_request(response) 同样可用——Robyn 会根据你的函数参数自动选择调用方式。
  • 即使某个 before_request 钩子提前返回了响应,after_request 钩子也始终会运行,因此你的访问日志能覆盖每一个响应。
  • 优先使用 %s 风格的日志参数(如上所示),而不是 f-string,这样只有在日志级别真正启用时才会进行字符串格式化。

借助监控和日志记录功能,蝙蝠侠现在能够轻松检测应用程序中的问题,分析其性能表现,确保系统始终保持最佳状态,随时准备协助他打击犯罪。