首页 > 编程语言 >Python日志记录

Python日志记录

时间:2024-03-23 20:03:04浏览次数:25  
标签:logging 记录 Python message module 模块 日志 logger

Python的logging模块是一个内置的标准库,它为编写程序时生成、记录和管理日志信息提供了强大而灵活的功能。日志对于软件开发至关重要,尤其是在调试、监控应用状态、追踪异常行为、分析性能瓶颈以及审计等方面。

入门级的logging应用主要是掌握如何在简单的Python程序中引入logging模块,设置基本的日志级别,记录日志信息,并选择适当的输出目的地(如控制台)。本篇文章就讲一讲logging的入门到进阶:

目录

一、日志级别

二、组件与工作流程

三、基本使用示例

1、导入logging模块并配置日志记录器

2、创建日志记录器实例

3、记录日志信息

4、查看日志输出

5、保存日志到文件

四、进阶

1、自定义日志格式

2、设置日志记录器层次结构

3、使用不同的处理器

4、实现日志文件轮转

1)、使用 RotatingFileHandler 实现按文件大小轮转

2)、使用 TimedRotatingFileHandler 实现按时间间隔轮转


一、日志级别

logging模块定义了多个日志级别,按严重性递增排列如下:

  1. DEBUG: 提供详细的内部信息,用于调试目的。
  2. INFO: 记录常规的运行信息,如系统状态、用户行为等。
  3. WARNING: 表示潜在的问题或非预期的情况,但程序仍能继续运行。
  4. ERROR: 报告程序运行时发生的错误,导致某些功能无法正常工作。
  5. CRITICAL: 指示严重的故障或系统即将崩溃的情况。

每个级别都对应一个整数值,值越大表示严重性越高。日志消息会被分配一个级别,只有当它的级别等于或高于所设置的日志记录器(logger)的阈值时,才会被实际记录和处理。

二、组件与工作流程

logging模块的核心组件包括:

  • Logger: 用于收集和分发日志事件。每个logger对象代表了程序中的某个部分或模块,可以独立设置日志级别和添加处理器。日志消息首先被发送到相应的logger。
  • Handler: 负责将logger传递过来的日志消息输出到适当的目的地,如控制台、文件、数据库等。常见的Handler类型有StreamHandler(输出到流,如sys.stdout或sys.stderr)、FileHandler(写入文件)、SMTPHandler(发送电子邮件)等。每个handler可以有自己的日志级别和格式化器。
  • Formatter: 定义日志消息的输出格式,包括时间戳、日志级别、消息内容、源文件名和行号等信息。可以自定义格式字符串以满足特定需求。
  • Filter: 可选组件,用于对日志消息进行额外的筛选。可以基于特定条件决定是否让某条日志消息通过,进一步细化日志记录的控制。

日志消息的处理流程大致如下:

用户通过logger对象调用相应级别的方法(如logger.debug()、logger.info()等)记录日志。
如果该消息级别不低于logger的阈值,消息会被传递给所有关联的handler。
handler检查消息级别是否达到自己的阈值,如果是,则使用关联的formatter格式化消息,并将格式化后的消息发送到指定的目标。

三、基本使用示例

1、导入logging模块并配置日志记录器

对于简单应用,可以使用logging.basicConfig()进行快速全局配置。例如:

import logging

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')


logging.basicConfig(
    level=logging.INFO,  # 设置日志级别为INFO
    format='%(asctime)s - %(levelname)s - %(message)s',  # 设置日志格式
    datefmt='%Y-%m-%d %H:%M:%S',  # 设置时间格式
    stream=sys.stdout,  # 输出到标准输出(控制台)
)

在这个配置中:

  • level=logging.INFO:设置日志级别为INFO,这意味着DEBUG级别的日志将不会被记录。你可以根据需要调整为DEBUG、WARNING、ERROR等其他级别。
  • format='%(asctime)s - %(levelname)s - %(message)s':定义日志的输出格式,包含时间戳、日志级别和消息内容。%(asctime)s表示时间戳,%(levelname)s表示日志级别,%(message)s表示消息正文。
  • datefmt='%Y-%m-%d %H:%M:%S':指定时间戳的显示格式。
  • stream=sys.stdout:指定日志输出到标准输出(即控制台)。若要改为输出到标准错误(stderr),可以使用stream=sys.stderr。

