Python日志封装案例如何封装日志工具

wen python案例 30

本文目录导读:

Python日志封装案例如何封装日志工具

  1. 方案1:基础封装(推荐用于小型项目)
  2. 方案2:单例模式封装(推荐用于大型项目)
  3. 方案3:高级封装(包含颜色输出和上下文信息)
  4. 使用建议
  5. 注意事项

我来为你提供一个完整的Python日志封装案例,包含多种实用方案。

方案1:基础封装(推荐用于小型项目)

import logging
import os
from datetime import datetime
class Logger:
    def __init__(self, name='app', log_level=logging.DEBUG, log_dir='logs'):
        """
        初始化日志器
        :param name: 日志器名称
        :param log_level: 日志级别
        :param log_dir: 日志文件目录
        """
        self.logger = logging.getLogger(name)
        self.logger.setLevel(log_level)
        # 创建日志目录
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
        # 日志文件路径(按日期分割)
        log_file = os.path.join(log_dir, f"{datetime.now().strftime('%Y%m%d')}.log")
        # 控制台处理器
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.INFO)
        # 文件处理器
        file_handler = logging.FileHandler(log_file, encoding='utf-8')
        file_handler.setLevel(log_level)
        # 定义格式器
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
        )
        console_handler.setFormatter(formatter)
        file_handler.setFormatter(formatter)
        # 避免重复添加处理器
        if not self.logger.handlers:
            self.logger.addHandler(console_handler)
            self.logger.addHandler(file_handler)
    def get_logger(self):
        return self.logger
# 使用示例
if __name__ == '__main__':
    log = Logger('my_app').get_logger()
    log.debug('这是一个调试信息')
    log.info('这是一个普通信息')
    log.warning('这是一个警告信息')
    log.error('这是一个错误信息')
    log.critical('这是一个严重错误')

方案2:单例模式封装(推荐用于大型项目)

import logging
import logging.handlers
import os
import sys
from functools import wraps
class LogManager:
    """日志管理器(单例模式)"""
    _instance = None
    _initialized = False
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    def __init__(self, config=None):
        if self._initialized:
            return
        self._initialized = True
        self.config = config or {
            'level': logging.DEBUG,
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            'date_format': '%Y-%m-%d %H:%M:%S',
            'log_dir': 'logs',
            'max_bytes': 10 * 1024 * 1024,  # 10MB
            'backup_count': 30,
            'encoding': 'utf-8'
        }
        # 创建日志目录
        os.makedirs(self.config['log_dir'], exist_ok=True)
        # 根日志器
        self.root_logger = logging.getLogger()
        self.root_logger.setLevel(self.config['level'])
        # 清除现有处理器
        self.root_logger.handlers.clear()
        # 添加处理器
        self._add_console_handler()
        self._add_file_handler()
        self._add_error_handler()
    def _add_console_handler(self):
        """添加控制台处理器"""
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setLevel(logging.INFO)
        console_handler.setFormatter(self._get_formatter())
        self.root_logger.addHandler(console_handler)
    def _add_file_handler(self):
        """添加文件处理器(按大小轮转)"""
        log_file = os.path.join(self.config['log_dir'], 'app.log')
        file_handler = logging.handlers.RotatingFileHandler(
            log_file,
            maxBytes=self.config['max_bytes'],
            backupCount=self.config['backup_count'],
            encoding=self.config['encoding']
        )
        file_handler.setLevel(self.config['level'])
        file_handler.setFormatter(self._get_formatter())
        self.root_logger.addHandler(file_handler)
    def _add_error_handler(self):
        """添加错误日志处理器"""
        error_log = os.path.join(self.config['log_dir'], 'error.log')
        error_handler = logging.handlers.RotatingFileHandler(
            error_log,
            maxBytes=self.config['max_bytes'],
            backupCount=self.config['backup_count'],
            encoding=self.config['encoding']
        )
        error_handler.setLevel(logging.ERROR)
        error_handler.setFormatter(self._get_formatter())
        self.root_logger.addHandler(error_handler)
    def _get_formatter(self):
        """获取格式器"""
        return logging.Formatter(
            self.config['format'],
            datefmt=self.config['date_format']
        )
    @staticmethod
    def get_logger(name=None):
        """获取日志器"""
        return logging.getLogger(name)
