1. 日志系统概述:为什么需要日志、日志级别、日志与打印的区别

大家好,欢迎来到这门实战课。

我是你们的老朋友,一个在运维坑里摸爬滚打多年的后端工程师。今天咱们聊聊日志系统。

你可能觉得日志很简单,不就是print一下吗?

嗯,我以前也这么想。直到有一次线上事故,让我彻底改变了看法。

1.1 为什么需要日志?

说白了,日志就是系统的「黑匣子」。飞机有黑匣子,我们的程序也得有。

我个人习惯把日志看作三样东西:

  • 眼睛:程序跑在服务器上,你看不到它内部发生了什么。日志就是你的眼睛。
  • 记忆:用户报了个bug,说「昨天下午三点左右出错了」。没有日志,你只能靠猜。
  • 证据:系统被攻击了?性能突然下降了?日志会告诉你「凶手是谁」。

我在项目中遇到过最典型的一个场景:

有一次凌晨两点,线上服务突然大面积超时。我登录服务器,第一件事就是看日志。结果发现是数据库连接池被耗尽,而罪魁祸首是一个没关闭游标的SQL查询。如果没有日志,我可能得排查到天亮。

核心观点:日志不是写给机器看的,是写给人看的。尤其是写给「未来的你」看的。

1.2 日志级别:DEBUG / INFO / WARNING / ERROR / CRITICAL

日志级别这东西,刚入行时我总觉得是形式主义。后来发现,级别用对了,能救命。

Python内置的logging模块定义了五个级别,从低到高依次是:

级别 数值 什么时候用
DEBUG 10 调试信息,开发阶段用。比如变量值、函数入口出口。
INFO 20 正常流程信息。比如「用户登录成功」「订单已创建」。
WARNING 30 警告,程序还能跑,但可能有隐患。比如「磁盘剩余空间不足10%」。
ERROR 40 错误,某个功能失败了,但程序没挂。比如「数据库连接超时」。
CRITICAL 50 严重错误,程序可能撑不住了。比如「内存耗尽,即将OOM」。

你想想看,如果所有信息都用INFO级别,那日志文件会变成一锅粥。真正重要的ERROR信息反而被淹没了。

我建议这样配置:

  • 开发环境:输出DEBUG及以上所有日志,方便调试。
  • 测试环境:输出INFO及以上,过滤掉太琐碎的调试信息。
  • 生产环境:输出WARNING及以上。除非你在排查特定问题,否则别开DEBUG,否则日志量会爆炸。

小技巧:我曾经在生产环境误开了DEBUG级别,结果一天产生了50GB日志,直接把磁盘撑爆了。从那以后,我都在配置里加了个「日志级别动态调整」的功能,通过API可以临时调低级别,排查完再恢复。

1.3 日志与打印的区别

很多新手喜欢用print来调试。说实话,我刚开始也是这么干的。

但print和日志,完全是两码事。

咱们直接看代码对比:

# 这是print,不推荐
print("用户登录成功,用户ID:", user_id)

# 这是logging,推荐
import logging
logging.info("用户登录成功,用户ID: %s", user_id)

区别在哪?我列几个关键点:

  1. 输出控制:print只能输出到控制台。logging可以同时输出到文件、控制台、远程服务器、甚至邮件。
  2. 级别过滤:print没有级别概念。logging可以设置只输出ERROR以上的日志。
  3. 格式化:print的格式你得自己拼。logging自带时间戳、进程ID、线程ID、文件名、行号等信息。
  4. 性能:print是同步阻塞的。logging可以异步写入,不影响主流程性能。
  5. 可配置性:print写死了。logging可以通过配置文件随时调整,不用改代码。

避坑指南:我曾经接手过一个项目,代码里全是print。上线后想查问题,发现控制台输出早就被冲掉了。更惨的是,print的内容里还包含了用户密码的明文……嗯,从那以后,我见到print就条件反射地皱眉。

所以,记住一句话:print是临时的,logging是永久的。

写代码时,养成用logging的习惯。刚开始可能觉得多打几个字麻烦,但等你真正需要排查线上问题时,你会感谢自己的。

1.4 一个简单的日志配置示例

说了这么多,咱们来点实际的。下面是我个人常用的日志配置模板:

import logging

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    filename='app.log',
    filemode='a'
)

# 使用
logger = logging.getLogger(__name__)

logger.debug("这是调试信息,开发时用")
logger.info("用户登录成功")
logger.warning("磁盘空间不足")
logger.error("数据库连接失败")
logger.critical("系统即将崩溃")

这个配置会把日志写入app.log文件,格式包含时间、模块名、级别和消息内容。

当然,生产环境不会这么简单。后面章节我会详细讲如何配置日志轮转、如何集中收集日志、如何做告警。

嗯,今天就先聊到这儿。日志这东西,看似基础,但用好它,能让你在运维路上少走很多弯路。

下一章,咱们聊聊Python的logging模块到底怎么用,以及那些你容易踩的坑。