Python|日志记录详解(1)

news2024/9/20 11:01:54
alt

引言

作为一名Python程序员,记录程序运行时的关键信息是一种有益的做法,这有助于深入理解你的代码。这种记录行为被称作日志记录,它是一个非常实用的工具,是编程工具箱中不可或缺的一部分。日志记录能够帮助你捕捉到在开发过程中可能忽略的情况。

这些记录被称作日志,它们就像始终监视应用程序运行的额外眼睛。日志能够记录哪些用户或IP地址访问了应用程序等信息。当程序出错时,日志提供的信息可能比错误堆栈跟踪更加丰富,它能够告诉你错误发生前程序的状态以及出错的具体代码行。

Python的标准库包含了一个日志系统。你只需几行代码,就可以在你的应用程序中实现日志功能。

在本教程中,你将学习以下内容:

  • 如何使用Python的日志模块
  • 如何配置基本的日志设置
  • 如何应用不同的日志级别
  • 如何使用格式化工具来美化你的日志消息
  • 如何使用处理器来改变日志的存储位置
  • 如何通过过滤器来定制日志规则

正确地记录关键数据,可以帮助你调试程序中的错误,分析应用的性能以便规划扩展,或者观察使用模式以制定市场策略。

如果您经常利用Python的 print() 函数来了解程序的执行流程,那么学习日志记录将是您自然而然的进阶选择。本教程[1]将带领您迈出记录日志的第一步,并告诉您如何随着项目的发展逐步完善日志功能。

Python 日志模块

Python 标准库中的日志模块是一个现成且功能强大的工具,它既适合编程新手,也能满足企业团队的需求。

日志模块的核心组件是所谓的日志记录器。你可以将日志记录器想象成一个你代码中的记录员,它负责决定记录哪些信息,信息的详细程度,以及这些信息的存储或发送目的地。

探索 Root Logger

要初步了解日志模块和日志记录器是如何工作的,你可以打开 Python 的标准交互式解释器(REPL),然后输入以下代码:

>>> import logging
>>> logging.warning("Remain calm!")
WARNING:root:Remain calm!

输出信息在每条日志消息前都会标明其严重性等级,以及“root”,这是日志模块为其默认日志记录器指定的名称。这种输出展示了日志的默认格式,您可以对其进行配置,以包含时间戳或其他额外信息。

在上述例子中,您向根日志记录器发送了一条消息,其日志等级被设置为“警告”。日志等级是日志记录中的关键组成部分。默认情况下,存在五个标准等级,用于区分事件的严重程度。每个等级都有对应的函数,您可以使用这些函数来记录相应严重程度的事件。

以下是五个默认日志级别(按严重性递增的顺序排列):

alt

日志模块配备了一个默认的日志记录器,这使得您可以轻松开始记录日志,无需进行复杂的配置。但是,如上表所示的日志函数暴露了一个可能出乎您意料的小特点:

>>> logging.debug("This is a debug message")

>>> logging.info("This is an info message")

>>> logging.warning("This is a warning message")
WARNING:root:This is a warning message

>>> logging.error("This is an error message")
ERROR:root:This is an error message

>>> logging.critical("This is a critical message")
CRITICAL:root:This is a critical message

请注意,debug()info() 级别的日志消息并没有被记录。这是因为日志模块默认情况下只记录 WARNING 及以上级别的日志信息。您可以通过调整日志模块的配置,使其能够记录所有级别的日志事件。

调整日志级别

要配置基本的日志设置并设定日志级别,日志模块包含了一个名为 basicConfig() 的函数。作为 Python 开发者,您可能会觉得这个函数的驼峰命名法有些不寻常,因为它不符合 PEP 8 的命名规范:

在本教程的后续部分,您将学习到 basicConfig() 的常用参数。目前,我们将重点放在 level 参数上,用它来设定根日志记录器的日志级别。

>>> import logging

>>> logging.basicConfig(level=logging.DEBUG)
>>> logging.debug("This will get logged.")
DEBUG:root:This will get logged.

利用 level 参数,您可以定义希望记录的日志消息的严重性级别。您可以通过指定类中预定义的常量来实现这一点。作为 level 参数,您可以选择使用该常量的直接值、它的数字形式,或者是对应的字符串形式。

alt

设置日志级别将启用定义级别及更高级别的所有日志记录调用。例如,当您将日志级别设置为 DEBUG 时,将记录所有处于或高于 DEBUG 级别的事件。

格式化输出

默认情况下,日志会记录日志级别、记录器名称和日志内容,这为日志记录提供了基础。但您可以通过 basicConfig() 函数中的 format 参数来丰富您的日志,加入更多数据。

format 参数允许您输入一个包含多个预设属性的字符串。您可以把这些属性想象成是您在字符串中设置的格式占位符。format 的默认设置格式大致如下:

