目录

一、Python Logging 模块概述

二、相关组件

Logger

Handler

Formatter

Filter

LogRecord

Level

三、基本配置

Formatters格式:

四、记录日志

五、日志记录者(Loggers)

logging.getLogger(name=None)

六、处理器(Handlers)

logging.Handler()

RotatingFileHandler和TimedRotatingFileHandler:

七、进阶使用

日志消息的过滤

日志流的重定向

日志的异步写入

八、propagate属性

九、结论


一、Python Logging 模块概述

logging模块是Python的标准库的一部分,它使得追踪事件、诊断问题和调试应用程序变得容易。它提供了不同的日志级别,如DEBUG、INFO、WARNING、ERROR和CRITICAL,这可以帮助开发者根据重要性区分日志消息。

二、相关组件

在Python的logging模块中,有几个重要的组件构成了日志系统的基础。下表概述了这些组件以及它们的作用:

三、基本配置

Formatters格式:

下面是一个logging.basicConfig的使用示例:

import logging

# 配置日志记录器
logging.basicConfig(
    filename='example.log',
    filemode='w',
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    level=logging.DEBUG
)

# 记录日志
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')

在这个示例中,我们使用 logging.basicConfig 方法自定义了日志记录行为,将日志记录到文件 example.log 中,使用追加模式,指定了输出格式和时间格式,将日志级别设置为 DEBUG。最后,我们记录了不同级别的日志消息。

四、记录日志

配置完成后,可以使用不同的日志级别方法来记录消息:

logging.debug('这是一个debug信息')
logging.info('这是一个info信息')
logging.warning('这是一个warning信息')
logging.error('这是一个error信息')
logging.critical('这是一个critical信息')

五、日志记录者(Loggers)

logging.getLogger(name=None)

每个Logger都可以有独立的日志级别、处理器和格式化器。这样可以灵活配置日志信息的记录方式。例如:

import logging

# 获取名为'my_logger'的Logger
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG) # 设置日志级别为DEBUG

# 创建一个Handler来将日志写入文件
file_handler = logging.FileHandler('my_logger.log')
file_handler.setLevel(logging.ERROR) # 该Handler只记录ERROR及以上级别的日志

# 创建一个Handler来将日志输出到控制台
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO) # 控制台仅记录INFO及以上级别的日志

# 设置日志格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)

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

# 使用不同的日志级别记录消息
logger.debug('这是一条DEBUG级别的消息')  # 不会被任何处理器记录,因为它低于它们的设置级别
logger.info('这是一条INFO级别的消息')    # 会被console_handler处理并显示在控制台
logger.warning('这是一条WARNING级别的消息')  # 会被console_handler处理并显示在控制台
logger.error('这是一条ERROR级别的消息')    # 会被file_handler和console_handler处理,并记录到文件和控制台
logger.critical('这是一条CRITICAL级别的消息') # 同上

六、处理器(Handlers)

如果要将日志记录发送到不同的目的地,比如文件或者网络,就需要使用处理器(Handlers)。每个处理器可以有自己的日志级别,格式化器(Formatter)和过滤器(Filter)。

logging.Handler()

每个Handler可以有自己的日志级别和格式化器。如果不显式设置Handler级别,它将默认处理所有级别的日志。例如:

# 创建一个文件处理器,并设置级别为ERROR
file_handler = logging.FileHandler('error.log')
file_handler.setLevel(logging.ERROR)

# 创建一个格式化器,并设置相应的格式
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)

# 将处理器添加到记录者
logger.addHandler(file_handler)

# 这条ERROR级别的信息将被写入'error.log'文件中
logger.error('这是一个error信息')

RotatingFileHandler和TimedRotatingFileHandler:

RotatingFileHandler会按照一定的规则(比如文件大小或保留的文件数量)来自动滚动日志文件,从而避免单个文件过大或存储过多历史日志的问题。当达到指定条件时,RotatingFileHandler会自动将当前日志文件重命名为旧的备份文件,并创建一个新的日志文件来记录最新的日志消息。可以使用maxBytes和backupCount两个参数来控制每个日志文件的最大大小和保存的备份文件数目。

例如,下面是一个使用RotatingFileHandler的示例:

import logging
from logging.handlers import RotatingFileHandler


logger = logging.getLogger(__name__)


# 创建RotatingFileHandler对象,设置日志输出路径、最大文件大小和备份数量
handler = RotatingFileHandler('mylog.log', maxBytes=1024*1024, backupCount=5)


# 设置日志级别和输出格式
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)


# 将处理器添加到日志记录器中
logger.addHandler(handler)


# 记录日志
logger.info("This is a test message")

与RotatingFileHandler不同,TimedRotatingFileHandler会按照一定的时间间隔来自动滚动日志文件,从而避免存储过多历史日志的问题。TimedRotatingFileHandler会根据指定的时间间隔(比如每小时、每天或每周)创建新的日志文件,并将当前日志消息写入到这个最新的日志文件中。可以使用when和interval两个参数来控制时间间隔。