# 日志装饰器
def log_function_call(logger=None):
    """函数调用日志装饰器"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            log = logger or LogManager.get_logger(func.__module__)
            log.info(f"调用函数: {func.__name__}, args: {args}, kwargs: {kwargs}")
            try:
                result = func(*args, **kwargs)
                log.info(f"函数 {func.__name__} 执行成功")
                return result
            except Exception as e:
                log.error(f"函数 {func.__name__} 执行失败: {str(e)}")
                raise
        return wrapper
    return decorator
# 使用示例
@log_function_call()
def test_function(name, age):
    """测试函数"""
    return f"Hello, {name}! You are {age} years old."
if __name__ == '__main__':
    # 初始化日志管理器
    log_manager = LogManager()
    # 获取不同模块的日志器
    logger1 = LogManager.get_logger('module_a')
    logger2 = LogManager.get_logger('module_b')
    logger1.info('模块A的日志信息')
    logger2.warning('模块B的警告信息')
    # 测试装饰器
    result = test_function('Alice', 25)
    print(result)

方案3:高级封装(包含颜色输出和上下文信息)

import logging
import json
import traceback
import colorlog
from pathlib import Path
from typing import Optional, Dict, Any
class ColoredLogger:
    """带颜色的日志器"""
    def __init__(self, name: str, log_file: Optional[str] = None, level: str = 'DEBUG'):
        self.logger = logging.getLogger(name)
        self.logger.setLevel(getattr(logging, level.upper()))
        # 颜色格式器
        color_formatter = colorlog.ColoredFormatter(
            '%(log_color)s%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S',
            log_colors={
                'DEBUG': 'cyan',
                'INFO': 'green',
                'WARNING': 'yellow',
                'ERROR': 'red',
                'CRITICAL': 'red,bg_white',
            }
        )
        # 普通格式器
        plain_formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S'
        )
        # 控制台处理器(带颜色)
        console_handler = logging.StreamHandler()
        console_handler.setFormatter(color_formatter)
        console_handler.setLevel(logging.DEBUG)
        # 文件处理器(不带颜色)
        if log_file:
            Path(log_file).parent.mkdir(parents=True, exist_ok=True)
            file_handler = logging.FileHandler(log_file, encoding='utf-8')
            file_handler.setFormatter(plain_formatter)
            file_handler.setLevel(logging.DEBUG)
            self.logger.addHandler(file_handler)
        self.logger.addHandler(console_handler)
    def info(self, msg: str, extra: Dict[str, Any] = None):
        """信息日志"""
        if extra:
            msg = f"{msg} | {json.dumps(extra, ensure_ascii=False)}"
        self.logger.info(msg)
    def error(self, msg: str, exc_info: bool = True, extra: Dict[str, Any] = None):
        """错误日志"""
        if extra:
            msg = f"{msg} | {json.dumps(extra, ensure_ascii=False)}"
        if exc_info:
            msg = f"{msg}\n{traceback.format_exc()}"
        self.logger.error(msg)
    def warning(self, msg: str, extra: Dict[str, Any] = None):
        """警告日志"""
        if extra:
            msg = f"{msg} | {json.dumps(extra, ensure_ascii=False)}"
        self.logger.warning(msg)
    def debug(self, msg: str, extra: Dict[str, Any] = None):
        """调试日志"""
        if extra:
            msg = f"{msg} | {json.dumps(extra, ensure_ascii=False)}"
        self.logger.debug(msg)
# 使用示例
if __name__ == '__main__':
    # 初始化日志器
    logger = ColoredLogger('my_app', 'logs/app.log', 'DEBUG')
    # 基本使用
    logger.info('应用启动成功')
    logger.debug('这是调试信息', extra={'user_id': 123, 'action': 'login'})
    logger.warning('资源使用率过高', extra={'cpu': 85, 'memory': 70})
    # 错误处理
    try:
        result = 1 / 0
    except Exception as e:
        logger.error('计算错误', exc_info=True, extra={'operation': 'divide'})

使用建议

  1. 小型项目:使用方案1的基础封装即可
  2. 中型项目:推荐方案2的单例模式,包含错误日志分离
  3. 大型项目:使用方案3的高级封装,支持颜色输出和结构化日志

安装所需依赖:

pip install colorlog

注意事项

  1. 避免重复处理器:使用单例模式或检查handlers列表
  2. 日志轮转:使用RotatingFileHandler避免日志文件过大
  3. 性能考虑:生产环境避免打印过多DEBUG级别的日志
  4. 安全性:不要在日志中打印敏感信息(密码、token等)
  5. 编码问题:使用UTF-8编码避免中文乱码

抱歉,评论功能暂时关闭!