Python的日志模块(logging
)是一个非常强大、灵活的日志记录框架,适用于各种规模的应用程序。它允许开发者将程序执行中的信息输出到多个地方,如控制台、文件、网络等。接下来我们来详细介绍它的功能和使用方法。
logging
模块提供了几种内置的日志级别,用于标识日志的严重程度。默认情况下,日志级别从低到高依次为:
DEBUG
:调试信息,最详细的日志信息,用于诊断问题。INFO
:普通运行信息,确认程序按预期工作。WARNING
:表示潜在问题或提示,比如磁盘空间不足。ERROR
:更严重的问题,程序的某些功能无法正常执行。CRITICAL
:最严重的级别,程序可能无法继续运行。logging
模块有四个核心组件,每个组件有不同的用途:
可以通过logging.basicConfig()
配置日志输出。
import logging
# 配置日志模块
logging.basicConfig(level=logging.INFO)
# 日志输出
logging.debug('这是调试信息')
logging.info('这是普通信息')
logging.warning('这是警告信息')
logging.error('这是错误信息')
logging.critical('这是严重错误信息')
在这个例子中,logging.basicConfig()
用于一次性配置日志输出,level
参数设置最低日志级别。只有级别高于level
的日志才会被输出。
你可以通过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()
记录异常,它会输出堆栈跟踪信息。除了输出到控制台,你还可以将日志输出到文件:
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
文件中。
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('这条日志同时输出到控制台和文件')
在这个例子中,日志会同时输出到控制台和文件。
你可以通过配置文件配置日志系统,logging
模块支持JSON
、YAML
或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格式):
{
"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格式):
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('这是调试信息')
你可以使用过滤器来过滤特定的日志消息:
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
关键字的消息会被输出。