指定了一个基本的日志格式,所有未显式配置的logger都将继承这些设置。

2、创建日志记录器实例

尽管basicConfig()已经设置了全局的日志行为,但对于更复杂的项目,通常建议创建特定的logger实例。这样可以为不同的模块或组件赋予独立的日志记录器,便于管理和区分日志来源。创建logger实例如下:

logger = logging.getLogger(__name__)

这里使用__name__作为logger的名称,它会自动填充为当前模块的名称,有助于在多模块环境中识别日志来源。就相当于给指定模块或者类加上标签,如果你的程序很大,可能希望不同的模块或类各自有日志记录,这样查起来更方便。

import logging

module_logger = logging.getLogger('MyModule')
module_logger.info('这是MyModule模块的日记')

这样,日记前面就有标签了,一看就知道是哪个部分写的。下面是一个简单的例子,展示如何为不同模块或类创建带标签的logger实例,并记录日志:

project/
│
├── main.py
├── module_a.py
└── module_b.py

#主程序结构示例

main.py (主程序):

import logging
import module_a
import module_b

# 基本日志配置
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    stream=sys.stdout,
)

# 调用模块A和模块B的功能
module_a.do_something()
module_b.do_something_else()

module_a.py (模块A):

import logging

# 创建模块A的日志记录器,标签为'module_a'
module_a_logger = logging.getLogger('module_a')

def do_something():
    module_a_logger.info('模块A开始执行操作...')
    # ... 执行具体操作 ...
    module_a_logger.info('模块A操作完成')

module_b.py (模块B):

import logging

# 创建模块B的日志记录器,标签为'module_b'
module_b_logger = logging.getLogger('module_b')

def do_something_else():
    module_b_logger.info('模块B开始执行操作...')
    # ... 执行具体操作 ...
    module_b_logger.info('模块B操作完成')

在这个例子中:

  • main.py 是主程序,导入了模块module_a和module_b,并进行了基本的日志配置。配置中使用%(name)s来显示日志记录器的名称(即标签)。
  • module_a.py 和 module_b.py 分别代表两个不同的模块。在每个模块中,我们创建了一个带有特定标签的logger实例(如module_a_logger和module_b_logger),标签对应模块的名称。
  • 模块中的函数(如do_something()和do_something_else())在执行关键操作前后,使用各自的logger实例记录日志信息,标签确保了日志消息能够明确标识出它们来自哪个模块。

当你运行main.py时,控制台会输出类似这样的日志:

2024-08-9 10:00:00 - module_a - INFO - 模块A开始执行操作...
2024-08-9 10:00:01 - module_a - INFO - 模块A操作完成
2024-08-9 10:00:02 - module_b - INFO - 模块B开始执行操作...
2024-08-9 10:00:03 - module_b - INFO - 模块B操作完成

每个日志消息都带有标签(如module_amodule_b),清晰地表明了它们分别来自哪个模块。这种做法有助于你在查看日志时快速定位问题所在,特别是在大型项目中,具有显著的便利性。

3、记录日志信息

有了配置好的logger实例,就可以在代码中使用不同级别的方法来记录日志了。例如:

logger.debug('This is a debug message.')
logger.info('This is an info message.')
logger.warning('This is a warning message.')
logger.error('This is an error message.')
logger.critical('This is a critical message.')

这些方法对应于之前设置的日志级别。只有级别等于或高于已设置日志级别的消息才会被实际记录和输出。

4、查看日志输出

运行程序,你会在控制台看到类似这样的日志输出:

2024-03-22 15: - This is an info message.
2024-03-22 15:22:34 - WARNING - This is a warning message.
2024-03-22 15:22:34 - ERROR - This is an error message.
2024-03-22 15:22:34 - CRITICAL - This is a critical message.

5、保存日志到文件

如果希望将日志保存到文件而不是仅输出到控制台,可以使用FileHandlerstream=sys.stdout。修改basicConfig()如下:

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    filename='app.log',  # 将日志保存到文件'app.log'
)

现在,日志信息将被写入到指定的app.log文件中,而不是控制台。

四、进阶