>>> import logging
>>> logging.basicConfig(format="%(levelname)s:%(name)s:%(message)s")
>>> logging.warning("Hello, Warning!")
WARNING:root:Hello, Warning!

这种格式被称为 printf 风格字符串格式化。您也可能遇到使用美元符号和大括号(${})的日志格式,这与 Python 的 string.Template() 类相关。如果您熟悉现代 Python 中的字符串格式化方法,那么您可能更习惯于使用大括号({})来进行字符串的格式化。

您可以通过 style 参数来指定格式字符串的样式。style 可选用的值为 "%"、"$" 或 "{"。当您指定了 style 参数后,您的格式字符串就需要与所选样式一致。如果不一致,程序将抛出一个 ValueError 异常。

>>> import logging
>>> logging.basicConfig(format="{levelname}:{name}:{message}", style="{")
>>> logging.warning("Hello, Warning!")
WARNING:root:Hello, Warning!

正如之前提到的,format 参数允许您输入一个包含多个预设属性的字符串。您选择使用的属性将基于您希望从日志中获取的信息类型。

除了日志消息的文本和级别,通常在日志中包含时间戳也是一个好习惯。时间戳能够精确记录下程序发出日志消息的具体时间点。这有助于您监测代码的执行效率或者识别某些错误发生的规律。

要在日志中加入时间戳,您可以在调用 basicConfig() 时,在格式字符串中使用 asctime 属性。默认情况下,asctime 会显示包括毫秒在内的时间。如果您不需要这么详细的时间信息,或者您想要自定义时间戳的格式,那么您需要在 basicConfig() 函数调用中加入 datefmt 参数。

>>> import logging
>>> logging.basicConfig(
...     format="{asctime} - {levelname} - {message}",
...     style="{",
...     datefmt="%Y-%m-%d %H:%M",
... )

>>> logging.error("Something went wrong!")
2024-07-22 09:26 - ERROR - Something went wrong!

在上文的例子中,您的日志信息以时间戳作为开头。在 datefmt 字符串中,您使用特定的指令来设置时间戳的格式,这些指令包括年份(%Y)、月份(%m)、日期(%d)、小时(%H)和分钟(%M)。如果您想查看所有可用的日期指令,以便嵌入到格式字符串中,可以参考 time.strftime() 函数的官方文档。

当您需要记录一系列时间点上的事件,或者您打算将日志信息存储到外部文件中时,了解每条日志消息的具体时间就变得尤为关键。

记录到文件

到目前为止,您的日志信息仅输出到了控制台。如果您打算对日志进行归档,那么将它们保存到一个可以随着时间不断增长的文件中是明智的选择。

要实现日志文件的保存,您可以在配置日志记录器时,通过 basicConfig() 函数的 filename 参数来指定日志文件的路径。这与在 Python 中使用 open() 函数打开文件类似,您需要提供文件的存储路径。同时,指定文件的编码方式和打开模式也是推荐的做法。

>>> import logging
>>> logging.basicConfig(
...     filename="app.log",
...     encoding="utf-8",
...     filemode="a",
...     format="{asctime} - {levelname} - {message}",
...     style="{",
...     datefmt="%Y-%m-%d %H:%M",
... )

>>> logging.warning("Save me!")

使用上面的设置,您的日志信息会被存储到一个名为 app.log 的文件里,而不是输出到控制台。为了确保新日志追加到文件中而不是替换掉已有的内容,您应该将文件模式设置为 a,代表“追加”。

app.log 文件是一个普通的文本文件,您可以使用任何文本编辑器来查看或编辑它。

2024-07-22 09:55 - WARNING - Save me!

除了对日志记录进行格式化,将日志存储在以日期命名的文件夹中,并调整日志文件的命名也是一个不错的方法。您还可以尝试更具创造性的方式,比如将日志记录格式化为 CSV 文件的格式,这样您就可以保存日志并编写自己的程序来练习如何解析 CSV 文件。

显示变量

在大多数情况下,您希望在日志中包含应用程序的动态信息。您已经看到日志记录函数采用字符串作为参数。通过利用 Python 的 f 字符串,您可以创建包含变量信息的详细调试消息:

>>> import logging
>>> logging.basicConfig(
...     format="{asctime} - {levelname} - {message}",
...     style="{",
...     datefmt="%Y-%m-%d %H:%M",
...     level=logging.DEBUG,
... )

>>> name = "Samara"
>>> logging.debug(f"{name=}")
2024-07-22 14:49 - DEBUG - name='Samara'

首先,配置记录器并将调试级别设置为 DEBUG 以显示调试消息。然后,定义一个值为“Samara”的变量名称。使用自记录表达式,您可以通过在变量名称后附加等号 (=) 来在 f 字符串中插入变量名称及其值。

