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

通用日志函数封装:如何为第三方库函数实现通用日志包装器?

Great question! You’ve already got a solid start with your shutil.copytree wrapper—creating a generic solution will eliminate repetitive logging code and make your codebase cleaner. Let’s walk through how to build a reusable logging wrapper that works for both exception-throwing functions (like most shutil methods) and non-exception-throwing ones (some subprocess utilities that return error codes, for example).

Generic Logging Wrapper with Decorators

Decorators are perfect for this use case—they let you wrap any function with logging logic without modifying the original code. Here’s a flexible implementation:

import functools
import logging

def log_function_call(logger, action_desc, success_desc=None, success_check=None):
    """
    A generic decorator to log function calls, successes, and failures.
    
    Args:
        logger: The logging instance to use (e.g., your class's self.debug/self.error source)
        action_desc: A string describing the action, formatted with *args/**kwargs values
        success_desc: Optional string for success messages (defaults to a generic "done" message)
        success_check: Optional function to determine if the function succeeded (for non-exceptional failures)
    """
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # Log the starting action
            logger.debug(f":- {action_desc.format(*args, **kwargs)}")
            
            try:
                result = func(*args, **kwargs)
            except Exception as e:
                # Log exceptions and return False (or re-raise if you prefer callers to handle it)
                logger.error(f":- Failed to {action_desc.format(*args, **kwargs)}; Error: {str(e)}")
                return False
            else:
                # Handle non-exceptional failures if a success check is provided
                if success_check is not None and not success_check(result):
                    logger.error(f":- Failed to {action_desc.format(*args, **kwargs)}; Result: {str(result)}")
                    return False
                
                # Log success
                if success_desc:
                    logger.debug(f":- {success_desc.format(*args, **kwargs)}")
                else:
                    logger.debug(f":- Done with {action_desc.format(*args, **kwargs)}")
                return result
        return wrapper
    return decorator

How to Use It for shutil.copytree

Since shutil.copytree throws exceptions on failure, you can use the decorator without a success_check:

import shutil

class YourFileHandler:
    def __init__(self):
        # Assuming your logger is configured here (maps to self.debug/self.error)
        self.logger = logging.getLogger(__name__)
        
        # Wrap shutil.copytree as an instance method
        self.copytree = log_function_call(
            logger=self.logger,
            action_desc="Copying tree from \"{0}\" to \"{1}\"",
            success_desc="Successfully copied tree from \"{0}\" to \"{1}\""
        )(shutil.copytree)

# Usage in your code:
handler = YourFileHandler()
handler.copytree("/path/to/source", "/path/to/dest")

Handling Non-Exception-Throwing Functions

For functions that don’t throw exceptions but return a status code or boolean (like subprocess.call), use the success_check parameter to define what counts as a failure:

import subprocess

def check_subprocess_success(returncode):
    # Return True if the command succeeded (standard 0 return code)
    return returncode == 0

class YourCommandRunner:
    def __init__(self):
        self.logger = logging.getLogger(__name__)
        
        self.run_command = log_function_call(
            logger=self.logger,
            action_desc="Running command: {0}",
            success_desc="Command {0} completed successfully",
            success_check=check_subprocess_success
        )(subprocess.call)

# Usage:
runner = YourCommandRunner()
runner.run_command(["echo", "Hello World"])  # Logs success
runner.run_command(["invalid-command"])     # Logs failure

Key Benefits of This Approach

  • No Repetition: Define your logging logic once and apply it to any function
  • Flexibility: Customize messages and success criteria per function
  • Preserves Original Behavior: Uses functools.wraps to keep the original function’s name, docstring, and signature intact
  • Centralized Error Handling: All logging and failure logic lives in one place, making it easy to update later

Your original copytree implementation works great, but this generic wrapper scales seamlessly to all the shutil, subprocess, and other library functions you need to log.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:34:55