随着对logging模块的深入使用,可以进一步学习和应用更复杂的日志处理技术,如自定义日志格式、使用不同的处理器、设置日志记录器层次结构、实现日志文件轮转等等。

1、自定义日志格式

自定义日志格式是指在使用Python的logging模块时,根据实际需求更改日志消息的输出样式。这可以通过创建一个logging.Formatter对象并设置其格式字符串来实现。格式字符串使用特殊的占位符(如%(asctime)s%(levelname)s等)来插入日志消息中的不同属性。以下是如何自定义日志格式的实例:

import logging

# 创建自定义格式器
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(name)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S')

# 创建Handler,将Formatter与之关联
console_handler = logging.StreamHandler()  # 输出到控制台
console_handler.setFormatter(formatter)

# 获取或创建Logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)  # 设置日志级别

# 将Handler添加到Logger
logger.addHandler(console_handler)

# 记录日志
logger.debug('This is a debug message.')
logger.info('This is an info message.')
logger.warning('This is a warning message.')
logger.error('This is an error message.')
logger.critical('This is a critical message.')

运行这段代码,你将在控制台看到按照自定义格式输出的日志消息。同样,如果使用了FileHandler,日志消息将以同样的格式写入指定的文件。通过这种方式,你可以根据项目需求灵活调整日志的输出样式,使其更加符合团队约定或易于后期分析。

logging.Formatter传入自定义的格式字符串,格式字符串中可以包含以下常用的占位符:

  • %(asctime)s: 时间戳。默认格式类似2003-07-08 16:49:45,896,可以通过datefmt参数进一步自定义。
  • %(levelname)s: 日志级别名称,如DEBUGINFOWARNINGERRORCRITICAL
  • %(name)s: 记录器名称(即logger实例的名称)。
  • %(message)s: 日志消息正文。
  • %(module)s: 发出日志消息的模块名。
  • %(funcName)s: 发出日志消息的函数名。
  • %(lineno)d: 发出日志消息的源代码行号。
  • %(thread)d 或 %(threadName)s: 当前线程ID或名称。
  • %(process)d 或 %(processName)s: 当前进程ID或名称。
  • 其他自定义字段(如果在日志记录时添加了额外的元数据)。

2、设置日志记录器层次结构

logging模块中的日志记录器(logger)支持层次结构的概念,这意味着记录器可以组织成一个树状结构,通过名称的点分隔表示父子关系。这种层次结构使得日志管理更为灵活,允许在不同粒度上设置日志级别、过滤规则等配置。以下是设置日志记录器层次结构的步骤和示例:

import logging

# 创建处理器,输出到控制台
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)  # 控制台只输出INFO及以上级别

# 设置根记录器级别为INFO
root_logger = logging.getLogger()
root_logger.setLevel(logging.INFO)
root_logger.addHandler(console_handler)

# 模块A记录器,级别为DEBUG
module_a_logger = logging.getLogger('module_a')
module_a_logger.setLevel(logging.DEBUG)  # 模块A记录更详细的日志

# 模块A内部子模块记录器,继承模块A的级别
module_a_submodule_logger = logging.getLogger('module_a.submodule')

# 使用记录器记录日志
module_a_logger.debug('Debug message from module A')
module_a_submodule_logger.info('Info message from submodule of module A')

运行这段代码,控制台将只输出module_a.submoduleinfo消息,因为这是唯一高于处理器级别(INFO)的日志。module_adebug消息虽然其记录器级别允许,但由于处理器级别限制,不会被输出。

通过这样的层次结构设置,可以方便地在不同层级上管理日志记录,如全局设置根记录器的级别以控制整体日志输出量,然后在特定模块或子系统中细化日志级别以获取更多调试信息。这种结构也使得日志过滤、路由到不同输出目的地等操作更加灵活和高效。

3、使用不同的处理器

使用不同的处理器(Handler)可以让Python的logging模块将日志消息输出到多种不同的目的地,如控制台、文件、电子邮件、数据库等。每个处理器负责一种特定的输出方式,并且可以独立配置其日志级别、输出格式和过滤条件。以下是使用不同处理器的步骤和示例:

import logging
from logging import handlers

# 创建处理器
console_handler = logging.StreamHandler()
file_handler = logging.FileHandler('application.log')

# 设置处理器级别
console_handler.setLevel(logging.INFO)
file_handler.setLevel(logging.DEBUG)

