Python日志模块详解

Python日志模块详解

Python的日志模块(logging)是一个非常强大、灵活的日志记录框架,适用于各种规模的应用程序。它允许开发者将程序执行中的信息输出到多个地方,如控制台、文件、网络等。接下来我们来详细介绍它的功能和使用方法。

1. 基本概念

1.1 日志级别

logging模块提供了几种内置的日志级别,用于标识日志的严重程度。默认情况下,日志级别从低到高依次为:

  • DEBUG:调试信息,最详细的日志信息,用于诊断问题。
  • INFO:普通运行信息,确认程序按预期工作。
  • WARNING:表示潜在问题或提示,比如磁盘空间不足。
  • ERROR:更严重的问题,程序的某些功能无法正常执行。
  • CRITICAL:最严重的级别,程序可能无法继续运行。

1.2 日志组件

logging模块有四个核心组件,每个组件有不同的用途:

  1. Logger:日志记录器,是日志系统的入口,用来生成日志记录。
  2. Handler:处理器,用来将日志记录发送到合适的地方(如文件、控制台)。
  3. Filter:过滤器,用来过滤日志记录,决定哪些日志记录应当被输出。
  4. Formatter:格式器,用来定义日志记录的最终输出格式。

2. 基本用法

可以通过logging.basicConfig()配置日志输出。

import logging

# 配置日志模块
logging.basicConfig(level=logging.INFO)

# 日志输出
logging.debug('这是调试信息')
logging.info('这是普通信息')
logging.warning('这是警告信息')
logging.error('这是错误信息')
logging.critical('这是严重错误信息')

在这个例子中,logging.basicConfig()用于一次性配置日志输出,level参数设置最低日志级别。只有级别高于level的日志才会被输出。

3. 配置日志格式

你可以通过Formatter来指定日志的输出格式,包括时间、日志级别、模块名称等信息。

import logging

# 设置格式化器
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# 创建一个日志记录器
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)

# 创建控制台处理器并设置其格式
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)

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

# 日志记录
logger.debug('这是调试信息')
logger.info('这是普通信息')
logger.warning('这是警告信息')

在这个例子中,我们创建了一个名为my_logger的记录器,设置了控制台处理器,并指定了日志的输出格式。

常用的格式化占位符

  • %(name)s:记录器的名称(即通过 logging.getLogger() 创建的 logger 名称)。
  • %(levelname)s:日志级别名称(如 DEBUG, INFO, WARNING, ERROR, CRITICAL)。
  • %(levelno)s:日志级别的数值(如 DEBUG=10, INFO=20, WARNING=30, ERROR=40, CRITICAL=50)。
  • %(asctime)s:日志事件发生的时间,默认为 ISO8601 格式(你也可以通过 datefmt 参数自定义)。
  • %(msecs)d:日志事件时间的毫秒部分。
  • %(message)s:实际的日志消息内容(用户传递的消息)。
  • %(pathname)s:调用日志输出函数的完整文件路径。
  • %(filename)s:调用日志输出函数的文件名,不带路径。
  • %(module)s:调用日志输出函数所在的模块名(即文件名,不带 .py 后缀)。
  • %(funcName)s:调用日志输出函数的函数名。
  • %(lineno)d:调用日志输出函数的行号。
  • %(thread)d:线程 ID。
  • %(threadName)s:线程名称。
  • %(process)d:进程 ID。
  • %(processName)s:进程名称。
  • %(created)f:日志事件发生的时间戳(UNIX 时间)。
  • %(relativeCreated)d:日志事件发生相对于 logging 模块加载时间的毫秒数。
  • %(exc_info)s:异常相关信息,如果使用 logger.exception() 记录异常,它会输出堆栈跟踪信息。

4. 输出到文件

除了输出到控制台,你还可以将日志输出到文件:

import logging

# 创建文件处理器
file_handler = logging.FileHandler('app.log')

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

# 获取日志记录器并设置日志级别
logger = logging.getLogger('file_logger')
logger.setLevel(logging.INFO)

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

# 记录日志
logger.info('日志记录到文件中')

这样,日志会被输出到app.log文件中。

5. 多个处理器

logging允许为一个Logger添加多个Handler,可以同时输出到多个目的地。

import logging

# 创建日志记录器
logger = logging.getLogger('multi_handler_logger')

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

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

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

