733 字
4 分钟
logging

Logging#

Logger#

当在import logging的时候就创建了全局的单例logging.root,之后通过logging.getlogger()获得的所有logger都是root的子logger。logger的层级也是用name字段来区分的。 logging模块创建的所有的logger对象全部是全局单例的,通过name字段区分,所以说完全不需要logger的传递,在所有的模块直接gerlogger你想要的logger就行了,包括logging对象本身就是root logger,随便在哪import了就直接用,包括配置,你可以在刚开始就把后面可能会用到的logger给get出来然后先配置好,然后在别的模块直接调用就行了。这个设计有个问题,就是你要接管别的库的logger,必须要知道他们内置的logger的name,只能去文档查了,大部分库都会有logging板块的,比如uvicorn,这个设计很奇葩,我最开始用这个感觉也太奇葩了点,所以说可以用更现代化的loguru。

Handler#

控制输出位置的,输出到哪里都行,用docker的话还是统一放到stdout就行了。

Formatter#

可以把logrecord的字段通过格式字符串(有点像c的那种),输出成你想要的字符串。

Filter#

可以在这里对进入这个过滤器的LogRecord进行逻辑处理,包括增加字段,检查字段过滤等等。

LogRecord#

logger.info(msg)函数发射的日志记录本体,他会通过一个个logger向上传递,里面有着很多字段,具体看这个,通过这个,再在formatter可以控制输出格式和字段。

架构网络#

logger和handler是多对多的,并且一个logger可以有多个handler。handler和filter也是多对多的,并且一个handler可以连上多个filter顺序执行,filter和logger也是多对多的。filter在handler上和在logger上的处理的LogRecord作用域不同。handler和formatter是多对一的。

工程实践#

配置#

工程上我们会在项目启动的刚开始载入下面这个配置的字典来,配置日志系统,通过logging.config.dictConfig(dict)来加载这个字典

class TraceIDFilter(logging.Filter):
def filter(self, record):
record.trace_id = trace_id_var.get()
return True
LOGGING_CONFIG = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"standard_format": {
"format": "%(levelname)-8s | %(asctime)s | %(name)s | %(trace_id)s | %(message)s",
},
"systemd_format": {
"format": "%(levelname)-8s | %(asctime)s | %(name)s | %(message)s",
},
},
"filters": {
"trace_filter": {"()": "app.core.logging_config.TraceIDFilter"},#这个过滤器实际上就是让所有的LogRecord经过TraceIDFilter这个函数统一处理加上trace_id这个字段
},
"handlers": {
"console": {
"class": "logging.StreamHandler",
"formatter": "standard_format",
"filters": ["trace_filter"],
"stream": "ext://sys.stdout",
},
"uvicorn_output": {
"class": "logging.StreamHandler",
"formatter": "systemd_format",
"stream": "ext://sys.stdout",
},
},
"loggers": {
"": { #""表示根logger
"handlers": ["console"],
"level": "INFO",
},
"uvicorn.access": {
"handlers": [], #覆盖uvicorn原生的logging,让他统一传到uvicorn节点输出
"propagate": True,
},
"uvicorn.error": {
"handlers": [], #覆盖uvicorn原生的logging,让他统一传到uvicorn节点输出
"propagate": True,
},
"uvicorn": {
"handlers": ["uvicorn_output"], # 统一输出,并不传到root节点
"propagate": False,
},
},
}
logging
https://blog.cannian.space/posts/2026-4-28-logging/
作者
Cannian
发布于
2026-04-28
许可协议
CC BY-NC-SA 4.0