# 创建并设置格式器
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(name)s: %(message)s')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)

# 获取或创建记录器
logger = logging.getLogger('my_application')

# 添加处理器
logger.addHandler(console_handler)
logger.addHandler(file_handler)

# 使用记录器记录日志
logger.debug('Debug message')
logger.info('Info message')
logger.warning('Warning message')
logger.error('Error message')
logger.critical('Critical message')

运行这段代码,INFO及以上级别的日志消息将输出到控制台,而所有级别的日志消息(包括DEBUG)都将写入到application.log文件中。通过使用不同的处理器,可以将日志消息路由到多种目的地,以满足不同的监控、分析和归档需求。

常见的处理器类型包括:

  • logging.StreamHandler: 输出到标准输出(sys.stdout)或标准错误(sys.stderr)。
  • logging.FileHandler: 将日志写入到指定的文件。
  • logging.handlers.RotatingFileHandler: 当文件达到一定大小时,自动创建新的日志文件,并可选择保留旧文件。
  • logging.handlers.TimedRotatingFileHandler: 按照固定时间间隔(如每天、每周)自动创建新的日志文件。
  • logging.handlers.SMTPHandler: 发送日志邮件。
  • logging.handlers.HTTPHandler: 将日志发送到HTTP服务器。

4、实现日志文件轮转

日志文件轮转(log file rotation)是一种常见的日志管理策略,当日志文件达到一定大小或达到特定时间点时,自动创建新的日志文件,同时可以保留旧日志文件以供后续查阅或归档。在Python的logging模块中,可以使用logging.handlers.RotatingFileHandlerlogging.handlers.TimedRotatingFileHandler来实现日志文件轮转。以下是两种方式的实现示例:

1)、使用 RotatingFileHandler 实现按文件大小轮转

RotatingFileHandler会在日志文件达到指定大小时自动创建新的日志文件。你可以设置最大文件大小、备份文件数量以及备份文件名的模式:

import logging
from logging.handlers import RotatingFileHandler

# 创建RotatingFileHandler实例
rotating_handler = RotatingFileHandler('app.log', maxBytes=10_000_000, backupCount=5)

# 设置处理器级别、格式器等
rotating_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(name)s: %(message)s')
rotating_handler.setFormatter(formatter)

# 获取或创建记录器
logger = logging.getLogger('my_app')

# 添加处理器
logger.addHandler(rotating_handler)

# 使用记录器记录日志
logger.debug('Debug message')
logger.info('Info message')
logger.warning('Warning message')
logger.error('Error message')
logger.critical('Critical message')

在这个例子中:

  • RotatingFileHandler('app.log', maxBytes=10_000_000, backupCount=5) 创建了一个RotatingFileHandler,指定主日志文件名为app.log,当文件大小达到10MB时触发轮转,最多保留5个备份文件。
  • 当日志文件达到最大大小时,RotatingFileHandler会自动创建一个新文件(如app.log.1),并将当前app.log重命名为app.log.2(如果存在app.log.1,则依次向后重命名)。依此类推,直至达到备份文件数量上限,超出的最旧文件将被删除。

2)、使用 TimedRotatingFileHandler 实现按时间间隔轮转

TimedRotatingFileHandler会在指定的时间间隔到达时自动创建新的日志文件。你可以设置轮转周期(如按小时、天、周、月等),以及备份文件的模式:

import logging
from logging.handlers import TimedRotatingFileHandler

# 创建TimedRotatingFileHandler实例
timed_rotating_handler = TimedRotatingFileHandler('app.log', when='midnight', backupCount=7)

# 设置处理器级别、格式器等
timed_rotating_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(name)s: %(message)s')
timed_rotating_handler.setFormatter(formatter)

# 获取或创建记录器
logger = logging.getLogger('my_app')

# 添加处理器
logger.addHandler(timed_rotating_handler)

# 使用记录器记录日志
logger.debug('Debug message')
logger.info('Info message')
logger.warning('Warning message')
logger.error('Error message')
logger.critical('Critical message')

