Python日志模块配置:从print到logging的优雅升级指南

简介: 从 `print` 到 `logging` 是 Python 开发的必经之路。`print` 调试简单却难维护,日志混乱、无法分级、缺乏上下文;而 `logging` 支持级别控制、多输出、结构化记录,助力项目可维护性升级。本文详解痛点、优势、迁移方案与最佳实践,助你构建专业日志系统,让程序“有记忆”。

​免费python编程教程:https://pan.quark.cn/s/2c17aed36b72
引言:为什么print该退休了?
"先用print调试,等项目大了再改logging"——这是许多Python初学者的真实写照。但当项目规模从几十行代码膨胀到几千行时,控制台里成百上千的print语句就像失控的洪水:找不到关键信息、无法关闭特定输出、无法区分不同模块的日志……这时你才会意识到,用logging替代print不是选择题,而是程序员的必修课。
探秘代理IP并发连接数限制的那点事 (99).png

一、print的五大痛点

  1. 无法分级输出

    调试信息、警告、错误混在一起

    print("DEBUG: 用户ID获取成功")
    print("WARNING: 磁盘空间不足")
    print("ERROR: 数据库连接失败")

当需要临时关闭调试信息时,只能手动删除或注释所有print语句。

  1. 输出位置固定
    所有print都定向到标准输出,无法同时写入文件、发送邮件或推送到监控系统。

  2. 缺乏上下文信息

    错误发生时不知道时间、模块名等信息

    user_id = get_user_id()
    print(f"获取到的用户ID: {user_id}") # 错误发生时难以追溯

  3. 性能问题
    在高频循环中,print的I/O操作会显著拖慢程序速度。

  4. 格式混乱
    不同开发者的print风格各异,导致日志难以统一分析。

二、logging模块的核心优势

  1. 五级日志级别
    级别 数值 使用场景
    DEBUG 10 开发调试细节
    INFO 20 程序运行关键节点
    WARNING 30 潜在问题但不影响运行
    ERROR 40 严重错误但程序能继续
    CRITICAL 50 致命错误导致程序退出
    import logging

logging.debug("详细的调试信息") # 开发时开启,生产时关闭
logging.info("用户登录成功") # 记录关键业务事件
logging.warning("磁盘剩余5%") # 提示需要关注的问题
logging.error("数据库查询失败") # 记录业务异常
logging.critical("系统崩溃") # 记录致命错误

  1. 灵活的输出控制
    import logging

基本配置:同时输出到控制台和文件

logging.basicConfig(
level=logging.INFO, # 只显示INFO及以上级别
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='app.log', # 输出到文件
filemode='a' # 追加模式
)

添加控制台输出

console = logging.StreamHandler()
console.setLevel(logging.DEBUG) # 控制台显示DEBUG及以上
formatter = logging.Formatter('%(levelname)s: %(message)s')
console.setFormatter(formatter)
logging.getLogger().addHandler(console)

  1. 模块化设计

    在不同模块中创建独立的logger

    module_a.py

    import logging
    logger = logging.getLogger(name) # 自动使用模块名作为标识
    logger.info("模块A初始化完成")

module_b.py

import logging
logger = logging.getLogger(name)
logger.debug("模块B的调试信息")

  1. 异常自动捕获
    try:
    1/0
    except Exception as e:
    logging.exception("发生异常:") # 自动记录完整堆栈

    等同于:

    logging.error("发生异常:", exc_info=True)

三、从print到logging的平滑过渡方案
方案1:快速替换(适合小型项目)

定义print的替代函数

def log_print(msg, level=logging.INFO):
logger = logging.getLogger(name)
if level == logging.DEBUG:
logger.debug(msg)
elif level == logging.INFO:
logger.info(msg)

# ...其他级别处理

使用示例

log_print("这条消息相当于print", logging.INFO)

方案2:完全迁移(推荐)
全局配置:在项目入口处配置logging

config_logging.py

import logging
from logging.handlers import RotatingFileHandler

def setup_logger():
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

# 控制台处理器
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)

# 文件处理器(按大小轮转)
fh = RotatingFileHandler(
    'app.log', maxBytes=1024*1024, backupCount=5
)
fh.setLevel(logging.DEBUG)

# 格式设置
formatter = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
ch.setFormatter(formatter)
fh.setFormatter(formatter)

logger.addHandler(ch)
logger.addHandler(fh)

模块中使用:

main.py

from config_logging import setup_logger
setup_logger()

import module_a
module_a.do_something()

module_a.py

import logging
logger = logging.getLogger(name)

def do_something():
logger.debug("进入do_something方法")
try:

    # 业务逻辑
    logger.info("操作成功完成")
except Exception as e:
    logger.error(f"操作失败: {str(e)}")

四、进阶技巧:让日志更专业

  1. 日志轮转(避免日志文件过大)
    from logging.handlers import TimedRotatingFileHandler

每天午夜轮转,保留7天日志

handler = TimedRotatingFileHandler(
'app.log', when='midnight', backupCount=7
)

  1. 结构化日志(便于ELK等系统分析)
    import re
    from logging import Filter

class SensitiveFilter(Filter):
def filter(self, record):

    # 过滤信用卡号等敏感信息
    record.msg = re.sub(r'\d{4}-\d{4}-\d{4}-\d{4}', '****-****-****-****', record.msg)
    return True

logger = logging.getLogger()
logger.addFilter(SensitiveFilter())

  1. 敏感信息过滤
    import re
    from logging import Filter

class SensitiveFilter(Filter):
def filter(self, record):

    # 过滤信用卡号等敏感信息
    record.msg = re.sub(r'\d{4}-\d{4}-\d{4}-\d{4}', '****-****-****-****', record.msg)
    return True

logger = logging.getLogger()
logger.addFilter(SensitiveFilter())

  1. 异步日志(提升性能)
    from logging.handlers import QueueHandler, QueueListener
    import queue
    import threading

log_queue = queue.Queue(-1) # 无界队列
queue_handler = QueueHandler(log_queue)

def handle_log_record(record):

# 实际的日志处理函数
logger = logging.getLogger()
logger.handle(record)

listener = QueueListener(log_queue, handle_log_record)
listener.start()

在主线程中使用

logger = logging.getLogger()
logger.addHandler(queue_handler)

五、常见问题解决方案
问题1:日志重复输出
原因:多次添加处理器或继承父logger的处理器

解决:

创建logger时设置propagate=False

logger = logging.getLogger('my_logger')
logger.propagate = False # 阻止向上传递日志

问题2:生产环境DEBUG日志过多
解决:使用环境变量动态控制级别

import os
import logging

LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO').upper()
logging.basicConfig(level=LOG_LEVEL)

问题3:多线程日志混乱
原因:多个线程同时写入日志

解决:logging模块默认是线程安全的,但需注意:

避免在多个线程中重复配置logging
使用logging.getLogger(name)获取logger实例
六、最佳实践总结
统一入口:在项目启动时集中配置logging
合理分级:DEBUG用于开发,INFO记录业务,WARNING/ERROR记录异常
模块化命名:使用name作为logger名称
格式规范:包含时间、模块名、日志级别等关键信息
输出多样:控制台+文件+远程日志服务组合使用
性能考量:高频日志考虑异步处理
安全过滤:避免记录密码、密钥等敏感信息
七、迁移路线图
第一阶段:替换所有控制台print为logging.info
第二阶段:添加文件输出和日志轮转
第三阶段:实现模块化日志和级别控制
第四阶段:引入结构化日志和监控集成
结语:日志是程序的记忆
从print到logging的升级,不仅是技术手段的进步,更是开发思维的转变。好的日志系统就像程序的"黑匣子",在出现问题时能快速定位原因,在正常运行时能监控健康状态。当你的项目规模从"能运行"迈向"可维护"时,就会深刻体会到logging模块带来的价值——它不仅是调试工具,更是程序可靠性的重要保障。

现在,打开你的项目,找到第一个print语句,让它光荣退休吧!

目录
相关文章
|
7月前
|
存储 调度 C++
16 倍性能提升,成本降低 98%! 解读 SLS 向量索引架构升级改造
大规模数据如何进行语义检索? 当前 SLS 已经支持一站式的语义检索功能,能够用于 RAG、Memory、语义聚类、多模态数据等各种场景的应用。本文分享了 SLS 在语义检索功能上,对模型推理和部署、构建流水线等流程的优化,最终带给用户更高性能和更低成本的针对大规模数据的语义索引功能。
611 61
|
监控 Kubernetes Go
日志采集效能跃迁:iLogtail 到 LoongCollector 的全面升级
LoongCollector 在日志场景中实现了全面的重磅升级,从功能、性能、稳定性等各个方面均进行了深度优化和提升,本文我们将对 LoongCollector 的升级进行详细介绍。
821 87
|
8月前
|
缓存 Java 应用服务中间件
Spring Boot配置优化:Tomcat+数据库+缓存+日志,全场景教程
本文详解Spring Boot十大核心配置优化技巧,涵盖Tomcat连接池、数据库连接池、Jackson时区、日志管理、缓存策略、异步线程池等关键配置,结合代码示例与通俗解释,助你轻松掌握高并发场景下的性能调优方法,适用于实际项目落地。
1536 5
|
安全 BI 网络安全
EventLog Analyzer 如何满足等保合规要求?密码有效期、产品日志保留、配置备份三大核心问题全面解答
EventLog Analyzer(ELA)助力企业满足网络安全等级保护要求,支持配置自动/手动备份、日志180天留存及密码策略管理,提升合规性与安全运营效率。
270 0
|
12月前
|
SQL 安全 算法
解读 Python 3.14:模板字符串、惰性类型、Zstd压缩等7大核心功能升级
Python 3.14 引入了七大核心技术特性,大幅提升开发效率与应用安全性。其中包括:t-strings(PEP 750)提供更安全灵活的字符串处理;类型注解惰性求值(PEP 649)优化启动性能;外部调试器API标准化(PEP 768)增强调试体验;原生支持Zstandard压缩算法(PEP 784)提高效率;REPL交互环境升级更友好;UUID模块扩展支持新标准并优化性能;finally块语义强化(PEP 765)确保资源清理可靠性。这些改进使Python在后端开发、数据科学等领域更具竞争力。
658 5
解读 Python 3.14:模板字符串、惰性类型、Zstd压缩等7大核心功能升级
|
11月前
|
存储 NoSQL MongoDB
Docker中安装MongoDB并配置数据、日志、配置文件持久化。
现在,你有了一个运行在Docker中的MongoDB,它拥有自己的小空间,对高楼大厦的崩塌视而不见(会话丢失和数据不持久化的问题)。这个MongoDB的数据、日志、配置文件都会妥妥地保存在你为它精心准备的地方,天旋地转,它也不会失去一丁点儿宝贵的记忆(即使在容器重启后)。
1378 4
|
10月前
|
JSON 安全 Go
Go语言项目工程化 —— 日志、配置、错误处理规范
本章详解Go语言项目工程化核心规范,涵盖日志、配置与错误处理三大关键领域。在日志方面,强调其在问题排查、性能优化和安全审计中的作用,推荐使用高性能结构化日志库zap,并介绍日志级别与结构化输出的最佳实践。配置管理部分讨论了配置分离的必要性,对比多种配置格式如JSON、YAML及环境变量,并提供viper库实现多环境配置的示例。错误处理部分阐述Go语言显式返回error的设计哲学,讲解标准处理方式、自定义错误类型、错误封装与堆栈追踪技巧,并提出按调用层级进行错误处理的建议。最后,总结各模块的工程化最佳实践,助力构建可维护、可观测且健壮的Go应用。
|
11月前
|
IDE 开发工具 Python
魔搭notebook在web IDE下,使用jupyter notebook,python扩展包无法更新升级
魔搭notebook在web IDE下,使用jupyter notebook,python扩展包无法更新升级,不升级无法使用,安装python扩展包的时候一直停留在installing
300 4
|
存储 监控 API
【Azure App Service】分享使用Python Code获取App Service的服务器日志记录管理配置信息
本文介绍了如何通过Python代码获取App Service中“Web服务器日志记录”的配置状态。借助`azure-mgmt-web` SDK,可通过初始化`WebSiteManagementClient`对象、调用`get_configuration`方法来查看`http_logging_enabled`的值,从而判断日志记录是否启用及存储方式(关闭、存储或文件系统)。示例代码详细展示了实现步骤,并附有执行结果与官方文档参考链接,帮助开发者快速定位和解决问题。
354 22
|
存储 安全 Python
[python]使用标准库logging实现多进程安全的日志模块
[python]使用标准库logging实现多进程安全的日志模块
792 1

推荐镜像

更多