0

0

python中如何使用logging模块记录日志?

裘德小鎮的故事

裘德小鎮的故事

发布时间:2025-09-14 21:49:01

|

415人浏览过

|

来源于php中文网

原创

Python的logging模块通过分级管理、多目标输出和结构化格式,提供比print更专业、灵活的日志解决方案,适用于从简单脚本到大型项目的各类应用场景。

python中如何使用logging模块记录日志?

Python的

logging
模块是一个功能强大且灵活的内置工具,它提供了一种标准化的方式来记录应用程序运行过程中的事件。简单来说,它能让你精细地控制日志信息的级别、输出目标(比如控制台、文件甚至是网络服务),以及它们的格式,这比单纯用
print
语句来调试要高级和专业得多。它不仅仅是打印,更是一种系统化的信息追踪和故障排查机制。

解决方案

要开始使用

logging
模块,最直接的方式就是通过
basicConfig
函数进行基本配置。这通常在你的应用程序入口点完成,它会为你设置一个默认的处理器(通常是
StreamHandler
,输出到控制台)和一个默认的格式。

import logging

# 配置日志系统:
# level=logging.INFO 设置了日志的最低级别,低于INFO的日志(如DEBUG)将不会被处理。
# format 定义了日志的输出格式,这里包含了时间、级别、日志名和消息。
# filename='app.log' 将日志输出到文件,而不是默认的控制台。
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(name)s - %(message)s',
                    filename='app.log',
                    filemode='a') # 'a'表示追加模式,'w'表示覆盖模式

# 获取一个日志器实例,通常推荐使用模块名作为日志器名称
logger = logging.getLogger(__name__)

# 使用不同级别的日志记录消息
logger.debug("这是一条调试信息,如果level是INFO,它将不会被记录。")
logger.info("程序启动了,一切正常。")
logger.warning("发现一个潜在的问题,但程序可以继续运行。")
logger.error("发生了一个错误,需要注意。")
logger.critical("发生了严重错误,程序可能无法继续运行!")

# 如果想同时输出到控制台,需要添加一个StreamHandler
# 这种情况下,basicConfig就不能直接设置所有东西了,需要更细致的配置
# 下面会详细解释

这段代码执行后,你会在当前目录下找到一个名为

app.log
的文件,里面记录了INFO、WARNING、ERROR和CRITICAL级别的日志信息。
basicConfig
是一个很方便的起点,但它也有局限性,比如一旦调用就很难再次修改,并且它只能配置一个根日志器。对于更复杂的场景,我们需要深入了解
Logger
Handler
Formatter

为什么在Python项目里,使用
logging
print
更靠谱?

我个人觉得,当你开始写超过几十行的脚本,或者任何打算在生产环境运行的代码时,

print
就显得力不从心了。它能让你看到一些东西,但仅此而已。
logging
模块则完全是另一个维度。

立即学习Python免费学习笔记(深入)”;

print
最大的问题是它的粗暴和不可控。你打印出来的信息,要么在,要么不在,没有中间地带。一旦部署到服务器上,你总不能一直盯着控制台吧?而
logging
能让你:

  1. 分级管理信息
    DEBUG
    ,
    INFO
    ,
    WARNING
    ,
    ERROR
    ,
    CRITICAL
    这些级别,让你能根据重要性筛选信息。开发时看
    DEBUG
    ,生产环境只看
    INFO
    WARNING
    以上,这太方便了。
  2. 灵活的输出目标:日志可以输出到文件、控制台、远程服务器、数据库,甚至是邮件。
    print
    只能到标准输出。想象一下,你的程序崩溃了,日志文件却记录了详细的堆栈信息,这比屏幕上闪过几行字有用太多了。
  3. 结构化和上下文
    logging
    可以轻松地在日志中加入时间戳、文件名、行号、函数名甚至线程ID,这些上下文信息对于排查问题至关重要。
    print
    你得手动拼接这些信息,既麻烦又容易出错。
  4. 性能考量:在生产环境中,大量的
    print
    语句可能会对性能造成不小的影响,尤其是在循环内部。
    logging
    在不满足日志级别要求时,会跳过大部分处理,开销小得多。
  5. 易于维护和扩展:通过配置,你可以随时调整日志的行为,而不需要修改代码。比如,临时提高某个模块的日志级别来调试一个特定问题,或者将所有
    ERROR
    日志发送到监控系统。
    print
    则意味着你得改代码,重新部署。

所以,与其说

logging
print
的替代品,不如说它是一个成熟的、工业级的解决方案,用于构建可观测、可维护的应用程序。

如何配置更复杂的日志输出,比如同时输出到文件和控制台?

basicConfig
无法满足你的需求时,就需要更细致地使用
logging
模块的核心组件:
Logger
(日志器)、
Handler
(处理器)和
Formatter
(格式器)。它们协同工作,提供了极大的灵活性。

一个

Logger
对象是日志系统的入口点,它负责接收日志请求。
Handler
决定了日志信息发送到哪里,而
Formatter
则定义了日志信息的显示格式。

import logging

# 1. 创建一个日志器实例
# 通常推荐使用__name__作为日志器的名称,这样可以创建分层的日志器
logger = logging.getLogger('my_app')
logger.setLevel(logging.DEBUG) # 设置日志器的最低处理级别

# 2. 创建一个控制台处理器 (StreamHandler)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO) # 控制台只输出INFO及以上级别的日志

# 3. 创建一个文件处理器 (FileHandler)
file_handler = logging.FileHandler('detailed_app.log', mode='a', encoding='utf-8')
file_handler.setLevel(logging.DEBUG) # 文件中记录所有DEBUG及以上级别的日志

# 4. 定义日志的格式器
# console_formatter 用于控制台,可以简洁一些
console_formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
# file_formatter 用于文件,可以包含更多细节
file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s')

# 5. 将格式器添加到处理器
console_handler.setFormatter(console_formatter)
file_handler.setFormatter(file_formatter)

# 6. 将处理器添加到日志器
logger.addHandler(console_handler)
logger.addHandler(file_handler)

# 尝试记录一些日志
logger.debug("这条调试信息只会出现在文件中。")
logger.info("程序正在执行关键步骤。")
logger.warning("发现一个配置问题。")
logger.error("一个严重的错误发生了,堆栈信息:", exc_info=True) # exc_info=True 会自动捕获异常信息

这段代码展示了如何为同一个

Logger
添加多个
Handler
,并且每个
Handler
可以有自己独立的日志级别和格式。这样,我们就能实现
DEBUG
级别的日志写入文件,而
INFO
及以上的日志同时输出到控制台,这在开发和生产环境中都非常实用。
exc_info=True
是一个很棒的特性,它能自动将当前异常的堆栈信息附加到日志中,这对于错误排查简直是神器。

科大讯飞-AI虚拟主播
科大讯飞-AI虚拟主播

科大讯飞推出的移动互联网智能交互平台,为开发者免费提供:涵盖语音能力增强型SDK,一站式人机智能语音交互解决方案,专业全面的移动应用分析;

下载

在大型项目中,如何优雅地管理多个模块的日志,避免日志信息混乱?

在大型项目中,日志的混乱是一个常见问题。不同的模块、不同的功能可能需要独立的日志输出策略,如果所有日志都混在一起,排查问题就成了大海捞针。Python的

logging
模块通过日志器层级结构传播机制来解决这个问题。

当你调用

logging.getLogger(name)
时,你实际上是获取了一个具有特定名称的日志器。这些日志器是分层的,它们之间通过点号
.
来表示父子关系。例如,
logging.getLogger('my_app.module_a')
logging.getLogger('my_app')
的子日志器。

关键点:

  1. 按模块命名日志器:最佳实践是在每个模块中都通过

    logger = logging.getLogger(__name__)
    来获取日志器。
    __name__
    是一个内置变量,它在每个模块中都是该模块的完全限定名(比如
    my_package.my_module
    )。这样做的好处是,你可以根据模块名来控制日志,例如,只提高
    my_app.database
    模块的日志级别。

  2. 日志传播(Propagation):子日志器发出的日志信息,默认情况下会“传播”到其父日志器,直到根日志器。这意味着,如果你在根日志器上配置了处理器,那么所有子日志器的日志都会经过这个处理器。

让我们看一个例子:

# main.py
import logging
import my_module

# 配置根日志器(或者一个顶层日志器)
root_logger = logging.getLogger() # 获取根日志器
root_logger.setLevel(logging.INFO)

# 创建一个文件处理器,用于记录所有INFO及以上级别的日志
file_handler = logging.FileHandler('project_logs.log')
file_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
root_logger.addHandler(file_handler)

# 创建一个控制台处理器,只输出WARNING及以上级别到控制台
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.WARNING)
console_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
root_logger.addHandler(console_handler)

# 获取主应用的日志器
app_logger = logging.getLogger('my_app')
app_logger.info("主应用启动中...")
app_logger.debug("这条DEBUG信息不会被根日志器处理,因为根日志器的level是INFO。") # 不会被记录到文件或控制台

# 调用模块中的函数
my_module.do_something()

# my_module.py
import logging

# 获取当前模块的日志器,它会是'my_module'这个名字
module_logger = logging.getLogger(__name__) # 这里的__name__就是'my_module'
module_logger.setLevel(logging.DEBUG) # 模块内部可以设置更低的级别,但最终会受父日志器限制

def do_something():
    module_logger.debug("my_module: 正在执行一些内部操作...")
    module_logger.info("my_module: 关键步骤完成。")
    try:
        1 / 0
    except ZeroDivisionError:
        module_logger.error("my_module: 发生了除零错误!", exc_info=True)

在这个例子中:

  • main.py
    中的
    app_logger
    (
    my_app
    )和
    my_module.py
    中的
    module_logger
    (
    my_module
    )都是根日志器(
    root_logger
    )的子日志器。
  • my_module
    DEBUG
    日志
    "my_module: 正在执行一些内部操作..."
    module_logger
    层级是可以被处理的,但因为它传播到了
    root_logger
    ,而
    root_logger
    的级别是
    INFO
    ,所以这条
    DEBUG
    日志最终不会被任何处理器记录。
  • INFO
    ERROR
    级别的日志则会通过
    root_logger
    file_handler
    写入文件,
    ERROR
    还会通过
    console_handler
    输出到控制台。

通过这种层级结构和传播机制,你可以为整个应用程序设置一个通用的日志策略,同时允许特定模块在需要时记录更详细(或更少)的信息。如果某个子日志器不需要将日志传播给父日志器,可以设置

logger.propagate = False
。这种分层管理,让大型项目的日志变得井井有条,易于追踪和维护。

相关文章

python速学教程(入门到精通)
python速学教程(入门到精通)

python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
python中print函数的用法
python中print函数的用法

python中print函数的语法是“print(value1, value2, ..., sep=' ', end=' ', file=sys.stdout, flush=False)”。本专题为大家提供print相关的文章、下载、课程内容,供大家免费下载体验。

186

2023.09.27

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

208

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

295

2023.10.25

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

395

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

575

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

395

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

575

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

502

2023.08.10

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.3万人学习

Django 教程
Django 教程

共28课时 | 3.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号