例如,下面是一个使用TimedRotatingFileHandler的示例:

import logging
from logging.handlers import TimedRotatingFileHandler


logger = logging.getLogger(__name__)


# 创建TimedRotatingFileHandler对象,设置日志输出路径、时间间隔和备份数量
handler = TimedRotatingFileHandler('mylog.log', when='D', interval=1, backupCount=5)


# 设置日志级别和输出格式
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)


# 将处理器添加到日志记录器中
logger.addHandler(handler)


# 记录日志
logger.info("This is a test message")

#在这个示例中,我们使用TimedRotatingFileHandler创建一个每天滚动一次的日志文件,最多保留5个历史日志文件。当时间间隔到达时,TimedRotatingFileHandler会自动将当前日志文件重命名为旧的备份文件,并创建一个新的日志文件来记录最新的日志消息。

七、进阶使用

日志系统的高级功能包括日志消息的过滤、日志流的重定向以及日志的异步写入等。可以利用过滤器按照具体需求筛选日志信息,或者创建自定义的日志处理器来扩展其功能。

日志消息的过滤

过滤器(Filter)可用于对日志消息进行额外的控制,它允许更精细的日志消息输出。比如,你可能只想记录特定条件下的日志消息。

import logging

class InfoFilter(logging.Filter):
    def filter(self, record):
        return record.levelno == logging.INFO

logger = logging.getLogger('my_advanced_logger')
logger.setLevel(logging.DEBUG)

# 创建一个流处理器,并设置级别为DEBUG
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)

# 为流处理器设置过滤器,只记录INFO级别的日志
stream_handler.addFilter(InfoFilter())

# 为logger添加处理器
logger.addHandler(stream_handler)

# 下面的日志中,只有INFO级别的日志会被输出
logger.debug('这是一个debug信息')
logger.info('这是一个info信息')
logger.warning('这是一个warning信息')
logger.error('这是一个error信息')

日志流的重定向

有时候,将日志流重定向到除了标准输出之外的地方可能非常有用,比如一个文件或者网络。下面的代码示例展示了如何将日志输出到一个文件中。

import logging

# 创建logger
file_logger = logging.getLogger('fileLogger')
file_logger.setLevel(logging.DEBUG)

# 创建一个文件处理器
file_handler = logging.FileHandler('my_log.log')
file_handler.setLevel(logging.DEBUG)

# 创建一个格式化器,并添加到文件处理器上
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)

# 将文件处理器添加到logger
file_logger.addHandler(file_handler)

# 记录一条信息
file_logger.info('这是保存到文件的信息')

日志的异步写入

在一些高性能要求的应用中,异步日志记录可以减少日志记录对应用性能的影响。Python的logging模块自身不直接支持异步记录,但可以使用concurrent.futures模块或其他异步框架来实现。以下是一个简单的使用concurrent.futures.ThreadPoolExecutor来实现异步日志记录的示例。

import logging
from concurrent.futures import ThreadPoolExecutor

# 创建logger
async_logger = logging.getLogger('asyncLogger')
async_logger.setLevel(logging.DEBUG)

# 添加简单的流处理器
stream_handler = logging.StreamHandler()
async_logger.addHandler(stream_handler)

# 定义一个异步记录日志的函数
def async_log(message):
    async_logger.info(message)

# 使用线程池执行器来异步记录日志
with ThreadPoolExecutor() as executor:
    executor.submit(async_log, '这是异步记录的信息')

八、propagate属性

在Python的logging模块中,propagate是Logger对象的一个属性,用于控制日志信息是否传播(或称为“向上传递”)到Logger的父级。默认情况下,这个属性被设置为True

例如,假设我们有一个“root”Logger,以及一个名为"module"的子Logger,子Logger的propagate属性设置为True

import logging

# 配置root Logger
root_logger = logging.getLogger()
root_handler = logging.StreamHandler()
root_formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
root_handler.setFormatter(root_formatter)
root_logger.addHandler(root_handler)
root_logger.setLevel(logging.DEBUG)

# 配置module Logger
module_logger = logging.getLogger('module')
module_logger.setLevel(logging.DEBUG)

# 发送日志消息
module_logger.debug('这条消息将会在root_logger的handler中也被看到,因为propagate默认为True')

如果你不希望日志在层次结构中向上传递,可以将propagate属性设置为False

module_logger.propagate = False
module_logger.debug('这条消息不会传播到root_logger,只会在module_logger的handler中被处理')

九、结论

合理使用logging模块可以极大提升应用程序的可维护性。通过不同的日志级别,格式化和处理器,可以创建出能够满足不同需求的灵活的日志记录方案。无论是进行问题排查还是系统行为分析,logging模块都是Python开发者的得力助手。

04-06 13:19