Python3 模块精讲:logging 日志记录(企业项目必备)

 

📝 本章学习目标:本章聚焦企业级 Python 项目开发规范,帮助读者从零彻底掌握 logging 模块的使用、配置、封装与落地。通过本章学习,你将能独立搭建可复用、可监控、可持久化、多环境兼容的日志体系,全面替代 print 调试,满足线上项目运维、排查、审计与日志采集需求。


一、引言:为什么 logging 是项目第一必备模块

1.1 背景与意义

💡 核心认知:在真实企业项目中,日志是系统的 “黑匣子”。没有规范日志,等于线上程序 “裸奔”。

Python 自带的 print() 只能简单输出,无法满足:

  • 日志分级(debug/info/warn/error)
  • 持久化落地(写入文件、按大小 / 时间切割)
  • 多模块统一输出
  • 日志格式标准化(时间、文件名、行号、级别、信息)
  • 对接 ELK、 Loki、云监控等采集系统
  • 生产环境动态开关调试信息
  • 异常堆栈完整捕获

logging 是 Python 官方内置、零依赖、生产级稳定的日志库,是所有后端、爬虫、数据分析、AI 工程化项目的基础基建。据行业实践统计:规范日志能让故障排查效率提升 10 倍以上

1.2 本章结构概览

为了帮助你系统性掌握,本章按以下路线展开:

plaintext

📊 概念解析 → 核心组件 → 使用方法 → 高级配置 → 企业封装 → 实战案例 → 最佳实践 → 总结展望

二、核心概念解析

2.1 基本定义

概念一:logging 模块

  • Python 官方标准库,无需安装,直接 import 使用。
  • 支持日志级别、日志输出、格式控制、滚动切割、多处理器
  • 可同时输出到控制台、文件、网络、消息队列等多个目的地。

概念二:日志核心能力

表格

能力说明企业必备
级别控制区分 debug/info/warning/error/critical
格式定制时间、路径、行号、进程、线程
持久化写入文件并自动切割
多 handler同时控制台 + 文件 + 远程
全局单例跨模块共享同一日志配置

2.2 关键术语解释

⚠️ 注意:以下术语是理解 logging 的基础,请务必掌握。

术语 1:日志级别(Level)

  • DEBUG:调试信息,开发环境用
  • INFO:普通运行信息,正常流程
  • WARNING:警告,不影响运行但需注意
  • ERROR:错误,函数 / 请求失败
  • CRITICAL:严重错误,系统崩溃

术语 2:核心组件

  • Logger:日志器,提供调用接口
  • Handler:处理器,控制输出位置(控制台 / 文件)
  • Formatter:格式器,定义输出样式
  • Filter:过滤器,精细化过滤日志

2.3 技术架构概览

💡 架构理解:

plaintext

┌─────────────────────────────────────────┐
│              业务调用层                  │
│        logger.info()/error() 等          │
├─────────────────────────────────────────┤
│              Logger 日志器              │
│           负责级别过滤与分发            │
├─────────────────────────────────────────┤
│              Handler 处理器             │
│      StreamHandler / FileHandler 等     │
├─────────────────────────────────────────┤
│              Formatter 格式器           │
│        时间、级别、文件名、行号、内容    │
└─────────────────────────────────────────┘

三、技术原理深入

3.1 核心组件原理

组件一:Logger(日志器)

python

运行

import logging

# 获取日志器(全局单例)
logger = logging.getLogger(__name__)

# 设置最低级别
logger.setLevel(logging.DEBUG)

作用:接收日志、按级别过滤、分发给 Handler。

组件二:Handler(输出器)

常用:

  • StreamHandler:控制台输出
  • FileHandler:文件输出
  • RotatingFileHandler:按大小切割
  • TimedRotatingFileHandler:按时间切割

组件三:Formatter(格式器)

python

运行

formatter = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(filename)s - %(lineno)d - %(message)s'
)

组件四:Filter(过滤器)

用于更细粒度控制日志输出,一般项目较少使用。


3.2 基础使用流程

📊 标准流程:

  1. 获取 logger
  2. 设置级别
  3. 创建 Handler
  4. 设置 Formatter
  5. 添加 Handler 到 logger
  6. 输出日志

最简可运行代码

python

运行

import logging

# 1. 基本配置
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    filename='run.log'
)

# 2. 输出日志
logging.debug('调试信息')
logging.info('程序启动成功')
logging.warning('磁盘空间不足')
logging.error('数据库连接失败')
logging.critical('服务崩溃!')

