Python Flask 日志集成 logid 实现方案:基于 threading.local 与 Filter
本文详解如何在 Flask 应用中通过 threading.local 存储 logid,并利用 logging 模块的 Filter 功能自动将 logid 注入日志输出。方案使用 uuid.uuid1().time 生成趋势递增的唯一标识,无需手动修改每个日志打印点,实现请求上下文的自动关联与问题定位。
为了便于问题定位,常见的做法是在日志中引入 logid,以便关联同一个请求的上下文。这主要解决两个问题:一是 logid 作为“全局”变量如何保存和传递;二是如何让日志打印时自动携带 logid,避免在每个打印日志的地方手动传入参数。
logid 保存与传递机制
传统做法是将 logid 保存在 threading.local 中,确保同一线程内该值保持一致。在 before_app_request 钩子中生成 logid 并将其存入该线程局部变量即可。
import threading
from blueprint.hooks import hooks
thread_local = threading.local()
app = Flask()
app.thread_local = thread_local
import uuid
from flask import Blueprint
from flask import current_app as app
hooks = Blueprint('hooks', __name__)
@hooks.before_app_request
def before_request():
"""
处理请求之前的钩子
:return:
"""
# 生成logid
app.thread_local.logid = uuid.uuid1().time
由于需要一个数字类型的 logid,简单使用 uuid.uuid1().time 通常足以满足并发需求,它既保证不重复,又具有趋势递增的特性(通过 logid 即可判断请求的先后顺序)。
打印日志自动携带 logid
这是 Python 日志库自带的功能,可以通过 Filter 来实现这一需求。
import logging
# https://docs.python.org/3/library/logging.html#logrecord-attributes
log_format = "%(asctime)s %(levelname)s [%(threadName)s-%(thread)d] %(logid)s %(filename)s:%(lineno)d %(message)s"
file_handler = logging.FileHandler(file_name)
logger = logging.getLogger()
logid_filter = ContextFilter()
file_handler.addFilter(logid_filter)
file_handler.setFormatter(logging.Formatter(log_format))
logger.addHandler(file_handler)
class ContextFilter(logging.Filter):
"""
logging Filter
"""
def filter(self, record):
"""
threading local 获取logid
:param record:
:return:
"""
log_id = thread_local.logid if hasattr(thread_local, 'logid') else '-'
record.logid = log_id
return True
在 log_format 中使用了多个系统自带的占位符,但 %(logid)s 默认并不存在。每条日志在打印输出前都会经过 Filter 处理,利用这一特性,我们可以将 record.logid 赋值,最终打印出的日志便包含了 logid。
虽然最终实现了功能,但由于是通用化方案,实现起来略显复杂。其实官方教程中介绍了一种更简单的方式:injecting-request-information,看来平时多查阅官方文档很有必要。
以上就是 Python 如何使用 logging 为 Flask 增加 logid 的详细内容,更多关于 Python 为 Flask 增加 logid 的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













