• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

SOC/IP验证工程师

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

python中logging库的详细用法

Python logging 库详细指南

logging 是 Python 标准库中功能强大且灵活的日志记录模块。下面详细介绍其用法。

1. 基础用法

快速开始

import logging

# 基础配置和简单使用
logging.basicConfig(level=logging.DEBUG)
logging.debug('这是 debug 信息')
logging.info('这是 info 信息')
logging.warning('这是 warning 信息')
logging.error('这是 error 信息')
logging.critical('这是 critical 信息')

日志级别

import logging

# 日志级别从低到高
"""
CRITICAL = 50
ERROR = 40
WARNING = 30
INFO = 20
DEBUG = 10
NOTSET = 0
"""

# 设置日志级别
logging.basicConfig(level=logging.INFO)  # 只记录 INFO 及以上级别的日志

logging.debug('这条不会显示')    # 级别 10 < 20,不记录
logging.info('这条会显示')       # 级别 20 >= 20,记录
logging.warning('这条也会显示')   # 级别 30 >= 20,记录

2. 高级配置

basicConfig 详细参数

import logging
import sys

logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
    handlers=[
        logging.FileHandler('app.log', encoding='utf-8'),
        logging.StreamHandler(sys.stdout)
    ]
)

logging.info('配置完成的日志记录')

格式化字符串常用字段

"""
%(name)s            Logger 的名字
%(levelno)s         数字形式的日志级别
%(levelname)s       文本形式的日志级别
%(pathname)s        调用日志输出函数的模块的完整路径名
%(filename)s        调用日志输出函数的模块的文件名
%(module)s          调用日志输出函数的模块名
%(funcName)s        调用日志输出函数的函数名
%(lineno)d          调用日志输出函数的语句所在的代码行
%(created)f         当前时间,用 UNIX 标准的表示时间的浮点数表示
%(asctime)s         字符串形式的当前时间
%(msecs)d           毫秒部分
%(relativeCreated)d 日志事件发生的时间相对于 logging 模块加载时间的相对毫秒数
%(thread)d          线程 ID
%(threadName)s      线程名
%(process)d         进程 ID
%(message)s         用户输出的消息
"""

3. Logger, Handler, Formatter, Filter

完整的组件配置

import logging
import logging.handlers

def setup_logger():
    # 创建 logger
    logger = logging.getLogger('my_app')
    logger.setLevel(logging.DEBUG)
    
    # 防止日志重复处理
    if logger.handlers:
        logger.handlers.clear()
    
    # 创建 formatter
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    
    # 控制台 handler
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)
    console_handler.setFormatter(formatter)
    
    # 文件 handler
    file_handler = logging.FileHandler('app.log', encoding='utf-8')
    file_handler.setLevel(logging.DEBUG)
    file_handler.setFormatter(formatter)
    
    # 滚动日志文件 handler
    rotating_handler = logging.handlers.RotatingFileHandler(
        'app_rotating.log', 
        maxBytes=1024*1024,  # 1MB
        backupCount=5,
        encoding='utf-8'
    )
    rotating_handler.setLevel(logging.DEBUG)
    rotating_handler.setFormatter(formatter)
    
    # 时间滚动日志 handler
    timed_handler = logging.handlers.TimedRotatingFileHandler(
        'app_timed.log',
        when='midnight',  # 每天午夜
        interval=1,
        backupCount=7,
        encoding='utf-8'
    )
    timed_handler.setLevel(logging.DEBUG)
    timed_handler.setFormatter(formatter)
    
    # 添加所有 handlers
    logger.addHandler(console_handler)
    logger.addHandler(file_handler)
    logger.addHandler(rotating_handler)
    logger.addHandler(timed_handler)
    
    return logger

# 使用配置好的 logger
logger = setup_logger()
logger.info('应用程序启动')
logger.debug('调试信息')
logger.error('错误信息')

4. 高级特性

日志过滤器

import logging

class InfoFilter(logging.Filter):
    def filter(self, record):
        # 只允许 INFO 级别的日志通过
        return record.levelno == logging.INFO

# 配置过滤器
logger = logging.getLogger('filtered_logger')
handler = logging.StreamHandler()
handler.addFilter(InfoFilter())
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)

logger.debug('DEBUG 信息')  # 被过滤
logger.info('INFO 信息')    # 显示
logger.warning('WARNING 信息')  # 被过滤

异常处理

import logging
import traceback

logger = logging.getLogger('exception_logger')
logging.basicConfig(level=logging.DEBUG)

def risky_function():
    try:
        1 / 0
    except Exception as e:
        # 方法1: 使用 logging.exception (自动包含堆栈跟踪)
        logger.exception('发生除零错误')
        
        # 方法2: 使用 logger.error 并手动添加堆栈
        logger.error('发生错误: %s, 堆栈: %s', e, traceback.format_exc())
        
        # 方法3: 使用 exc_info 参数
        logger.error('错误详情:', exc_info=True)

risky_function()

结构化日志 (JSON 格式)

import logging
import json

class JSONFormatter(logging.Formatter):
    def format(self, record):
        log_entry = {
            'timestamp': self.formatTime(record),
            'level': record.levelname,
            'logger': record.name,
            'message': record.getMessage(),
            'module': record.module,
            'function': record.funcName,
            'line': record.lineno
        }
        
        if record.exc_info:
            log_entry['exception'] = self.formatException(record.exc_info)
            
        return json.dumps(log_entry, ensure_ascii=False)

# 使用 JSON 格式
logger = logging.getLogger('json_logger')
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)