3.3 高级配置原理

按文件大小切割

python

运行

from logging.handlers import RotatingFileHandler

handler = RotatingFileHandler(
    'app.log',
    maxBytes=1024*1024*5,  # 5MB
    backupCount=5,        # 保留5个文件
    encoding='utf-8'
)

按时间切割(企业最常用)

python

运行

from logging.handlers import TimedRotatingFileHandler

handler = TimedRotatingFileHandler(
    'run.log',
    when='midnight',  # 每天凌晨切割
    interval=1,
    backupCount=7,    # 保留7天
    encoding='utf-8'
)

四、实践应用指南

4.1 应用场景分析

✅ 核心场景:logging 在企业中的必备场景

场景一:后端 API 服务(FastAPI/Flask/Django)

  • 记录请求路径、参数、返回值、耗时
  • 记录数据库异常、第三方接口调用失败
  • 按天切割,对接 ELK

场景二:数据处理 / AI 训练

  • 记录数据读取、清洗进度
  • 记录模型指标、loss、异常样本
  • 保存关键节点信息,便于复现

场景三:定时任务 / 爬虫

  • 记录启动、执行、结束状态
  • 记录失败任务、重试次数
  • 长期运行必须落地日志

场景四:多模块大型项目

  • 统一日志格式、统一文件输出
  • 全局共享 logger,避免混乱

4.2 实施步骤详解

🔧 企业标准实施步骤:

步骤一:确定日志规范① 输出格式(时间、级别、文件名、行号、信息)② 级别规则(dev=DEBUG,prod=INFO)③ 切割策略(按天 / 按大小)④ 保存时长(7 天 / 30 天)⑤ 输出位置(控制台 + 文件)

步骤二:技术选型清单

plaintext

## logging 技术选型清单
### 核心组件
- [ ] Logger:全局单例
- [ ] StreamHandler:控制台输出
- [ ] TimedRotatingFileHandler:按天切割
- [ ] Formatter:统一格式
### 增强能力
- [ ] 编码 utf-8
- [ ] 堆栈捕获
- [ ] 多环境兼容
- [ ] 重复 Handler 去重

步骤三:开发实现

表格

任务描述时间
基础配置basicConfig 快速使用0.5 小时
高级封装单例 logger 函数 / 类1 小时
多模块集成跨文件导入使用1 小时
异常捕获完整堆栈记录1 小时
测试验证分级输出、切割、编码1 小时

4.3 最佳实践分享

💡 经验总结:最佳实践一:全局单例原则① 一个项目只创建一个 logger② 避免重复添加 Handler③ 所有模块导入同一个 logger

最佳实践二:分级规范

  • DEBUG:开发调试
  • INFO:启动、成功、流程正常
  • WARNING:配置问题、资源不足
  • ERROR:业务异常、调用失败
  • CRITICAL:系统不可用

最佳实践三:生产禁忌

  • 禁止用 print
  • 禁止输出敏感信息(密码、密钥)
  • 禁止无限大小日志文件
  • 必须切割、必须压缩、必须定期清理

五、超多代码示例(从入门到企业级)

示例 1:最简控制台输出

python

运行

import logging

# 基础配置
logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s - %(levelname)s - %(message)s"
)

# 测试输出
logging.debug("调试信息")
logging.info("普通信息")
logging.warning("警告信息")
logging.error("错误信息")
logging.critical("严重错误")

示例 2:日志输出到文件

python

运行

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    filename="app.log",      # 输出文件
    filemode="a",            # 追加模式
    encoding="utf-8"
)

logging.info("程序启动成功")
logging.error("数据库连接失败")

示例 3:同时输出到控制台 + 文件

python

运行

import logging

logger = logging.getLogger("test")
logger.setLevel(logging.DEBUG)
logger.handlers.clear()  # 清空已有处理器

# 控制台处理器
sh = logging.StreamHandler()
sh.setLevel(logging.DEBUG)

# 文件处理器
fh = logging.FileHandler("app.log", encoding="utf-8")
fh.setLevel(logging.INFO)

# 格式
formatter = logging.Formatter("%(asctime)s | %(levelname)s | %(message)s")
sh.setFormatter(formatter)
fh.setFormatter(formatter)

logger.addHandler(sh)
logger.addHandler(fh)