在这个例子中:

  • TimedRotatingFileHandler('app.log', when='midnight', backupCount=7) 创建了一个TimedRotatingFileHandler,指定主日志文件名为app.log,每天午夜(midnight)触发轮转,最多保留7个备份文件。
  • 当轮转时间点到达时,TimedRotatingFileHandler会自动创建一个新文件(如app.log.2024-0¾-10),并将当前app.log重命名为备份文件。依此类推,直至达到备份文件数量上限,超出的最旧文件将被删除。

通过使用RotatingFileHandler或TimedRotatingFileHandler,可以根据实际需求轻松实现日志文件的轮转,避免单个日志文件过大,同时保留历史日志以供查阅或归档。

希望该篇文章能有效帮助大家理解应用logging模块~

标签:logging,记录,Python,message,module,模块,日志,logger
From: https://blog.csdn.net/qq_52758588/article/details/136972944

相关文章

  • python-day02
    python判断语句if、elif、elseif条件:结果elif条件:结果else条件:结果随件数产生importrandom#随机产生1-10的随机数num=random.randint(1,10)while循环while条件:循环体eg:while循环实现九九乘法表i=1whilei<=9:j=1whi......
  • python实现列1的数据补充到列2
    具体代码(我是以一个数据较少的csv文件做了测试,具体的csv文件需要修改部分代码才能顺利实现)importpandasaspddf01=pd.read_csv("D:\\12140\\Desktops\\111\\333\\333.csv",encoding="utf-8",dtype="str")data=df01['新增'].fillna('no_zeng......
  • python环境搭建及特定操作系统注意事项
    文章目录搭建Python环境通用的流程:**1.下载并安装Python解释器****2.验证安装****3.安装包管理器(pip)****4.安装必要的开发工具****5.创建虚拟环境(推荐)****6.安装项目所需的库****7.配置IDE/编辑器**特定操作系统(如Windows、macOS、Linux)的特定步骤或注意事项**Wi......
  • Python虚拟环境conda的安装使用
    文章目录conda虚拟环境的详细步骤和注意事项:**安装Conda****创建Conda虚拟环境****激活Conda虚拟环境****安装Python包****管理Conda环境****其他优势与特性**相较于`venv`,使用`conda`管理虚拟环境有以下优势:**性能****资源占用****其他性能与资源相关因素****结论**......
  • 2024华为OD统一考试(C卷)最新题库(Java & Python & C++)
    关于华为OD​华为的员工补充途径有三种,分别是校招、OD转正和社招。校招是华为唯一的正式员工入职途径,但是从近几届开始竞争非常激烈,尤其是在CV、AI、NLP等赛道上,所以对于C9等专业的学生来说,可以考虑转向一些冷门方向。​OD转正是指在华为工作满一年之后,可以根据部门OD......
  • 【LeetCode 552】学生出勤记录II
    题目描述原题链接:LeetCode.552学生出勤记录II解题思路根据题意,缺勤天数最多只有一天,迟到最多只能连续两天,可以按末尾两个字符状态作为DP数组含义的不同维度往后递推长度增长时的数量值。dp[i][j]中的i表示长度为i的出勤记录,j表示末尾字符状态:j的值含义0无......
  • python小白学习笔记Mac版本
    和win系统的不同之处python的cmd验证在win系统中,只需要输入python就可以得到相关python的版本信息但是在mac系统中,需要输入python3.12(3.12是具体版本的号码)只输入python和pip也显示找不到相关文件(已经成功的安装前提下)只有输入第三行代码python3.12才会显示pyth......
  • MyBatis记录
    什么是MyBatis(1)Mybatis是一个半ORM(对象关系映射)框架,它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。(2)MyBatis可以使用XML或注解来配置和映射......
  • python合并多个csv文件需要注意的问题(合并多个列名问题)
    问题描述起初我使用python语言合并多个csv文件时,存在这几个csv文件有不止一个列名相同,仅仅依靠一个列名内容进行合并;就很容易造成相同列名对应相同内容分别占据了两个列,感官极为不好,还会影响到后面的数据清洗;问题解决#在on的这里加一个中括号,这样就能够同时包括多个列名,依据......
  • 使用python登录boss 并自动投递简历打招呼
    使用的是selenium4的和3的版本语法有点出入但是大差不差暂时还没有完善会持续更新fromseleniumimportwebdriverimporttimefromselenium.webdriver.common.byimportByfromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supp......