Python 中的日志记录(Logging)如何配置和使用?

Python日志记录通过logging模块实现,核心组件包括Logger、Handler、Formatter和Filter。使用basicConfig可快速配置,而复杂场景可通过自定义Logger和Handler将日志输出到控制台、文件或滚动文件。相比print,logging支持级别控制(DEBUG、INFO、WARNING、ERROR、CRITICAL),可灵活配置输出目标与格式,适用于调试、监控和生产环境。通过FileHandler写入文件,RotatingFileHandler按大小滚动,TimedRotatingFileHandler按时间滚动,实现高效日志管理。

python 中的日志记录(logging)如何配置和使用?

Python中的日志记录,核心在于通过

logging

模块建立一套结构化的信息捕获、处理和输出机制。它不仅仅是打印消息那么简单,更是一种系统性的管理,让你能够精细控制哪些信息在何时、何地、以何种形式被记录下来,这对于程序的调试、监控和后期维护至关重要。它提供了一种比

print

语句强大得多的方式来理解你的代码在做什么。

解决方案

要配置和使用Python的日志记录,你需要理解几个核心组件:

Logger

(记录器)、

Handler

处理器)、

Formatter

(格式器)和

Filter

(过滤器)。

最基础的用法,可以直接通过

logging.basicConfig()

来快速配置,这对于简单的脚本或开发环境非常方便:

import logging# 配置基本日志,将INFO级别及以上的消息输出到控制台logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')logging.debug('这是一条调试信息') # 不会显示,因为级别低于INFOlogging.info('程序启动了')logging.warning('检测到潜在问题')logging.error('发生了一个错误')logging.critical('系统崩溃!')

当你需要更复杂的控制时,比如将日志同时输出到文件和控制台,或者自定义不同的日志级别和格式,就需要手动创建和配置

Logger

Handler

Formatter

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

import logging# 1. 获取一个记录器实例logger = logging.getLogger('my_app')logger.setLevel(logging.DEBUG) # 设置记录器最低处理级别为DEBUG# 2. 创建一个文件处理器,用于将日志写入文件file_handler = logging.FileHandler('app.log', encoding='utf-8')file_handler.setLevel(logging.INFO) # 文件处理器只处理INFO及以上级别的日志# 3. 创建一个控制台处理器,用于将日志输出到控制台console_handler = logging.StreamHandler()console_handler.setLevel(logging.DEBUG) # 控制台处理器处理DEBUG及以上级别的日志# 4. 定义日志的格式formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')# 5. 将格式器添加到处理器file_handler.setFormatter(formatter)console_handler.setFormatter(formatter)# 6. 将处理器添加到记录器logger.addHandler(file_handler)logger.addHandler(console_handler)# 现在可以使用logger来记录日志了logger.debug('这条调试信息会出现在控制台')logger.info('这条信息会出现在文件和控制台')logger.warning('这是一个警告,也会出现在两处')try:    1 / 0except ZeroDivisionError:    logger.exception('除零错误发生!') # exception会自动记录堆栈信息

这段代码展示了如何细致地控制日志流向和内容。

getLogger

可以获取一个具名的记录器,这在大型应用中区分不同模块的日志非常有用。通过为不同的

Handler

设置不同的级别,我们可以实现日志分流,比如调试信息只在控制台显示,而重要的错误信息则同时写入文件。

为什么Python的logging模块比简单的print语句更具优势?

说实话,刚开始写Python脚本时,谁不是满屏的

print()

?快速、直接,看一眼就知道结果。但很快你就会发现,当程序规模稍微大一点,或者需要部署到生产环境时,

print()

的局限性就暴露无遗了。

logging

模块之所以是标准库,自有其道理。

首先,它提供了日志级别

DEBUG

,

INFO

,

WARNING

,

ERROR

,

CRITICAL

,这些级别让你能够区分信息的轻重缓急。你可以设置一个全局的阈值,比如在开发时显示所有

DEBUG

信息,而到了生产环境,只记录

INFO

WARNING

及以上的内容。

print()

可没这功能,它就是一股脑儿地输出。

其次,输出目标多样化

print()

只能往标准输出(通常是控制台)打印。但

logging

可以通过不同的

Handler

将日志发送到文件、网络(TCP/UDP)、邮件、HTTP服务器,甚至操作系统的日志系统。这在分布式系统或需要集中式日志管理的场景下,是