利用日志模块观察变量的当前值是应用调试初期的有效手段。如果您希望更深入地理解代码的运行情况,将异常信息记录到日志中会是一个合理的选择。

捕获堆栈跟踪

日志模块提供了捕获应用程序中完整堆栈跟踪的能力。当设置 exc_info 参数为 True 时,就可以记录异常信息,具体的日志记录函数调用方法如下:

>>> import logging
>>> logging.basicConfig(
...     filename="app.log",
...     encoding="utf-8",
...     filemode="a",
...     format="{asctime} - {levelname} - {message}",
...     style="{",
...     datefmt="%Y-%m-%d %H:%M",
... )

>>> donuts = 5
>>> guests = 0
>>> try:
...     donuts_per_guest = donuts / guests
... except ZeroDivisionError:
...     logging.error("DonutCalculationError", exc_info=True)
...

由于您正在登录 app.log 文件,因此您可以跟踪文件中的堆栈跟踪:

2024-07-22 15:04 - ERROR - DonutCalculationError
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

如果未将 exc_info 设置为 True,那么上述程序的输出将不会显示任何异常信息,在现实世界的应用中,这些异常可能远比一个除以零的错误(ZeroDivisionError)要复杂。

鉴于记录错误是一种常规操作,日志模块提供了一个便捷函数,可以减少您的代码输入量。如果您是在异常处理程序中进行日志记录——您将在后文中了解到更多细节——那么您可以使用 logging.exception() 函数。此函数会以错误(ERROR)级别记录一条消息,并将异常详情附加到这条消息上。

以下示例展示了如何使用 logging.exception() 函数来获得与之前相同的日志输出结果:

>>> try:
...     donuts_per_guest = donuts / guests
... except ZeroDivisionError:
...     logging.exception("DonutCalculationError")
...

使用 logging.exception() 函数的效果等同于使用 logging.error() 函数并设置 exc_info 参数为 True。因为这个函数总是会记录下异常信息,所以您应当仅在捕获到异常时调用它。

调用 logging.exception() 会生成一条错误级别的日志条目。如果您不希望以错误级别记录,您可以使用日志模块中其他级别的函数,比如 debug()info()warning()error()critical(),并在调用时将 exc_info 参数设置为 True,以便包含异常信息。

Reference
[1]

Source: https://realpython.com/python-logging/

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2073363.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

哈里和梅根的批评者似乎并不理解“不可征服运动会”的全球影响力

哈里王子和梅根马克尔的批评者似乎无法理解为什么这对夫妇继续像王室之旅一样环游世界。答案很简单&#xff1a;不可征服运动会。苏塞克斯夫妇通过这项体育赛事获得了成功&#xff0c;它为“国际受伤、受伤和生病的军人和女性提供了康复之路”。各国正在争夺未来运动会的主办权…

Photoshop用户必备:PS全套插件分享(PS插件全家桶)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 PS全套插件 📒🎈 获取方式 🎈⚓️ 相关链接 ⚓️📖 介绍 📖 你是否时常为Photoshop中复杂的操作流程感到困扰,渴望拥有一把钥匙,能瞬间解锁设计效率与创意的新世界?今天,我将给大家分享一款让众多设计师梦寐以求的…

Elasticsearch用法

&#x1f4a5; 该系列属于【SpringBoot基础】专栏&#xff0c;如您需查看其他SpringBoot相关文章&#xff0c;请您点击左边的连接 目录 一、初识elasticsearch 1. 安装Elasticsearch和Kibana 2. 倒排索引 3. IK分词器 4. 基础概念 二、索引库操作 1. Mapping映射属性 2…

IM项目:进阶版即时通讯项目---语音识别和验证码服务

文章目录 语音识别基本功能模块划分流程图实现逻辑解析proto文件 验证码服务 本篇主要是对于该项目的语音识别和验证码服务模块的一个梳理&#xff0c;项目会直接使用部分封装好的内容&#xff0c;可以查看前面的文档或在本文档中进行查看和学习 由于这两个模块非常相似&#…

模型 卡茨管理模型

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。技术、人际、概念&#xff1a;管理技能三支柱。 1 卡茨管理模型的应用 1.1 产品经理能力模型&#xff1a;基于卡茨管理模型的应用 在现代企业管理中&#xff0c;产品经理的角色越来越受到重视。根据…

HTML简单了解和基础知识记录

参考视频 html的用途 超文本标记语言&#xff08;英语&#xff1a;HyperText Markup Language&#xff0c;简称&#xff1a;HTML&#xff09;&#xff0c;用来显示网页的文字和框架结构&#xff0c;可以认为是网页的骨架。 标签/元素 用于定义文字图片连接等&#xff0c;分…

超简单Java邮件发送-为你的小程序实现邮箱验证码登录

