Python 日志练习:级别、处理器与格式
需要上下文时,print 语句就不够了。日志给每条消息一个严重级别、一个目的地和一种格式,让你不必修改每个调用点就能检查生产行为。
获取命名日志器
用 logging.getLogger 传入稳定名称,例如模块名。命名日志器形成层级,配置可以共享。不要每次函数调用都创建新日志器。
import logging
logger = logging.getLogger("app")
logger.setLevel(logging.INFO)
print(logger.name)每个模块一个日志器
级别负责过滤记录
日志器只处理不低于自身级别的记录。INFO 低于 WARNING,所以日志器设为 WARNING 时 info 调用会被忽略。要有意识地设置级别,而不是把所有东西都降到 DEBUG。
import logging
from io import StringIO
stream = StringIO()
logger = logging.getLogger("app")
logger.handlers[:] = [logging.StreamHandler(stream)]
logger.setLevel(logging.WARNING)
logger.propagate = False
logger.info("hidden")
logger.warning("shown")
print(stream.getvalue().strip())低于阈值
处理器决定目的地
处理器把记录写到流、文件或其他目的地。StreamHandler 适合控制台,也适合用 StringIO 捕获输出的测试。需要控制记录去向时,显式添加处理器。
import logging
from io import StringIO
stream = StringIO()
logger = logging.getLogger("demo")
logger.handlers[:] = [logging.StreamHandler(stream)]
logger.setLevel(logging.INFO)
logger.propagate = False
logger.info("hello")
print(stream.getvalue().strip())可测试的流处理器
格式化器控制文本
格式化器把日志记录变成最终字符串。格式串可以包含级别、日志器名称、消息和其他记录属性。保持格式稳定,日志才方便搜索。
import logging
from io import StringIO
stream = StringIO()
handler = logging.StreamHandler(stream)
handler.setFormatter(logging.Formatter("%(levelname)s:%(message)s"))
logger = logging.getLogger("demo")
logger.handlers[:] = [handler]
logger.setLevel(logging.INFO)
logger.propagate = False
logger.warning("check")
print(stream.getvalue().strip())级别与消息
自己管理输出时停止传播
记录会沿日志器层级向上传给祖先处理器。本地处理器和根日志器都配置时,输出可能重复。想让日志器自成一体时,把 propagate 设为 False。
import logging
from io import StringIO
stream = StringIO()
logger = logging.getLogger("demo")
logger.handlers[:] = [logging.StreamHandler(stream)]
logger.setLevel(logging.INFO)
logger.propagate = False
logger.info("once")
print(stream.getvalue().strip())一条记录,一个目的地
你的练习清单
- 用 getLogger 和稳定的模块级名称。
- 把日志器级别设为需要的最低严重级别。
- 每个目的地都附加一个处理器。
- 默认文本不够时使用格式化器。
- 本地处理器应独占输出时设置 propagate=False。
常见问题
应该用 print 还是 logging?
消息需要严重级别、过滤或不同目的地时用 logging。很小的脚本和即时调试用 print 也可以。
为什么日志消息没有出现?
检查日志器级别、处理器级别,以及是否附加了处理器。级别高于记录严重程度时会被过滤。
可以测试日志输出吗?
可以。给 StringIO 附加 StreamHandler,设置 propagate 为 False,调用日志器,然后断言捕获的文本。
练习日志
12 道题,覆盖级别、处理器、格式化器、传播和过滤行为。
继续阅读: