器→工具, 术→技巧, 研发, 编程语言

Python标准库之日志记录logging

钱魏Way · · 26 次浏览

logging模块简介

Python的logging模块是一个非常强大的工具,用于在应用程序中记录和管理日志信息。它提供了灵活的功能,可以在不同的输出目标(如控制台、文件、网络等)中记录日志,并支持不同的日志级别。先前基于PEP 282 — A Logging System翻译了一篇Python 日志模块logging的使用,感觉文绉绉的,让人看不懂,所以重新进行了一次梳理。

核心概念

  • Logger(记录器):Logger对象是应用程序可以直接使用的接口。你可以通过getLogger(name)获取一个记录器。通常,记录器会按照模块或类的名称进行命名,以便于区分不同的日志来源。
  • Handler(处理器):Handler用于定义日志消息发送到的位置。常见的处理器有StreamHandler(用于输出到控制台)和FileHandler(用于输出到文件)。每个记录器可以附加多个处理器。
  • Formatter(格式化器):Formatter用于定义日志消息的最终输出格式。你可以指定时间、日志级别、消息等的格式。通过设置格式化器,可以使日志输出更具可读性。
  • Level(级别):日志级别用于指示日志消息的严重性。常用的日志级别有:
    • NOTSET:未设置,默认值,不会记录任何消息。
    • DEBUG:详细的信息,通常只在诊断问题时使用。
    • INFO:确认程序按预期运行。
    • WARNING:表示潜在的问题。
    • ERROR:由于更严重的问题,程序已不能执行一些功能。
    • CRITICAL:严重错误,程序可能无法继续运行。

基本用法

以下是一个简单的使用示例:

import logging

# 创建一个logger
logger = logging.getLogger('example_logger')
logger.setLevel(logging.DEBUG)  # 设置最低日志级别

# 创建一个handler,用于写入日志文件
file_handler = logging.FileHandler('example.log')
file_handler.setLevel(logging.DEBUG)

# 创建一个handler,用于输出到控制台
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)

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

# 给logger添加handler
logger.addHandler(file_handler)
logger.addHandler(console_handler)

# 使用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')

高级功能

  • 配置日志:可以通过配置文件(如INI格式)或字典(如JSON格式)进行复杂的日志配置,使用config模块来加载这些配置。
  • 日志的层次结构:Logger对象是分层次的,根记录器是所有日志的祖先。子记录器会继承父记录器的设置。
  • 日志过滤:通过Filter对象可以实现更复杂的日志过滤机制,允许或拒绝特定的日志记录。
  • 线程安全:logging模块是线程安全的,适合多线程应用程序使用。
  • 性能:使用logging比直接使用print语句要高效,尤其是在大型应用程序中,因其可以动态调整日志级别,减少不必要的I/O操作。

通过灵活的配置和使用,Python的logging模块可以很好地满足各种应用程序的日志记录需求,从简单的调试到复杂的生产环境日志管理。

logging模块详解

Logger

功能:核心组件,用于记录日志消息。每个 Logger 对象对应一个日志记录器。

常用方法:

  • getLogger(name):获取指定名称的 Logger 对象。如果 Logger 对象不存在,则创建一个新的。
  • debug(msg, *args, **kwargs):记录调试级别的日志消息。
  • info(msg, *args, **kwargs):记录信息级别的日志消息。
  • warning(msg, *args, **kwargs):记录警告级别的日志消息。
  • error(msg, *args, **kwargs):记录错误级别的日志消息。
  • exception(msg, *args, **kwargs):记录异常级别的日志消息(包含异常信息)。
  • critical(msg, *args, **kwargs):记录严重错误级别的日志消息。
  • setLevel(level):设置 Logger 对象的日志级别。
  • addHandler(handler):添加日志处理器。
  • removeHandler(handler):移除日志处理器。

示例:

import logging

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

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')

Handler

功能:处理日志消息并决定如何将其输出到不同的目标(例如控制台、文件、网络)。

常用处理器:

  • StreamHandler:将日志消息输出到流(如stdout 或 sys.stderr)。
  • FileHandler:将日志消息写入文件。
  • RotatingFileHandler:将日志消息写入文件,并在文件达到指定大小时轮换。
  • TimedRotatingFileHandler:根据时间间隔轮换日志文件。
  • SocketHandler:将日志消息发送到网络套接字。
  • SMTPHandler:通过电子邮件发送日志消息。
  • HTTPHandler:通过 HTTP 请求发送日志消息。

示例:

import logging

# Create a logger
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)

# Create a console handler
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)

# Create a file handler
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.DEBUG)

# Add handlers to logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)

logger.debug('Debug message')
logger.info('Info message')

Formatter

功能:定义日志消息的格式,包括时间戳、日志级别、消息内容等。

常用格式化选项:

  • ‘%(asctime)s’:时间戳。
  • ‘%(name)s’:Logger 名称。
  • ‘%(levelname)s’:日志级别名称。
  • ‘%(message)s’:日志消息内容。

示例:

import logging

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

# Create a console handler
handler = logging.StreamHandler()

# Create a formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)

# Add handler to logger
logger.addHandler(handler)

logger.info('This is an info message')

Filter

功能:过滤不需要的日志消息,仅记录符合特定条件的消息。

常用方法:

  • addFilter(filter):添加过滤器。
  • removeFilter(filter):移除过滤器。

示例:

import logging

class CustomFilter(logging.Filter):
    def filter(self, record):
        return 'important' in record.getMessage()

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

handler = logging.StreamHandler()
handler.setFilter(CustomFilter())
logger.addHandler(handler)

logger.debug('This is an important message')
logger.debug('This is not important')

logging使用教程

基本用法

导入模块

首先,需要导入 logging 模块:

import logging

基本配置

可以使用 logging.basicConfig() 方法进行基本配置:

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S')
  • level:设置日志级别,低于该级别的日志不会被记录。
  • format:定义日志输出格式。
  • datefmt:定义日期时间格式。

记录日志

使用不同级别的方法记录日志:

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

Logger、Handler 和 Formatter

创建 Logger

Logger 是日志记录的入口:

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

添加 Handler

Handler 决定日志输出的位置,例如文件或控制台。

FileHandler:输出到文件。

file_handler = logging.FileHandler('my_log.log')
file_handler.setLevel(logging.DEBUG)

StreamHandler:输出到控制台。

console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)

设置 Formatter

Formatter 决定日志的最终输出格式:

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

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')

高级功能

日志配置文件

可以通过配置文件来管理日志设置,例如使用 logging.config 模块:

import logging.config
import yaml

with open('logging_config.yaml', 'r') as f:
    config = yaml.safe_load(f.read())
    logging.config.dictConfig(config)
示例 logging_config.yaml:
version: 1
formatters:
  simple:
    format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
  console:
    class: logging.StreamHandler
    level: DEBUG
    formatter: simple
    stream: ext://sys.stdout
loggers:
  my_logger:
    level: DEBUG
    handlers: [console]
    propagate: no

自定义 Filter

可以创建自定义的 Filter 来实现更复杂的日志过滤:

class MyFilter(logging.Filter):
    def filter(self, record):
        return 'special' in record.msg

my_filter = MyFilter()
console_handler.addFilter(my_filter)

日志的层次结构

Logger 是分层次的,子记录器会继承父记录器的设置。例如:

parent_logger = logging.getLogger('parent')
child_logger = logging.getLogger('parent.child')

parent_logger.setLevel(logging.WARNING)
child_logger.info('This will not be shown')
child_logger.warning('This will be shown')

实践中的一些建议

使用建议

  • 避免使用 root logger:尽量使用自定义的 logger,以便更好地管理和控制日志。
  • 合理设置日志级别:在开发环境中可以设置较低的日志级别,如DEBUG,而在生产环境中应设置为较高的级别,如 WARNING 或 ERROR。
  • 日志文件管理:对于输出到文件的日志,可以使用RotatingFileHandler 或 TimedRotatingFileHandler 来管理日志文件的大小和备份。

注意事项

  • 日志性能:确保日志记录不会对程序性能造成显著影响,特别是在高频率的日志记录场景中。
  • 日志轮换:使用 RotatingFileHandler 或 TimedRotatingFileHandler 处理大日志文件,避免日志文件过大。
  • 日志安全:确保日志文件的安全性,避免敏感信息泄露。
  • 通过合理使用 logging 模块,可以大大提高程序的可维护性和可调试性。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注