一、logging 介绍
logging 是 Python 标准库中的一个模块,它提供了灵活的日志记录功能。
主要特点:
-
可以方便地将日志信息输出到控制台、文件、网络等多种目标
-
支持不同级别的日志记录,满足不同场景下的需求
-
是标准库,无需额外安装
二、日志级别
日志级别从低到高(金字塔结构):
| 级别 | 数值 | 说明 |
|---|---|---|
DEBUG |
10 | 调试信息,最详细 |
INFO |
20 | 一般信息 |
WARNING |
30 | 警告信息(默认级别) |
ERROR |
40 | 错误信息 |
CRITICAL |
50 | 严重错误 |
规则: 只有高于或等于设定级别的日志才会被处理
DEBUG < INFO < WARNING < ERROR < CRITICAL
(低) (高)
三、基本使用
示例1:全局 logging 基本配置
import logging
logging.basicConfig(level=logging.INFO)
logging.debug('This is a debug message') # 不会输出(级别低于INFO)
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') # 会输出
示例2:自定义 logger 并输出到控制台
import logging
# 基本配置
logging.basicConfig(level=logging.INFO)
# 获取一个日志记录器对象,名称为当前模块的名称
logger = logging.getLogger(__name__)
# 设置日志记录器的级别为 DEBUG
logger.setLevel(logging.DEBUG)
if __name__ == "__main__":
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')
示例3:自定义 logger 并输出到日志文件
import logging
# 获取日志记录器对象
logger = logging.getLogger(__name__)
# 设置日志级别
logger.setLevel(logging.DEBUG)
# 创建 FileHandler 对象,指定日志文件名
handler = logging.FileHandler(filename="test.log")
# 将处理器添加到日志记录器
logger.addHandler(handler)
if __name__ == "__main__":
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')
输出结果(test.log 文件内容):
This is a debug message
This is an info message
This is a warning message
This is an error message
This is a critical message
四、核心组件说明
| 组件 | 说明 |
|---|---|
Logger |
日志记录器,负责生成日志。通过 logging.getLogger(name) 获取 |
Handler |
处理器,决定日志输出到哪里(文件、控制台等) |
Formatter |
格式器,定义日志的输出格式 |
Filter |
过滤器,决定哪些日志需要输出 |
五、设置日志格式(Formatter)
import logging
# 获取日志记录器
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 创建文件处理器
handler = logging.FileHandler(filename="test.log")
# 创建格式器
formatter = logging.Formatter(
"%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d)] - %(message)s"
)
# 将格式器设置到处理器上
handler.setFormatter(formatter)
# 添加处理器到日志记录器
logger.addHandler(handler)
if __name__ == "__main__":
logger.debug('This is a debug message')
输出结果示例:
2025-01-06 19:17:42,753 DEBUG [__main__] [test.py (<module>:13)] - This is a debug message
六、格式占位符详解
| 占位符 | 说明 |
|---|---|
%(asctime)s |
日志记录的时间戳 |
%(levelname)s |
日志级别(DEBUG、INFO、WARNING、ERROR、CRITICAL) |
%(name)s |
日志记录器的名称 |
%(filename)s |
日志记录发生的文件名 |
%(funcName)s |
日志记录发生的函数名 |
%(lineno)d |
日志记录发生的行号 |
%(message)s |
日志消息本身 |
七、高级用法:多处理器 + 日志分离
在接口自动化测试项目中,通常需要将不同级别的日志输出到不同文件:
import logging
import os
import time
class InfoFilter(logging.Filter):
"""只过滤 INFO 级别的日志"""
def filter(self, record):
return record.levelno == logging.INFO
class ErrorFilter(logging.Filter):
"""只过滤 ERROR 级别的日志"""
def filter(self, record):
return record.levelno == logging.ERROR
class Logger:
logger = None
@classmethod
def getlog(cls):
if cls.logger is None:
# 创建 logger
cls.logger = logging.getLogger(__name__)
cls.logger.setLevel(logging.DEBUG)
# 创建日志目录
now = time.strftime("%Y-%m-%d")
LOG_PATH = 'logs'
if not os.path.exists(LOG_PATH):
os.mkdir(LOG_PATH)
# 定义日志文件路径
info_log_name = LOG_PATH + now + '_info.log'
error_log_name = LOG_PATH + now + '_error.log'
log_name = LOG_PATH + now + '.log'
# 创建 handler(所有日志)
handler = logging.FileHandler(log_name, encoding="utf-8")
handler.setLevel(logging.INFO)
# 创建 info handler(仅 INFO 级别)
info_handler = logging.FileHandler(info_log_name, encoding="utf-8")
info_handler.setLevel(logging.INFO)
info_handler.addFilter(InfoFilter())
# 创建 error handler(仅 ERROR 级别)
error_handler = logging.FileHandler(error_log_name, encoding="utf-8")
error_handler.setLevel(logging.ERROR)
error_handler.addFilter(ErrorFilter())
# 设置格式器
formatter = logging.Formatter(
"%(asctime)s %(levelname)s [%(name)s] [%(filename)s (%(funcName)s:%(lineno)d)] - %(message)s"
)
handler.setFormatter(formatter)
info_handler.setFormatter(formatter)
error_handler.setFormatter(formatter)
# 添加处理器
cls.logger.addHandler(handler)
cls.logger.addHandler(info_handler)
cls.logger.addHandler(error_handler)
return cls.logger
效果:
-
2024-12-20.log:记录所有 INFO 及以上级别的日志 -
2024-12-20_info.log:只记录 INFO 级别的日志 -
2024-12-20_error.log:只记录 ERROR 级别的日志
八、在接口自动化框架中的实际应用
# utils/request_util.py
from utils.logger_util import Logger
class Request:
def __init__(self):
self.logger = Logger.getlog()
def get(self, url, **kwargs):
self.logger.info('准备开始发起get请求, url:' + url)
self.logger.info('接口信息是:{}'.format(kwargs))
s = requests.get(url, **kwargs)
self.logger.info('接口响应状态码:{}'.format(s.status_code))
self.logger.info('接口响应内容是:{}'.format(s.text))
return s
def post(self, url, **kwargs):
self.logger.info('准备开始发起post请求, url:' + url)
self.logger.info('接口信息是:{}'.format(kwargs))
s = requests.post(url, **kwargs)
self.logger.info('接口响应状态码是:{}'.format(s.status_code))
self.logger.info('接口响应内容是:{}'.format(s.text))
return s
九、总结对比
| 特性 | 普通 print | logging |
|---|---|---|
| 日志级别控制 | ❌ 不支持 | ✅ 支持(DEBUG/INFO/WARNING/ERROR/CRITICAL) |
| 输出目标 | 仅控制台 | 文件、控制台、网络等 |
| 格式定制 | 手动拼接 | Formatter 灵活配置 |
| 持久化 | ❌ 不保存 | ✅ 保存到文件 |
| 生产环境 | 不推荐 | ✅ 推荐 |
| 调试信息 | 手动添加 | 自动记录文件名、行号、函数名 |
十、快速上手模板
import logging
# 1. 创建 logger
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
# 2. 创建 handler(控制台 + 文件)
console_handler = logging.StreamHandler()
file_handler = logging.FileHandler('test.log', encoding='utf-8')
# 3. 创建 formatter
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# 4. 添加 handler
logger.addHandler(console_handler)
logger.addHandler(file_handler)
# 5. 使用
logger.debug("调试信息")
logger.info("一般信息")
logger.warning("警告信息")
logger.error("错误信息")