当前位置:首页>python>别老是用print打日志了,Python自带的logging库配置好排查问题效率翻倍

别老是用print打日志了,Python自带的logging库配置好排查问题效率翻倍

  • 2026-09-08 18:42:36
别老是用print打日志了,Python自带的logging库配置好排查问题效率翻倍

刚入行的时候,我跟大多数人一样,调试代码全靠 print。哪里不对就打印一下变量,满屏输出一坨,自己爽了,等别人或者生产环境出问题就傻眼了。日志文件里全是'这里进来了'“那个值不对”,连时间都没有,根本没法查。

后来我老老实实把项目里的 print 全换成了 logging。刚开始觉得麻烦,多了几行配置代码。用了一周后,线上问题排查速度快了不止一倍。生产环境出 bug,直接看日志文件,错误堆栈、时间戳、函数调用链一目了然,不用再远程上去加 print 了。

很多人觉得 Python 的 logging 库复杂,其实配置一次就能反复用。核心就三样东西:日志器(Logger)、处理器(Handler)、格式化器(Formatter)。日志器就是写日志的对象,处理器决定日志去哪(文件、控制台、网络),格式化器控制日志长什么样。

给大家看一个最实用的配置模板。直接在代码开头贴进去,后面所有模块都能用。

```python
import logging
import sys

def setup_logger(name=__name__, log_file='app.log', level=logging.INFO):
    logger = logging.getLogger(name)
    logger.setLevel(level)

     控制台输出,调试时候用
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setLevel(level)
    console_format = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(console_format)

     文件输出,持久化记录
    file_handler = logging.FileHandler(log_file, encoding='utf-8')
    file_handler.setLevel(logging.WARNING)   文件里只记录 WARNING 及以上的
    file_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s')
    file_handler.setFormatter(file_format)

    logger.addHandler(console_handler)
    logger.addHandler(file_handler)
    return logger

 直接模块级别调用,后面 import 这个就能用
logger = setup_logger('myapp')
```

这个配置有几个隐藏技巧。控制台输出用 StreamHandler,默认是 stderr,我改成 stdout,日志不会和错误信息混在一起。文件处理器单独设置级别为 WARNING,平时开发用 logger.info 不影响文件大小,只有真正的问题才会落盘。

用的时候简单得很。在任何 Python 文件里直接 import 这个 setup_logger 模块,然后这样写:

```python
logger.info('用户登录成功,用户ID: %s', user_id)
logger.warning('数据库连接超时,第3次重试')
logger.error('订单支付失败,订单号: %s', order_id, exc_info=True)
```

注意 exc_info=True 这个参数。它会自动把异常堆栈打出来。比 traceback.print_exc() 干净很多。

还有一个坑。很多人用 logging.getLogger() 的时候不传参数,默认拿根日志器。根日志器默认只处理 WARNING 以上的消息。你辛辛苦苦配了格式,结果 logger.info 根本没效果。一定是搞错了。要么给 getLogger 传一个名字,要么给处理器单独设置级别。

如果项目是 Django 或者 Flask,配置方法也差不多。Django 在 settings.py 里写 LOGGING 字典,Flask 用 app.logger 配合 logging.config.dictConfig。核心思路一模一样,就是把日志分类,给不同等级的消息安排不同的去处。

还有一个好用但容易忽略的东西:日志轮转。单文件日志无限往大里写,磁盘满了服务就挂了。用 RotatingFileHandler 可以按文件大小自动切割。

```python
from logging.handlers import RotatingFileHandler

rotating_handler = RotatingFileHandler(
    'app.log', maxBytes=1010241024, backupCount=5   10MB 大小,保留5个备份
)
```

或者按时间切割,用 TimedRotatingFileHandler。生产环境必须加上,这是血的教训。

有人觉得日志配置麻烦,写个字典配置就能一劳永逸。Python 自带的 logging.config.dictConfig 方法可以直接读取字典格式的配置,复制到新项目里改改路径就行。网上搜一下'Python logging dictConfig 模板'就能找到成熟的方案。

再说一个真实案例。之前接手一个老项目,所有日志都是 print 输出到控制台的。生产环境偶发崩溃,要查原因只能重现。我把所有 print 换成 logger,加上了时间戳和模块名。第二天线上出了同样的错误,拿着日志文件去排查,5分钟就定位到一个并发写入导致的文件损坏。换成以前,至少要花一整天反复测试。

现场的人最懂这种痛。上了 logging 之后该干嘛干嘛,日志自动写,错误自动分级。遇到线上紧急问题,一句 grep ERROR app.log | head -50 就锁定了原因。比对着满屏的 print 输出猜谜语强一万倍。

不用一口吃成胖子。先把当前项目里 print 最多的模块改成 logging。跑两三天就会发现,排查问题时总忍不住去翻那个模块的日志。这时候再改其他模块,心里就有底了。

最新文章

随机文章