print()

望尘莫及的。想象一下,你的程序崩溃了,日志信息自动发送到你的邮箱,这比你盯着控制台找错误要高效得多。

再者,格式化输出

logging.Formatter

让你能自定义日志消息的格式,包含时间戳、日志级别、模块名、文件名、行号、函数名等等。这使得日志信息更具可读性和可追溯性。

print()

要实现这些,你得手动拼接字符串,既麻烦又容易出错。而且,

logging

还能自动处理多线程环境下的日志同步,避免输出混乱。

最后,也是我认为最关键的一点,

logging

提升了代码的可维护性和专业性。它强制你思考日志的用途和重要性,而不是随意地插入打印语句。当你的程序出现问题时,一份结构良好、信息丰富的日志远比一堆无序的

print

输出更能帮助你快速定位问题。它就像是程序运行的“黑匣子”,记录下关键的飞行数据,以便事后分析。

Python日志级别有哪些,如何选择合适的级别?

Python的

logging

模块定义了五个标准的日志级别,它们代表了事件的不同严重程度。理解这些级别并正确使用它们,是有效日志记录的关键。

DEBUG (10):这是最低的级别,用于详细的调试信息。通常只在开发阶段或需要深入排查问题时启用。比如,某个变量的值在特定代码点是什么,某个函数被调用时传入了什么参数。

logger.debug("处理用户请求,用户ID: %s", user_id)

INFO (20):用于确认程序按预期运行的事件。这些是程序正常运行时的“里程碑”信息,可以用来了解程序的整体流程。

logger.info("数据库连接成功")logger.info("任务调度器启动")

WARNING (30):表示发生了意外或将来可能出现问题的情况,但程序仍然能够正常运行。这通常是一些需要注意但不是致命的问题。

logger.warning("配置文件未找到,使用默认设置")logger.warning("缓存刷新失败,将尝试重试")

ERROR (40):由于某个严重的问题,程序无法执行某些功能。这通常意味着某个操作失败了,但整个应用程序可能还没有完全崩溃。

logger.error("文件写入失败:%s", file_path)logger.error("API调用返回错误状态码:%d", status_code)

CRITICAL (50):这是最高的级别,表示发生了非常严重的错误,导致程序本身或系统组件无法继续运行。通常需要立即采取行动。

logger.critical("数据库服务不可用,应用程序即将退出")logger.critical("内存溢出,系统崩溃!")

如何选择合适的级别?

选择日志级别更像是一种艺术,而非严格的科学。我的经验是,从目的出发。

开发阶段:我会把记录器级别设为

DEBUG

,甚至

DEBUG

以下(如果有自定义级别的话),这样我能看到所有细节。每一个分支、每一个变量的变化,都可能成为我调试的线索。测试环境:通常会设为

INFO

DEBUG

,根据测试的深度和对日志量的容忍度来决定。目标是捕获所有潜在问题,同时避免日志文件过大。生产环境:这是最需要谨慎的地方。通常将记录器级别设为

INFO

WARNING

INFO

用于记录关键业务流程的进展,

WARNING

用于提示潜在风险。

ERROR

CRITICAL

是必须捕获的,它们是系统健康状况的晴雨表。在生产环境,

DEBUG

级别的日志通常会被禁用,因为它会产生巨大的日志量,影响性能,并可能暴露敏感信息。

一个好的实践是,“宁滥勿缺”地记录,但“按需过滤”地输出。也就是说,在代码中,你可以在任何你觉得有用的地方打上

DEBUG

INFO

日志。但在实际运行中,通过配置

Handler

的级别来控制最终输出的日志量。这样,当你需要深入调试时,只需调整配置,就能获得更详细的信息,而不需要修改代码。

如何将日志输出到文件或滚动文件?

将日志输出到文件是日志记录最常见的需求之一,因为它提供了持久化的记录,便于事后分析和故障排查。而“滚动文件”机制则解决了日志文件无限增长的问题,避免占用过多磁盘空间。

1. 输出到单个文件 (

FileHandler

)

最直接的方式是使用

logging.FileHandler

。它会将所有日志写入一个指定的文件。

import logginglogger = logging.getLogger('file_logger')logger.setLevel(logging.DEBUG)# 创建一个文件处理器,指定日志文件路径和编码# 默认是'a'模式(追加),如果文件不存在则创建file_handler = logging.FileHandler('my_application.log', encoding='utf-8')file_handler.setLevel(logging.INFO) # 文件中只记录INFO及以上级别的日志formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')file_handler.setFormatter(formatter)logger.addHandler(file_handler)logger.debug("这条调试信息不会写入文件,因为文件处理器级别是INFO")logger.info("程序正常运行")logger.warning("磁盘空间可能不足")logger.error("致命错误发生")

这里需要注意的是,

FileHandler

默认以追加模式(

'a'

)打开文件。如果你希望每次程序启动都清空旧日志并重新开始,可以将

mode='w'

作为参数传递给

FileHandler

2. 输出到滚动文件 (

RotatingFileHandler

TimedRotatingFileHandler

)

当你的应用程序长时间运行,或者产生大量日志时,一个日志文件会变得非常大,这不仅难以管理,也可能耗尽磁盘空间。

RotatingFileHandler

TimedRotatingFileHandler

就是为解决这个问题而设计的。

RotatingFileHandler

:按文件大小滚动

这个处理器会在日志文件达到指定大小时,将其重命名(通常是加上

.1

,

.2

等后缀),然后创建一个新的空文件继续写入日志。它会保留指定数量的旧日志文件。

import loggingfrom logging.handlers import RotatingFileHandlerimport timelogger = logging.getLogger('rotating_logger')logger.setLevel(logging.DEBUG)# 创建一个滚动文件处理器# filename: 日志文件名# maxBytes: 单个日志文件最大字节数,例如 10 * 1024 * 1024 (10MB)# backupCount: 保留的旧日志文件数量rotating_handler = RotatingFileHandler(    'app_rotated.log', maxBytes=10 * 1024 * 1024, backupCount=5, encoding='utf-8')rotating_handler.setLevel(logging.INFO)formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')rotating_handler.setFormatter(formatter)logger.addHandler(rotating_handler)for i in range(1000): # 模拟写入大量日志    logger.info(f"这是第 {i} 条日志消息,程序正在正常运行。")    time.sleep(0.01) # 稍微暂停,以便观察文件滚动

app_rotated.log

达到10MB时,它会被重命名为

app_rotated.log.1

,然后创建一个新的

app_rotated.log

。当新的

app_rotated.log

再次达到10MB时,

app_rotated.log.1

会被重命名为

app_rotated.log.2

app_rotated.log

变为

app_rotated.log.1

,再创建一个新的

app_rotated.log

。这个过程会持续,直到达到

backupCount

的限制,最旧的文件会被删除。

TimedRotatingFileHandler

:按时间间隔滚动

如果你更希望日志文件按天、按小时或按分钟滚动,

TimedRotatingFileHandler

是更好的选择。

import loggingfrom logging.handlers import TimedRotatingFileHandlerimport timelogger = logging.getLogger('timed_rotating_logger')logger.setLevel(logging.DEBUG)# 创建一个按时间滚动的处理器# filename: 日志文件名# when: 滚动周期,例如 'h' (小时), 'd' (天), 'midnight' (每天午夜)# interval: 滚动间隔,例如 when='h', interval=1表示每小时滚动一次# backupCount: 保留的旧日志文件数量timed_rotating_handler = TimedRotatingFileHandler(    'app_timed.log', when='midnight', interval=1, backupCount=7, encoding='utf-8')timed_rotating_handler.setLevel(logging.INFO)formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')timed_rotating_handler.setFormatter(formatter)logger.addHandler(timed_rotating_handler)# 模拟日志写入for i in range(50):    logger.info(f"这是第 {i} 条定时滚动日志消息。")    time.sleep(0.5)
when

参数可以设置为:

's'

:秒

'm'

:分钟

'h'

:小时

'd'

:天

'w0'

'w6'

:每周的某一天(w0=周一)

'midnight'

:每天午夜

使用滚动文件处理器是生产环境中日志管理的标准做法。它既保证了日志的完整性,又有效地控制了磁盘使用,是应用程序稳定运行不可或缺的一部分。

以上就是Python 中的日志记录(Logging)如何配置和使用?的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1369780.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月14日 09:57:33
下一篇 2025年12月14日 09:57:52