logger.setLevel(logging.INFO)

# 记录日志
logger.info('这条日志同时输出到控制台和文件')

在这个例子中,日志会同时输出到控制台和文件。

6. 使用配置文件

你可以通过配置文件配置日志系统,logging模块支持JSONYAMLINI格式。

INI文件

示例配置文件(INI格式):

[loggers]
keys=root

[handlers]
keys=consoleHandler,fileHandler

[formatters]
keys=defaultFormatter

[logger_root]
level=INFO
handlers=consoleHandler,fileHandler

[handler_consoleHandler]
class=StreamHandler
level=INFO
formatter=defaultFormatter
args=(sys.stdout,)

[handler_fileHandler]
class=logging.handlers.RotatingFileHandler
level=INFO
formatter=defaultFormatter
args=('./log/app.log', 'a', 10485760, 5, 'utf-8')  # 文件路径, 打开模式, 最大文件大小, 备份文件数, 编码

[formatter_defaultFormatter]
format=%(asctime)s %(levelname)s - %(pathname)s:%(funcName)s(),%(lineno)d - %(message)s
datefmt=%Y-%m-%d %H:%M:%S

在代码中加载这个配置:

import logging
import logging.config

logging.config.fileConfig('logging.conf')

logger = logging.getLogger()
logger.info('这是调试信息')

JSON文件

示例配置文件(JSON格式):

{
    "version": 1,
    "disable_existing_loggers": false,
    "formatters": {
        "default": {
            "format": "%(asctime)s %(levelname)s - %(pathname)s:%(funcName)s(),%(lineno)d - %(message)s",
            "datefmt": "%Y-%m-%d %H:%M:%S"
        }
    },
    "handlers": {
        "fileHandler": {
            "class": "logging.FileHandler",
            "level": "INFO",
            "formatter": "default",
            "filename": "./log/timed_log.log",
            "maxBytes": 10485760,
            "backupCount": 7,
            "encoding": "utf-8"
        },
        "consoleHandler": {
            "class": "logging.StreamHandler",
            "level": "INFO",
            "formatter": "default",
            "stream": "ext://sys.stdout"
        }
    },
    "loggers": {
        "": {
            "level": "INFO",
            "handlers": ["fileHandler", "consoleHandler"]
        },
        "django": {
            "level": "INFO",
            "handlers": ["fileHandler", "consoleHandler"]
        }
    }
}

在代码中加载这个配置:

import logging
import logging.config

# 读取 JSON 配置文件
with open('./conf/log_conf.json', 'r') as f:
    config = json.load(f)  # 读取并解析 JSON 配置文件为字典
    
# 使用 dictConfig 加载 JSON 配置
logging.config.dictConfig(config)
logger = logging.getLogger()
logger.info('这是调试信息')

YAML文件

示例配置文件(YAML格式):

version: 1
disable_existing_loggers: false

formatters:
  default:
    format: '%(asctime)s %(levelname)s - %(pathname)s:%(funcName)s(),%(lineno)d - %(message)s'
    datefmt: '%Y-%m-%d %H:%M:%S'

handlers:
  fileHandler:
    class: logging.handlers.RotatingFileHandler
    level: INFO
    formatter: default
    filename: './log/app.log'  # 基础文件名
    maxBytes: 10485760  # 最大文件大小为10MB
    backupCount: 5  # 最多保留5个日志文件
    encoding: utf-8

  consoleHandler:
    class: logging.StreamHandler
    level: INFO
    formatter: default
    stream: ext://sys.stdout

loggers:
  '':
    level: INFO
    handlers: [fileHandler, consoleHandler]

在代码中加载这个配置:

import logging
import logging.config
import yaml

# 读取 YAML 配置文件
with open('./conf/log_conf.yaml', 'r') as f:
    config = yaml.safe_load(f)  # 解析 YAML 配置文件为字典

# 使用 dictConfig 加载 JSON 配置
logging.config.dictConfig(config)
logger = logging.getLogger()
logger.info('这是调试信息')

7. 过滤器

你可以使用过滤器来过滤特定的日志消息:

import logging

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

logger = logging.getLogger()
logger.addFilter(CustomFilter())

logger.warning('这条消息会被过滤')
logger.warning('这是 special 消息')

在这个例子中,只有包含special关键字的消息会被输出。

你可能感兴趣的:(Python,python,logging)