本项目基于Apache Commons Email for Jakarta开发。 超简单实现邮箱发送&#xff0c;并以此扩展出邮箱验证码功能(请读者扩展实现)。 构建工具&#xff1a;Maven 演示邮箱&#xff1a;outlook 准备 请确保你的邮箱开启了SMTP服务&#xff0c;并获取相关参数&#xff0c;类似…

51单片机——模块化编程

1、模块化编程介绍 传统方式编程&#xff1a;所有的函数均放在main.c里&#xff0c;若使用的模块比较多&#xff0c;则一个文件内会有很多的代码&#xff0c;不利于代码的组织和管理&#xff0c;而且很影响编程者的思路。 模块化编程&#xff1a;把各个模块的代码放在不同的.…

诊断知识:agedDTCLimit的使用

文章目录 前言agedDTCLimit的定义agedDTCLimit的使用图解agedDTCLimit总结 前言 ECU中的存储空间一般无法将所有的DTC同时记录故障数据&#xff0c;所以故障发生之后记录的数据&#xff0c;需要在一段时间后未出现故障则自动清除&#xff0c;以保证新的故障出现时&#xff0c;…

苍穹外卖-day05(SpringBoot+SSM的企业级Java项目实战)

苍穹外卖-day05 课程内容 Redis入门 Redis数据类型 Redis常用命令 在Java中操作Redis 店铺营业状态设置 功能实现&#xff1a;营业状态设置 效果图&#xff1a; 选择营业中&#xff0c;客户可在小程序端下单&#xff1a; 选择打烊中&#xff0c;客户无法在小程序端下单&…

【Docker】Docker学习04 | dockerfile的编写

本文首发于 ❄️慕雪的寒舍 dockerfile是构建docker镜像的基础&#xff0c;它规定了一系列语法&#xff0c;让我们可以在某个基础镜像之上&#xff0c;添加自己需要的操作&#xff0c;打包出一个自己的镜像。 1. dockerfile基本语法 下面是dockerfile的基本语法和其对应的功能…

【算法进阶2-动态规划】斐波那契数列(递归调用、动态规划)、钢条切割问题(自定而下实现、自底向上、切割方案)

1 斐波那契数 2 钢条切割问题 2.1 最优解情况 2.2 钢条切割问题之自定而下实现 2.3 钢条切割问题之自底向上实现 2.4 钢条切割问题-重构解-切割方案 1 斐波那契数 # 1 子问题的重复计算 def fibonacci(n: int) -> int:"""使用递归方式计算第 n 个斐波那契数…

计算机毕业设计选题推荐-法律援助平台-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

有限差分学习笔记

有限差分介绍 ​ 在数学中&#xff0c;有限差分法&#xff08;finite-difference methods&#xff0c;简称FDM&#xff09;&#xff0c;是一种微分方程数值方法&#xff0c;是通过有限差分来近似导数&#xff0c;从而寻求微分方程的近似解。 由泰勒展开式的推导 显式方…

给Go+Sciter开发的桌面客户端软件添加系统托盘图标

在桌面端软件开发中&#xff0c;系统托盘图标是提升用户体验的重要元素。托盘图标不仅能提供直观的状态反馈&#xff0c;还能让软件在后台运行时依然保持与用户的交互。通过托盘图标&#xff0c;用户可以轻松最小化软件、退出程序&#xff0c;甚至弹出通知&#xff0c;从而避免…

【海外EI 会议合集】电网系统/绿色能源/新材料主题均可

第五届电网系统与绿色能源国际学术会议&#xff08;PGSGE 2025&#xff09; 2025 5th International Conference on Power Grid Systems and Green Energy 重要信息 会议官网&#xff1a;www.pgsge.org 会议时间&#xff1a;2025年1月10-12日 会议地点&#xff1a;马来西亚…

Linux 部署 MinIO(远程服务器)

1. 下载安装 进入 Linux 内 cd /usr/local/ # 新建目录 mkdir minio # 进入目录 cd minio # 下载地址 wget https://dl.min.io/server/minio/release/linux-amd64/minio# 授权 chmod x minio 2. 自定义配置 自定义账号与登录密码&#xff0c;直接在本目录 默认登录账号和…

【吊打面试官系列-Memcached面试题】memcached 能够更有效地使用内存吗?

大家好&#xff0c;我是锋哥。今天分享关于 【memcached 能够更有效地使用内存吗&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; memcached 能够更有效地使用内存吗&#xff1f; Memcache 客户端仅根据哈希算法来决定将某个 key 存储在哪个节点上&#xff0c;而…

ES的介绍和使用

全文搜索引擎 Elastic Search 第一节 引言 当系统数据量上了10亿、100亿条的时候&#xff0c;我们用什么数据库好&#xff1f;如何解决单点故障&#xff1f;如何提升检索速度&#xff1f;如何解决统计分析问题&#xff1f; 传统数据库的应对解决方案 关系型数据库 通过主从备…