相关推荐

  • 如何使用Python处理日期和时间(datetime模块)?

    datetime模块是Python处理日期时间的核心工具,提供date、time、datetime、timedelta和timezone等类,支持创建、格式化、解析及加减运算。通过datetime.now()获取当前时间,date.today()获取当前日期,strptime()从字符串解析时间,s…

    2025年12月14日
    000
  • Python 多线程与多进程的选择与实践

    答案:Python中多线程适用于I/O密集型任务,因线程在I/O等待时释放GIL,提升并发效率;多进程适用于CPU密集型任务,可绕过GIL实现多核并行。选择时需根据任务类型、数据共享需求、通信开销和资源消耗综合权衡,混合模式可用于复杂场景,同时注意避免竞态条件、死锁、僵尸进程等陷阱,合理使用线程池或…

    2025年12月14日
    000
  • 如何理解Python的Lambda函数?适用场景是什么?

    Lambda函数是匿名、单行函数,适用于简洁的回调场景,如map、filter、sorted中,与def函数相比,其无名、仅含表达式、不可多行,优势在简洁,劣势在复杂逻辑下可读性差,常见误区包括过度复杂化、误用语句和闭包陷阱,最佳实践是保持简单、用于高阶函数、优先选择列表推导式等更Pythonic的…

    2025年12月14日
    000
  • is 与 == 的区别:身份判断与值判断

    is 比较对象身份(内存地址),== 比较对象值。is 用于判断是否同一对象,如 is None;== 调用 eq 方法比较值,适用于值相等性判断。 is 与 == 的区别在于, is 比较的是两个对象的身份(在内存中的地址),而 == 比较的是两个对象的值。简单来说, is 看是不是同一个东西, …

    2025年12月14日
    000
  • Flask 的蓝本(Blueprint)与上下文机制

    蓝本是Flask模块化应用的结构工具,用于拆分功能组件、提升可维护性与复用性;上下文机制则通过请求上下文和应用上下文管理运行时数据,确保多线程下全局变量的安全访问,二者协同实现清晰架构与高效运行。 Flask的蓝本(Blueprint)是其模块化应用的核心工具,它允许我们将应用的不同功能部分拆分成独…

    2025年12月14日
    000
  • 谈谈你对Python设计模式的理解,并举例说明。

    设计模式在Python中是提升代码质量与团队协作效率的思维工具,其核心在于理解思想而非拘泥结构。Python的动态特性如鸭子类型、一等函数和装饰器语法,使得工厂、装饰器、策略等模式实现更简洁。例如,工厂模式解耦对象创建,装饰器模式通过@语法动态增强功能,策略模式利用接口隔离算法。相比传统实现,Pyt…

    2025年12月14日
    000
  • with 语句和上下文管理器(Context Manager)的原理

    with语句通过上下文管理器协议确保资源在进入和退出代码块时被正确初始化和清理,即使发生异常也能自动释放资源,从而避免资源泄漏;它通过__enter__和__exit__方法或contextlib的@contextmanager装饰器实现,使文件、数据库连接等资源管理更安全、简洁。 with 语句在…

    2025年12月14日
    000
  • 解释一下Python的生成器(Generator)和迭代器(Iterator)。

    生成器是创建迭代器的简洁方式,通过yield按需生成值,节省内存;迭代器通过__iter__和__next__实现遍历协议,支持惰性计算,适用于处理大文件、无限序列和构建数据管道,提升性能与资源利用率。 Python中的生成器(Generator)和迭代器(Iterator)是处理序列数据,尤其是大…

    2025年12月14日
    000
  • 字典(Dict)的实现原理与键值对存储机制

    字典的核心是哈希表,通过哈希函数将键映射为索引,实现高效存取;为解决哈希冲突,采用开放寻址法或链式法,Python使用开放寻址法变种;键必须不可变以确保哈希值稳定,避免查找失败;当填充因子过高时,字典触发扩容,新建更大哈希表并重新哈希所有元素,虽耗时但保障了平均O(1)性能。 字典(Dict)的核心…

    2025年12月14日
    000
  • 如何找出数组中出现次数超过一半的数字?

    摩尔投票算法能高效找出数组中出现次数超过一半的数字,其核心是通过抵消机制在O(n)时间与O(1)空间内锁定候选者,最终遍历验证其合法性。 要找出数组中出现次数超过一半的数字,最优雅且高效的方法无疑是摩尔投票算法(Moore’s Voting Algorithm)。它以一种巧妙的“抵消”机…

    2025年12月14日
    000
  • 如何找出列表中出现次数最多的元素?

    最直接的方法是使用哈希表统计元素频率,再找出最大值。遍历列表,用字典记录每个元素出现次数,然后遍历字典找出计数最大的元素。Python中可用collections.Counter优化实现,大规模数据可采用分块处理或数据库方案。 要找出列表中出现次数最多的元素,最直接也最常用的方法,就是先统计每个元素…

    2025年12月14日
    000
  • 如何用Python实现一个简单的Web服务器?

    Python内置http.server模块可快速搭建Web服务器,适合本地文件共享、教学演示等简单场景,优势是无需第三方库、实现便捷,但存在性能差、功能有限、安全性弱等局限,不适用于高并发或生产环境。通过继承BaseHTTPRequestHandler重写do_GET/do_POST方法可实现动态内…

    2025年12月14日
    000
  • 如何使用Python进行正则表达式匹配(re模块)?

    re模块是Python处理正则表达式的核心工具,提供re.search()(全文查找首个匹配)、re.match()(仅从字符串开头匹配)、re.findall()(返回所有匹配)、re.sub()(替换匹配项)和re.compile()(预编译提升性能)等关键函数;需注意使用原始字符串避免转义错误…

    2025年12月14日
    000
  • 如何实现Python的内存管理?

    Python内存管理依赖引用计数、垃圾回收和内存池。引用计数跟踪对象引用数量,引用为0时立即释放内存;但无法处理循环引用,因此引入垃圾回收机制,采用标记-清除和分代回收算法,定期检测并清除循环引用对象;同时通过Pymalloc内存池管理小内存块,减少系统调用开销,提升分配效率。三者协同工作,确保内存…

    2025年12月14日
    000
  • 如何读写文本文件和二进制文件?

    答案是文本文件以字符形式存储并依赖编码解析,二进制文件直接存储原始字节。读写时需区分模式(如’r’与’rb’),使用with语句管理资源,避免内存溢出需分块或逐行处理大文件,并注意编码、权限及模式错误。 读写文本文件和二进制文件,核心在于理解它们的数据…

    2025年12月14日
    000
  • 如何使用asyncio进行异步编程?

    asyncio通过协程实现单线程并发,适用于I/O密集型任务。使用async/await定义和调用协程,通过事件循环调度执行。可用asyncio.run()启动主协程,create_task()并发运行多个协程,gather()等待所有协程完成。异常处理需在await时捕获,未处理异常会存储于Tas…

    2025年12月14日
    000
  • 如何找到列表中的第二大元素?

    第二大元素可通过单次遍历或heapq模块高效获取。先处理元素不足或无差异情况,遍历时同步更新最大和第二大值,避免重复或无效比较。使用heapq.nlargest更Pythonic,代码简洁且基于优化堆实现,适合大多数场景。 找到列表中的第二大元素,核心思路是:先处理极端情况,然后遍历找到最大和第二大…

    2025年12月14日
    000
  • 列表(List)与元组(Tuple)的异同及选择依据

    列表可变,适用于需频繁修改的动态数据场景;元组不可变,确保数据安全,可用作字典键,适合固定数据集合。 列表(List)和元组(Tuple)在Python中都是序列类型,它们都用于存储一系列有序的元素。它们的核心区别在于可变性:列表是可变的,这意味着创建后可以修改其内容;而元组是不可变的,一旦创建,其…

    2025年12月14日
    000
  • 什么是Python的Type Hints?它有什么好处?

    Type Hints提升代码可读性、可维护性与开发效率,通过静态检查提前发现类型错误,增强IDE智能提示,且不影响运行时性能,可逐步引入大型项目,与单元测试互补而非替代,共同保障代码质量。 Python的Type Hints(类型提示)是一种在代码中声明变量、函数参数和返回值的预期类型的方式,但它并…

    2025年12月14日
    000
  • 装饰器(Decorator)的工作原理与手写实现

    装饰器是Python中通过函数闭包和语法糖实现功能扩展的机制,核心步骤包括定义外层接收函数、内层包装逻辑并返回wrapper;使用functools.wraps可保留原函数元信息;多个装饰器按从内到外顺序执行,适用于日志、权限等分层场景。 装饰器(Decorator),在我看来,是Python语言里…

    2025年12月14日
    000

发表回复

登录后才能评论
关注微信