logger.info('用户登录', extra={'user_id': 12345, 'ip': '192.168.1.1'})

5. 实际应用示例

项目中的日志配置

import logging
import logging.config
import os
from pathlib import Path

def setup_project_logging():
    log_dir = Path('logs')
    log_dir.mkdir(exist_ok=True)
    
    LOGGING_CONFIG = {
        'version': 1,
        'disable_existing_loggers': False,
        
        'formatters': {
            'standard': {
                'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
            },
            'detailed': {
                'format': '%(asctime)s [%(levelname)s] %(name)s (%(filename)s:%(lineno)d): %(message)s'
            },
            'json': {
                '()': 'pythonjsonlogger.jsonlogger.JsonFormatter',
                'format': '%(asctime)s %(levelname)s %(name)s %(message)s'
            }
        },
        
        'handlers': {
            'console': {
                'class': 'logging.StreamHandler',
                'level': 'INFO',
                'formatter': 'standard',
                'stream': 'ext://sys.stdout'
            },
            'file_debug': {
                'class': 'logging.handlers.RotatingFileHandler',
                'level': 'DEBUG',
                'formatter': 'detailed',
                'filename': log_dir / 'debug.log',
                'maxBytes': 10485760,  # 10MB
                'backupCount': 5,
                'encoding': 'utf-8'
            },
            'file_error': {
                'class': 'logging.handlers.RotatingFileHandler',
                'level': 'ERROR',
                'formatter': 'detailed',
                'filename': log_dir / 'error.log',
                'maxBytes': 10485760,
                'backupCount': 5,
                'encoding': 'utf-8'
            }
        },
        
        'loggers': {
            '': {  # root logger
                'handlers': ['console', 'file_debug', 'file_error'],
                'level': 'DEBUG',
                'propagate': False
            },
            'my_app': {
                'handlers': ['console', 'file_debug'],
                'level': 'DEBUG',
                'propagate': False
            },
            'requests': {
                'handlers': ['file_error'],
                'level': 'WARNING',
                'propagate': False
            }
        }
    }
    
    logging.config.dictConfig(LOGGING_CONFIG)

# 初始化日志配置
setup_project_logging()

# 在不同模块中使用
app_logger = logging.getLogger('my_app.main')
db_logger = logging.getLogger('my_app.database')
api_logger = logging.getLogger('my_app.api')

def example_usage():
    app_logger.info('应用程序启动')
    
    try:
        # 模拟一些操作
        db_logger.debug('执行数据库查询: SELECT * FROM users')
        api_logger.info('调用外部API')
        
        # 模拟错误
        raise ValueError('测试错误')
        
    except Exception as e:
        app_logger.error('操作失败', exc_info=True)
    
    app_logger.info('应用程序结束')

example_usage()

上下文信息日志

import logging
from contextlib import contextmanager

class ContextLogger:
    def __init__(self, logger, **context):
        self.logger = logger
        self.context = context
    
    def _add_context(self, msg, *args, **kwargs):
        if self.context:
            msg = f"{msg} [Context: {self.context}]"
        return msg, args, kwargs
    
    def info(self, msg, *args, **kwargs):
        msg, args, kwargs = self._add_context(msg, *args, **kwargs)
        self.logger.info(msg, *args, **kwargs)
    
    def error(self, msg, *args, **kwargs):
        msg, args, kwargs = self._add_context(msg, *args, **kwargs)
        self.logger.error(msg, *args, **kwargs)

@contextmanager
def log_context(logger, **context):
    """上下文管理器,为代码块添加日志上下文"""
    context_logger = ContextLogger(logger, **context)
    context_logger.info("开始执行")
    try:
        yield context_logger
        context_logger.info("执行成功")
    except Exception as e:
        context_logger.error("执行失败: %s", e)
        raise

# 使用示例
logger = logging.getLogger('context_example')

def process_user_data(user_id, action):
    with log_context(logger, user_id=user_id, action=action, trace_id='12345'):
        logger.info(f"处理用户 {user_id} 的 {action} 操作")
        # 模拟处理逻辑
        if user_id == 999:
            raise Exception("用户不存在")
        return f"操作 {action} 完成"

# 测试
process_user_data(123, 'update_profile')
process_user_data(999, 'delete_account')  # 这个会失败并记录错误

6. 性能考虑

避免不必要的字符串格式化

import logging

# 不好的写法(即使日志级别不够也会执行字符串格式化)
logger.debug('用户数据: %s', expensive_data_processing())

# 好的写法(先检查日志级别)
if logger.isEnabledFor(logging.DEBUG):
    logger.debug('用户数据: %s', expensive_data_processing())

# 或者使用参数形式(推荐)
logger.debug('用户数据: %s', expensive_data_processing())  # 参数在需要时才求值

7. 最佳实践总结

  1. 使用有意义的 logger 名称:通常使用 __name__
  2. 合理设置日志级别:生产环境用 INFO,开发环境用 DEBUG
  3. 使用适当的处理器:控制台用于开发,文件用于生产
  4. 包含足够的上下文信息:时间、级别、模块、行号等
  5. 避免敏感信息:不要在日志中记录密码、密钥等
  6. 使用结构化日志:便于后续分析和处理
  7. 合理配置日志轮转:避免日志文件过大

这个详细的 logging 指南涵盖了从基础到高级的各个方面,可以帮助你在项目中实现专业级的日志记录。

posted on 2025-10-14 22:22  SOC验证工程师  阅读(34)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3