python Logging日志模块简介
编辑本文主体部分参考此篇文章: 标点符-python Logger 模块
使用 logging
模块,可以在应用程序中记录调试信息、错误消息和其他运行时信息。
-
记录调试信息:可以在代码中插入日志信息,用于追踪程序的执行过程,例如函数的输入输出、变量的值等,帮助调试程序。
-
记录错误信息:可以在捕获异常时记录错误信息,方便排查问题。例如,记录未捕获的异常、错误堆栈等。
-
监控程序运行:可以将程序的运行情况记录到日志文件中,便于在程序运行过程中或运行后分析日志,了解程序的状态和行为。
最近使用日志模块,融入自己项目代码中。
模块功能简介
Python的logging模块是一个非常强大的工具,用于在应用程序中记录和管理日志信息。它提供了灵活的功能,可以在不同的输出目标(如控制台、文件、网络等)中记录日志,并支持不同的日志级别。
-
Logger(记录器):Logger对象是应用程序可以直接使用的接口。你可以通过getLogger(name)获取一个记录器。通常,记录器会按照模块或类的名称进行命名,以便于区分不同的日志来源。
-
Handler(处理器):Handler用于定义日志消息发送到的位置。常见的处理器有StreamHandler(用于输出到控制台)和FileHandler(用于输出到文件)。每个记录器可以附加多个处理器。
-
Formatter(格式化器):Formatter用于定义日志消息的最终输出格式。你可以指定时间、日志级别、消息等的格式。通过设置格式化器,可以使日志输出更具可读性。
- Logger 是日志记录的入口。
- Handler 决定日志消息发送到哪里,例如控制台或文件。
- Formatter 决定日志消息的具体格式。
基本用法
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_handlerwrei
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')
Logger 模块
核心组件,用于记录日志消息。每个 Logger 对象对应一个日志记录器。
常用方法:
-
getLogger(name)
:获取指定名称的 Logger 对象。如果 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)
:移除日志处理器。
logging
模块支持不同的日志级别(从低到高):
- DEBUG:用于调试目的,记录详细的日志信息,通常只在开发阶段使用。
- INFO:用于记录程序正常运行时的信息,如启动、配置等。
- WARNING:用于记录潜在的问题或异常情况,但程序仍能正常运行。
- ERROR:用于记录错误信息,程序可能无法执行某些功能。
- CRITICAL:用于记录严重的错误,程序可能无法继续运行。
通过设置不同的日志级别,可以控制哪些信息需要记录,哪些可以忽略。
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 请求发送日志消息。
self.logger = logging.getLogger(log_type.value)
self.logger.setLevel(logging.DEBUG) # 设置为最低级别,允许所有日志
if not self.logger.handlers:
# 控制台处理器 - INFO级别
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# 文件处理器 - DEBUG级别
file_handler = logging.FileHandler(self.log_path)
file_handler.setLevel(logging.DEBUG)
# 定义日志格式
formatter = logging.Formatter('%(asctime)s - %(levelname)s : %(message)s')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
self.logger.addHandler(console_handler)
self.logger.addHandler(file_handler)
# 存储handlers以便清理
self.handlers = [console_handler, file_handler]
这里 file_handler = logging.FileHandler('app.log')
,文件默认存储在当前工作同级目录中。
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',# 日志格式
datefmt='%Y/%m/%d %H:%M:%S') # 自定义时间格式
handler.setFormatter(formatter)
# Add handler to logger
logger.addHandler(handler)
logger.info('This is an info message')
格式说明
%(asctime)s
:
当前时间,默认格式为 YYYY-MM-DD HH:MM:SS,MS
(精确到毫秒)。示例:2024-11-19 14:30:45,123
%(name)s
:
日志记录器的名称,即 logging.getLogger('my_logger')
中的 'my_logger'
。示例:my_logger
%(levelname)s
:
日志级别名称,如 DEBUG
、INFO
、WARNING
、ERROR
或 CRITICAL
。示例:INFO
%(message)s
:
实际的日志消息内容,即 logger.info('This is an info message')
中的字符串。示例:This is an info message
常用时间格式代码
格式符 | 含义 | 示例 |
---|---|---|
%Y | 4 位年份 | 2024 |
%m | 两位月份(01-12) | 11 |
%d | 两位日期(01-31) | 19 |
%H | 小时(24 小时制,00-23) | 14 |
%I | 小时(12 小时制,01-12) | 02 |
%M | 分钟(00-59) | 30 |
%S | 秒(00-59) | 45 |
%f | 微秒(精确到百万分之一秒) | 123456 |
%p | AM 或 PM(与本地设置有关) | PM |
自定义格式示例
- 默认格式:
'%Y-%m-%d %H:%M:%S,%f'
- 输出:
2024-11-19 14:30:45,123
- 日期与时间分隔更明显:
'%Y/%m/%d %H:%M:%S'
- 输出:
2024/11/19 14:30:45
- 加入时区:
'%Y-%m-%d %H:%M:%S %Z'
- 输出:
2024-11-19 14:30:45 UTC
- 简洁格式:
'%H:%M:%S'
- 输出:
14:30:45
-
带 AM/PM 的 12 小时制:
'%I:%M:%S %p'
- 输出:
02:30:45 PM
全局配置写法 (不推荐)
-
快速设置: 一行代码完成基本配置,适合快速开发或简单需求。
-
全局影响:
basicConfig
配置的是根记录器(root logger),对所有通过logging
调用的日志生效。 -
默认处理器: 自动创建一个
StreamHandler
,输出到控制台或文件(取决于是否设置了filename
参数)。 -
小型项目或临时脚本,不需要复杂的日志管理。
-
日志需求简单,只有一个输出目标(例如写入单个文件)。
- 导入模块
import logging
- 基本配置
logging.basicConfig(level=logging.DEBUG)
- 记录信息
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')
配置日志格式
您可以自定义日志消息的格式,包括时间戳、日志级别和消息内容。
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logging.info('This is an info message with custom format')
将日志写入文件
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename='app.log',
filemode='w' # 'w' 表示写入模式,会覆盖文件。'a' 表示追加模式。
)
logging.info('This message will be written to app.log')
# 创建一个自定义的Logger
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG)
# 创建一个控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
# 创建一个文件处理器
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.ERROR)
# 创建一个格式器
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# 将格式器添加到处理器
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
# 将处理器添加到Logger
logger.addHandler(console_handler)
logger.addHandler(file_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')
日志抽象类写法
import logging
from datetime import datetime
from enum import Enum
from pathlib import Path
from isort import file
class LoggerType(Enum):
GPS = "gps"
DETECT = "detect"
WEBCAM = "webCam"
class BasicLogger:
def __init__(self, log_type: LoggerType) -> None:
self.log_path = self._create_log_file(log_type)
self.logger = None
self.handlers = [] # 存储handlers以便清理
if self.log_path:
self._setup_logger(log_type)
def _create_log_file(self, log_type: LoggerType)-> Path:
current_dir = Path(__file__).resolve().parent.parent
current_time = datetime.now().strftime("%Y-%m-%d")
log_dir_path = current_dir.joinpath("logs",log_type.value)
if not log_dir_path.exists():
log_dir_path.mkdir(parents=True)
log_path = log_dir_path.joinpath(f"{current_time}_{log_type.value}.log")
return log_path
def _setup_logger(self, log_type: LoggerType)-> None:
self.logger = logging.getLogger(log_type.value)
self.logger.setLevel(logging.DEBUG) # 设置为最低级别,允许所有日志
# handler处理日志消息并决定如何将其输出到不同的目标(例如控制台、文件、网络)
if not self.logger.handlers:
# 控制台设置INFO级别
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
# 日志文件设置DEBUG级别
file_handler = logging.FileHandler(self.log_path)
file_handler.setLevel(logging.DEBUG)
# 定义日志消息的格式,包括时间戳、日志级别、消息内容等
formatter = logging.Formatter('%(asctime)s - %(levelname)s : %(message)s')
console_handler.setFormatter(formatter)
file_handler.setFormatter(formatter)
self.logger.addHandler(console_handler)
self.logger.addHandler(file_handler)
# 存储handlers以便清理
self.handlers = [console_handler, file_handler]
def cleanup(self):
"""清理日志处理器"""
if self.logger:
for handler in self.handlers:
handler.close()
self.logger.removeHandler(handler)
self.handlers.clear()
class GPSLogger(BasicLogger):
def __init__(self):
super().__init__(LoggerType.GPS)
class WebCAMLogger(BasicLogger):
def __init__(self):
super().__init__(LoggerType.WEBCAM)
这样在其他代码中直接引入日志类即可。
- 0
- 1
-
分享