You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python通用函数起止日志装饰器实现:提取指定参数入日志

通用Python日志装饰器实现

核心思路

要实现满足需求的日志装饰器,核心难点是安全提取指定参数——不管被装饰函数的参数是位置传参、关键字传参,还是参数可选,都能从args和kwargs中准确拿到目标字段,同时避免直接打印整组参数。

这里用inspect模块解析函数签名,把args和kwargs绑定到函数的参数定义上,生成一个包含所有参数映射的字典,再从中提取我们需要的字段(比如product_id、message_id),完美解决参数形式不固定的问题。

完整实现代码

import inspect
import datetime
import logging

# 初始化日志配置
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)

def log_with_context(target_fields=["product_id", "message_id"]):
    def decorator(func):
        def wrapper(*args, **kwargs):
            # 解析被装饰函数的参数签名
            sig = inspect.signature(func)
            try:
                # 绑定传入的args和kwargs到签名,生成参数映射
                bound_args = sig.bind(*args, **kwargs)
                bound_args.apply_defaults()  # 应用默认值,处理可选参数
                params = bound_args.arguments
            except ValueError:
                # 极端情况:参数不匹配时,用空字典避免报错
                params = {}
            
            # 提取目标字段,不存在则设为None
            context = {field: params.get(field) for field in target_fields}
            # 添加时间戳
            context["timestamp"] = datetime.datetime.now().isoformat()

            # 函数执行前日志
            logger.info(
                f"Executing function: {func.__name__} | Context: {context}"
            )

            # 执行原函数
            try:
                result = func(*args, **kwargs)
                # 函数执行成功日志
                logger.info(
                    f"Function {func.__name__} executed successfully | Context: {context}"
                )
                return result
            except Exception as e:
                # 函数执行异常日志
                logger.error(
                    f"Function {func.__name__} failed | Error: {str(e)} | Context: {context}"
                )
                raise  # 重新抛出异常,不影响原函数的异常处理
        return wrapper
    return decorator

测试示例

测试1:参数为位置传参的函数

@log_with_context()
def process_order(product_id, quantity, message_id=None):
    if quantity <= 0:
        raise ValueError("Invalid quantity")
    return f"Processed order for product {product_id}"

process_order("PROD-123", 5, "MSG-456")
process_order("PROD-789", -2)  # 触发异常

测试2:参数为关键字传参的函数

@log_with_context(target_fields=["product_id", "user_id"])
def update_product(product_id, user_id, details=None):
    return f"Updated product {product_id} by user {user_id}"

update_product(user_id="USER-001", product_id="PROD-456")

关键特性说明

  • 通用性:不管被装饰函数的参数是位置、关键字还是可选参数,都能正确提取目标字段
  • 安全性:参数不匹配时不会崩溃,会用空字典处理
  • 低冗余:只打印指定的字段,不会输出整个args/kwargs的冗余数据
  • 可配置:通过target_fields参数可以自定义要提取的日志字段

内容的提问来源于stack exchange,提问作者shlomiLan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 18:22:48