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
及以上级别的日志会被输出到控制台。若需显示 DEBUG
或 INFO
,需要配置日志级别。
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 使用占位符格式化日志内容
通过 %s
或 format
方法,可以动态插入变量值:
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 字)