# 测试
logger.debug("这是调试信息(只在控制台)")
logger.info("这是普通信息(控制台+文件)")

示例 4:按文件大小自动切割

python

运行

import logging
from logging.handlers import RotatingFileHandler

logger = logging.getLogger("size_rotate")
logger.setLevel(logging.INFO)
logger.handlers.clear()

# 每 5MB 切割一个文件
handler = RotatingFileHandler(
    "rotate.log",
    maxBytes=5*1024*1024,  # 5MB
    backupCount=5,        # 最多保留5个
    encoding="utf-8"
)

formatter = logging.Formatter("%(asctime)s | %(levelname)s | %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)

# 测试
for i in range(1000):
    logger.info(f"测试日志 {i}")

示例 5:按时间自动切割(企业首选)

python

运行

import logging
from logging.handlers import TimedRotatingFileHandler

logger = logging.getLogger("time_rotate")
logger.setLevel(logging.INFO)
logger.handlers.clear()

# 每天凌晨切割,保留7天
handler = TimedRotatingFileHandler(
    "time.log",
    when="midnight",
    interval=1,
    backupCount=7,
    encoding="utf-8"
)

formatter = logging.Formatter("%(asctime)s | %(levelname)s | %(filename)s | %(lineno)d | %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)

logger.info("程序启动")
logger.warning("磁盘空间不足")
logger.error("接口调用失败")

示例 6:捕获异常堆栈信息

python

运行

import logging

logging.basicConfig(
    level=logging.ERROR,
    format="%(asctime)s | %(levelname)s | %(message)s",
    filename="error.log",
    encoding="utf-8"
)

try:
    a = 1 / 0
except Exception as e:
    logging.exception("发生除零错误")  # 自动打印堆栈

示例 7:多模块共用日志

python

运行

# ------------------- log_config.py -------------------
import logging
def get_logger():
    logger = logging.getLogger("project")
    if logger.handlers:
        return logger
    logger.setLevel(logging.DEBUG)
    sh = logging.StreamHandler()
    formatter = logging.Formatter("%(asctime)s | %(levelname)s | %(message)s")
    sh.setFormatter(formatter)
    logger.addHandler(sh)
    return logger

# ------------------- module_a.py -------------------
from log_config import get_logger
logger = get_logger()
def test():
    logger.info("A模块运行")

# ------------------- main.py -------------------
from log_config import get_logger
import module_a
logger = get_logger()

logger.info("主程序启动")
module_a.test()

示例 8:显示文件名 + 行号 + 函数名(企业标准格式)

python

运行

import logging

logger = logging.getLogger("detail")
logger.setLevel(logging.DEBUG)
logger.handlers.clear()

sh = logging.StreamHandler()
formatter = logging.Formatter(
    "%(asctime)s | %(levelname)-8s | %(filename)-15s | %(funcName)-10s | %(lineno)3d | %(message)s"
)
sh.setFormatter(formatter)
logger.addHandler(sh)

def test():
    logger.debug("进入函数")
    logger.info("执行成功")

test()

六、企业级实战案例

6.1 成功案例:企业级通用日志封装(可直接上线)

背景某 Python 后端项目需要统一日志:控制台 + 按天切割、多模块共用、兼容开发 / 生产环境。

解决方案(完整代码 + 逐行注释)

python

运行

# -*- coding: utf-8 -*-
"""
企业级 logging 封装
支持:控制台输出 + 按天切割 + 全局单例 + 中文不乱码
"""
import os
import logging
from logging.handlers import TimedRotatingFileHandler
from typing import Optional

def get_logger(name: str = __name__, log_dir: str = "logs") -> logging.Logger:
    """
    企业级日志获取函数(全局单例)
    :param name: 日志器名称
    :param log_dir: 日志保存目录
    :return: 配置好的 logger
    """
    # 如果日志器已存在,直接返回,避免重复添加 Handler
    logger = logging.getLogger(name)
    if logger.handlers:
        return logger

    # ===================== 1. 基础配置 =====================
    # 日志级别:开发DEBUG,生产INFO
    logger.setLevel(logging.DEBUG)
    # 避免日志向上传递到根日志器
    logger.propagate = False

    # ===================== 2. 创建日志目录 =====================
    if not os.path.exists(log_dir):
        os.makedirs(log_dir)

    # ===================== 3. 日志格式 =====================
    # 时间 - 日志器名 - 级别 - 文件名 - 行号 - 信息
    formatter = logging.Formatter(
        "%(asctime)s | %(name)-12s | %(levelname)-8s | %(filename)-15s | %(lineno)4d | %(message)s"
    )

    # ===================== 4. 控制台 Handler =====================
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.DEBUG)
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)

    # ===================== 5. 文件 Handler(按天切割) =====================
    log_file = os.path.join(log_dir, "app.log")
    file_handler = TimedRotatingFileHandler(
        filename=log_file,
        when="midnight",   # 每天凌晨切割
        interval=1,
        backupCount=7,     # 保留7天
        encoding="utf-8",  # 中文不乱码
        delay=True
    )
    file_handler.setLevel(logging.INFO)
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    return logger

