【发布时间】:2019-11-19 10:11:31
【问题描述】:
我有一个 Python Flask 应用程序。有一个运行状况检查经常命中一个端点 (/),我不想在日志中看到它。如何仅对一个 GET 端点禁用日志记录,而将其保留为其他所有端点?
【问题讨论】:
-
如果您还解释了如何结合 gunicorn 执行此操作,则将获得奖励
我有一个 Python Flask 应用程序。有一个运行状况检查经常命中一个端点 (/),我不想在日志中看到它。如何仅对一个 GET 端点禁用日志记录,而将其保留为其他所有端点?
【问题讨论】:
我建议您实现一个专用的日志过滤器。将该过滤器插入内部 werkzeug 记录器。
您还可以在https://github.com/pallets/werkzeug/blob/71cf9902012338f8ee98338fa7bba50572606637/src/werkzeug/serving.py#L378 研究子类化WSGI 请求处理程序log_request 方法
【讨论】:
Étienne Bersac 为我指明了正确的方向。
我是这样实现的:
from werkzeug import serving
parent_log_request = serving.WSGIRequestHandler.log_request
def log_request(self, *args, **kwargs):
if self.path == '/healthcheck':
return
parent_log_request(self, *args, **kwargs)
def filter_healthcheck_logs():
serving.WSGIRequestHandler.log_request = log_request
【讨论】:
另一种选择是对 Étienne Bersac
建议的 WSGIRequestHandler 进行猴子补丁这样:
from werkzeug.serving import WSGIRequestHandler
from werkzeug.urls import uri_to_iri
try:
import click
except ImportError:
click = None
def log_request(WSGIRequestHandler, code="-", size="-"):
try:
path = uri_to_iri(WSGIRequestHandler.path)
if path in black_listed_routes:
return
msg = "%s %s %s" % (WSGIRequestHandler.command, path, WSGIRequestHandler.request_version)
except AttributeError:
# path isn't set if the requestline was bad
msg = WSGIRequestHandler.requestline
code = str(code)
if click:
color = click.style
if code[0] == "1": # 1xx - Informational
msg = color(msg, bold=True)
elif code[0] == "2": # 2xx - Success
msg = color(msg, fg="white")
elif code == "304": # 304 - Resource Not Modified
msg = color(msg, fg="cyan")
elif code[0] == "3": # 3xx - Redirection
msg = color(msg, fg="green")
elif code == "404": # 404 - Resource Not Found
msg = color(msg, fg="yellow")
elif code[0] == "4": # 4xx - Client Error
msg = color(msg, fg="red", bold=True)
else: # 5xx, or any other response
msg = color(msg, fg="magenta", bold=True)
WSGIRequestHandler.log("info", '"%s" %s %s', msg, code, size)
def monkey_patch_logger():
WSGIRequestHandler.log_request = log_request
【讨论】:
这是一个基于 mpaepper 的answer 略微修改的实现。
它允许使用正则表达式指定禁用日志的端点。当您想要忽略端点的日志时,这可能很有用,例如 "/v1/recipes/<int:recipe_id>":
def disable_endpoint_logs():
"""Disable logs for requests to specific endpoints."""
disabled_endpoints = ('/', '/healthz', '/v1/recipes/[0-9]+')
parent_log_request = serving.WSGIRequestHandler.log_request
def log_request(self, *args, **kwargs):
if not any(re.match(f"{de}$", self.path) for de in disabled_endpoints):
parent_log_request(self, *args, **kwargs)
serving.WSGIRequestHandler.log_request = log_request
使用上面的代码,端点"/v1/recipes/23992341" 的日志将被忽略,但"/v1/recipes" 的日志不会被忽略。
只需在您的代码中调用此函数一次即可。
【讨论】:
提出的其他解决方案是正确的,它们适用于 Werkzeug 的默认 Flask 设置。同样的方法也适用于将 Flask 与 gevent 一起使用,但决定在此处发布,以防其他人偶然发现它并立即需要代码:
from gevent.pywsgi import WSGIHandler
class CustomWSGIHandler(WSGIHandler):
def log_request(self):
requests_to_ignore = ["/health", "/"]
if self.path in requests_to_ignore:
return
super(CustomWSGIHandler, self).log_request()
【讨论】: