Python log() 函数(保姆级教程)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观

前言

在编程开发中,日志记录(Logging)是调试、监控和追踪程序行为的重要工具。对于 Python 开发者而言,logging 模块提供的 log() 函数是实现这一功能的核心方法。无论是初学者还是中级开发者,掌握 log() 函数的使用方式、配置方法和最佳实践,都能显著提升代码的健壮性和可维护性。本文将从基础概念到高级技巧,结合实例逐步解析 Python 的日志系统,帮助读者建立系统的日志记录思维。


一、日志记录的必要性与核心概念

1.1 为什么需要日志记录?

想象一个场景:当你开发一个电商系统时,用户突然报告“订单支付失败”,但系统没有报错提示。此时,如果没有日志记录,你可能需要逐行检查代码逻辑,甚至模拟用户操作来复现问题,这显然效率极低。而通过日志记录,开发者可以:

  • 追踪问题根源:记录程序运行过程中的关键步骤和异常。
  • 监控系统状态:实时观察流量、资源消耗或性能瓶颈。
  • 简化调试流程:快速定位错误发生的位置和条件。

1.2 Python 日志系统的层级结构

Python 的 logging 模块遵循标准的日志级别(Severity Levels),从低到高依次为:

  • DEBUG:调试信息,用于记录程序内部状态。
  • INFO:程序正常运行时的重要事件。
  • WARNING:可能引发问题的非致命异常。
  • ERROR:程序功能受损,但未完全崩溃。
  • CRITICAL:系统崩溃或无法继续运行。

比喻:日志级别可以理解为不同紧急程度的警报。DEBUG 是“小故障提醒”,CRITICAL 是“红色警报”,开发者根据优先级处理问题。


二、log() 函数的基础用法

2.1 快速入门:记录简单日志

通过 logging 模块的 log() 函数,可以按级别记录日志。以下是一个基础示例:

import logging  

logging.debug("This is a debug message")  
logging.info("This is an info message")  
logging.warning("This is a warning message")  
logging.error("This is an error message")  
logging.critical("This is a critical message")  

注意:默认情况下,只有 WARNING 及以上级别的日志会被输出到控制台。若需显示 DEBUGINFO,需要配置日志级别。

2.2 配置日志输出格式

默认的日志输出可能不够清晰。通过 basicConfig() 可以自定义格式和输出位置:

import logging  

logging.basicConfig(  
    level=logging.DEBUG,         # 设置最低输出级别  
    format="%(asctime)s - %(levelname)s - %(message)s",  
    filename="app.log",          # 将日志写入文件(可选)  
    filemode="w"                 # 文件写入模式(w:覆盖,a:追加)  
)  

logging.info("Custom format log")  

输出示例

2023-10-05 14:30:22,123 - INFO - Custom format log  

三、log() 函数的进阶用法

3.1 灵活控制日志输出

3.1.1 动态调整日志级别

在程序运行时,可以通过修改 logger 的级别动态调整日志输出:

logger = logging.getLogger("my_logger")  
logger.setLevel(logging.DEBUG)  # 运行时调整级别  

logger.log(logging.INFO, "This message will be shown")  

3.1.2 使用占位符格式化日志内容

通过 %sformat 方法,可以动态插入变量值:

user = "Alice"  
amount = 100.50  
logging.info("User %s has deposited $%.2f", user, amount)  

3.2 多处理器配置:输出到不同位置

3.2.1 控制台与文件同时输出

通过添加多个处理器(Handler),可以将日志同时输出到控制台和文件:

logger = logging.getLogger("multi_handler")  

console_handler = logging.StreamHandler()  
console_handler.setLevel(logging.ERROR)  

file_handler = logging.FileHandler("error.log")  
file_handler.setLevel(logging.WARNING)  

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

logger.error("This error will appear in both console and file")  

3.2.2 自定义日志格式

使用 Formatter 类可定义更复杂的日志格式:

formatter = logging.Formatter(  
    "%(asctime)s [%(levelname)s] %(name)s: %(message)s",  
    datefmt="%Y-%m-%d %H:%M:%S"  
)  

四、高级技巧与最佳实践

4.1 结构化日志:JSON 格式

将日志以 JSON 格式输出,便于后续分析和自动化处理:

import logging  
import json  

class JsonFormatter(logging.Formatter):  
    def format(self, record):  
        log_dict = {  
            "timestamp": record.asctime,  
            "level": record.levelname,  
            "message": record.getMessage(),  
            "module": record.module  
        }  
        return json.dumps(log_dict)  

json_formatter = JsonFormatter()  
handler = logging.StreamHandler()  
handler.setFormatter(json_formatter)  

logger = logging.getLogger("json_logger")  
logger.addHandler(handler)  
logger.info("Structured logging example")  

输出示例

{"timestamp": "2023-10-05 14:30:22,123", "level": "INFO", "message": "Structured logging example", "module": "__main__"}  

4.2 异常追踪与堆栈信息

记录异常时,结合 exc_info 参数可捕获完整堆栈信息:

try:  
    1 / 0  
except ZeroDivisionError:  
    logging.error("Division by zero occurred", exc_info=True)  

输出示例

ERROR:Division by zero occurred  
Traceback (most recent call last):  
  File "...", line 2, in <module>  
    1 / 0  
ZeroDivisionError: division by zero  

4.3 日志轮转与压缩

使用 logging.handlers.RotatingFileHandler 可自动管理日志文件大小:

from logging.handlers import RotatingFileHandler  

handler = RotatingFileHandler(  
    "app.log",  
    maxBytes=1024*1024*5,  # 5MB  
    backupCount=3          # 最多保留 3 个备份  
)  

五、常见问题与解决方案

5.1 问题1:日志未按预期输出

原因:未正确配置日志级别或处理器。
解决:检查 basicConfig()logger.setLevel() 的设置,并确认处理器是否已添加到 logger

5.2 问题2:日志文件被覆盖

原因filemode 参数设置为 w(覆盖模式)。
解决:将 filemode 改为 a(追加模式),或使用 RotatingFileHandler 自动管理。

5.3 问题3:多线程环境下的日志混乱

原因:默认配置下,日志可能因并发写入导致内容交错。
解决:使用线程安全的处理器或添加线程 ID 到日志格式中:

logging.basicConfig(  
    format="%(asctime)s - %(threadName)s - %(message)s"  
)  

六、总结与展望

通过本文,读者应已掌握 Python log() 函数的核心用法、配置技巧以及实际应用场景。日志记录不仅是调试的工具,更是系统运维和性能优化的“眼睛”。随着项目复杂度的提升,开发者可以进一步探索:

  • 分布式日志系统:通过工具如 ELK(Elasticsearch, Logstash, Kibana)集中管理日志。
  • 日志分析与告警:结合机器学习模型识别异常模式,提前预警系统故障。

记住,优秀的日志记录习惯能大幅降低维护成本。从今天起,为你的代码添加有意义的注释和结构化的日志信息吧!


(全文约 1600 字)

最新发布