# ===================== 全局单例 logger =====================
logger = get_logger("project")

# ===================== 使用示例 =====================
if __name__ == '__main__':
    logger.debug("调试模式:参数详细信息")
    logger.info("服务启动成功")
    logger.warning("配置文件使用默认值")
    logger.error("数据库连接超时")
    logger.critical("磁盘已满,服务退出")

    # 异常捕获示例
    try:
        1 / 0
    except Exception as e:
        logger.exception("发生除零异常")  # 自动打印堆栈

实施效果

表格

指标未使用 logging使用企业级 logging提升
排查效率极低,靠猜定位行号、堆栈、时间极显著
日志混乱严重,多模块冲突统一格式、统一输出清晰
磁盘风险无限增长自动切割清理安全
可观测性支持采集系统生产可用

6.2 失败教训

❌ 案例二:无规范日志导致线上故障无法排查问题某项目全程使用 print,上线后出现:

  • 无时间、无级别、无堆栈
  • 无法定位异常位置
  • 无法复现问题
  • 无法定位是哪台机器、哪个请求出错

经验教训⚠️ 警示:

  • 企业项目严禁使用 print
  • 必须统一日志格式与输出
  • 必须记录异常堆栈
  • 必须持久化并切割

七、常见问题解答

7.1 技术问题

Q1:日志重复输出?💡 原因:logger 被多次实例化,重复添加 Handler。解决:判断 if logger.handlers 再添加。

Q2:中文乱码?解决:encoding='utf-8'

Q3:生产环境不想输出 DEBUG?解决:

python

运行

console_handler.setLevel(logging.INFO)

Q4:如何记录完整异常堆栈?解决:使用 logger.exception(e),自动捕获堆栈。

7.2 应用问题

Q5:多模块如何共用同一个 logger?utils/logger.py 中创建 logger,其他文件 import 即可。

Q6:日志太多如何优化?

  • 提升生产环境级别为 INFO
  • 按时间 / 大小自动切割
  • 定期清理旧日志
  • 使用消息队列异步输出

八、未来发展趋势

8.1 技术趋势

表格

趋势描述时间
结构化日志JSON 格式,便于采集已普及
异步日志不阻塞业务1–2 年
云原生日志直接对接云监控进行中
AI 日志分析自动异常检测2–3 年

8.2 应用趋势

  • 日志 → 监控 → 告警 → 自愈一体化
  • 微服务统一日志链路追踪
  • 大模型自动分析日志故障原因

8.3 职业发展

表格

阶段学习重点时间
入门基础配置、级别输出1 天
进阶多 Handler、切割、封装3 天
专业结构化、异步、多环境1 周
专家日志平台、链路追踪、告警1 月 +

九、本章小结

9.1 核心要点回顾

✅ 本章核心内容:① 概念理解:logging 级别、组件、架构② 技术原理:Logger/Handler/Formatter 协同工作③ 基础使用:basicConfig 快速上手④ 高级用法:切割、多输出、单例、异常捕获⑤ 企业封装:可直接上线的通用日志工具⑥ 最佳实践:规范、禁忌、避坑指南

9.2 学习建议

💡 给读者的建议:① 所有项目从第一天就用 logging,禁止 print② 直接复制本章企业封装代码使用③ 统一团队日志规范④ 生产环境必须按天 / 按大小切割


十、课后练习

练习一:基础使用用 basicConfig 配置日志,输出到控制台和文件,并区分级别。

练习二:高级封装基于本章代码,实现一个支持:

  • 控制台 + 文件双输出
  • 按天切割
  • 中文不乱码
  • 全局单例的日志工具,并在多模块中调用。

练习三:实战落地在你的项目中替换所有 print 为 logging,并验证输出正常。


十一、参考资料

📄 官方文档:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值