Python 入门:用标准库写一个带轮转的日志小工具

举报
yd_221032393 发表于 2026/10/23 06:40:51 2026/10/23
【摘要】 刚学 Python 的人写脚本,习惯用 print 打日志。调试时挺顺手,但脚本上线之后问题就来了:print 没有时间戳,没有级别区分,输出还混在终端里,出了问题想回溯,只能两眼一抹黑。这时候就要请出标准库里的 logging 模块——不需要装任何第三方包,几行配置就能得到一套正经的日志系统。 一、logging 的三板斧:Logger、Handler、Formatterlogging 的...

刚学 Python 的人写脚本,习惯用 print 打日志。调试时挺顺手,但脚本上线之后问题就来了:print 没有时间戳,没有级别区分,输出还混在终端里,出了问题想回溯,只能两眼一抹黑。这时候就要请出标准库里的 logging 模块——不需要装任何第三方包,几行配置就能得到一套正经的日志系统。

一、logging 的三板斧:Logger、Handler、Formatter

logging 的核心其实只有三个概念:

  • Logger:日志器,负责“记什么”。每个模块可以有自己的 logger,用 logging.getLogger(__name__) 拿名字,避免和别人的日志搅在一起。
  • Handler:处理器,负责“记到哪”。输出到控制台是 StreamHandler,写文件是 FileHandler。
  • Formatter:格式器,负责“长什么样”。比如 %(asctime)s - %(levelname)s - %(message)s 就会打出时间、级别和内容。

再加上日志级别(DEBUG < INFO < WARNING < ERROR < CRITICAL),只有大于等于设定级别的消息才会被记录。开发时设 DEBUG,上线后设 INFO,一行代码切换噪音量。

二、让日志自动轮转:TimedRotatingFileHandler

脚本长期跑,日志文件会越写越大。标准库提供了两个现成的轮转处理器:按大小轮转的 RotatingFileHandler 和按时间轮转的 TimedRotatingFileHandler。对定时任务类脚本,按天轮转最省心:

import logging
from logging.handlers import TimedRotatingFileHandler

logger = logging.getLogger("myjob")
logger.setLevel(logging.INFO)

handler = TimedRotatingFileHandler(
    "myjob.log", when="midnight", interval=1, backupCount=7, encoding="utf-8"
)
handler.setFormatter(logging.Formatter(
    "%(asctime)s [%(levelname)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
))
logger.addHandler(handler)

logger.info("任务开始")

when="midnight" 表示每天午夜切分,backupCount=7 只保留最近 7 天的旧日志,磁盘不会被日志撑爆。旧文件会自动命名为 myjob.log.2026-10-22 这种形式,排查历史问题时按日期找就行。

三、封装一个开箱即用的小工具

每个脚本都写一遍配置太啰嗦,包成一个函数放工具模块里:

# mylog.py
import logging, os
from logging.handlers import TimedRotatingFileHandler

def get_logger(name, log_dir="logs", level=logging.INFO):
    os.makedirs(log_dir, exist_ok=True)
    logger = logging.getLogger(name)
    if logger.handlers:  # 避免重复添加
        return logger
    logger.setLevel(level)

    file_h = TimedRotatingFileHandler(
        os.path.join(log_dir, f"{name}.log"),
        when="midnight", interval=1, backupCount=7, encoding="utf-8",
    )
    file_h.setFormatter(logging.Formatter(
        "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
    ))
    console_h = logging.StreamHandler()
    console_h.setFormatter(logging.Formatter("[%(levelname)s] %(message)s"))

    logger.addHandler(file_h)
    logger.addHandler(console_h)
    return logger

业务脚本里只需要两行:

from mylog import get_logger
log = get_logger("crawler")
log.info("开始抓取第 1 页")
log.warning("第 3 页超时,重试中")
log.error("第 5 页失败,已跳过")

既写文件又打控制台,开发联调和线上排查都顾得到。

四、几个新手容易踩的坑

  1. root logger 污染:直接用 logging.info(...) 走的是 root logger,库和业务日志会混在一起。养成 getLogger(__name__) 的习惯。
  2. 重复输出:handler 被添加多次,同一条日志会打好几遍。用上面的 if logger.handlers 守卫,或者在配置前 logger.handlers.clear()。
  3. 级别设错:logger.setLevel 和 handler.setLevel 是两道闸门,两个都要放行。最省事是只设 logger 的级别,handler 保持默认。
  4. 中文乱码:Windows 下写文件记得加 encoding="utf-8",否则中文日志打开是乱码。

小结

print 适合调试,logging 适合生产。从 print 换到 logging,成本就是学会 Logger/Handler/Formatter 三件套,再加一个轮转处理器。把 get_logger 收进自己的工具箱,以后每个脚本开局两行,日志规范一次到位。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。