当前位置: 代码网 > it编程>前端脚本>Python > 使用Python装饰器实现日志记录功能

使用Python装饰器实现日志记录功能

2026年08月09日 Python 我要评论
引言在现代软件开发中,日志记录(logging)是保障系统稳定性、可维护性和可追溯性的核心手段。无论是调试代码、排查问题,还是监控系统运行状态,日志都扮演着“数字日记”的角色。

引言

在现代软件开发中,日志记录(logging)是保障系统稳定性、可维护性和可追溯性的核心手段。无论是调试代码、排查问题,还是监控系统运行状态,日志都扮演着“数字日记”的角色。而 python 装饰器(decorator)作为一种优雅的语法糖,为日志记录提供了极佳的实现方式。

今天,我们将深入探讨装饰器在日志记录中的应用场景,并通过实战代码构建一个灵活、可扩展的日志系统。你将学会如何用装饰器为函数“自动添加”日志行为,无需修改原始逻辑,真正做到“无侵入式”日志增强。

什么是装饰器?为什么它适合日志记录?

装饰器的本质:函数的“包装器”

在 python 中,装饰器本质上是一个接受函数作为参数并返回新函数的高阶函数。它的核心思想是:不修改原函数代码,为其动态添加额外功能

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("👉 函数执行前")
        result = func(*args, **kwargs)
        print("👉 函数执行后")
        return result
    return wrapper

@my_decorator
def say_hello():
    print("hello, world!")

say_hello()

输出:

👉 函数执行前
hello, world!
👉 函数执行后

关键优势:无需改动 say_hello 的原始定义,就能为其注入“前后执行日志”。

日志记录的核心需求分析

一个理想的日志系统应具备以下特性:

特性说明
✅ 无侵入性不修改业务代码
✅ 可配置性支持不同级别(debug/info/warning/error)
✅ 上下文信息记录函数名、调用参数、执行时间等
✅ 异常捕获自动记录错误堆栈
✅ 多输出目标可写入文件、控制台、远程服务

这些需求与装饰器的“封装增强”理念完美契合。下面我们一步步实现一个完整的日志装饰器系统。

第一步:基础日志装饰器设计

我们从最简单的版本开始,逐步增强功能。

基础版:记录函数调用基本信息

import functools
import time
from datetime import datetime

def log_execution(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        print(f"🟢 [{datetime.now()}] 🔍 调用函数: {func.__name__}")
        
        try:
            result = func(*args, **kwargs)
            end_time = time.time()
            duration = (end_time - start_time) * 1000  # ms
            print(f"✅ [{datetime.now()}] 🕒 执行耗时: {duration:.2f}ms")
            return result
        except exception as e:
            end_time = time.time()
            duration = (end_time - start_time) * 1000
            print(f"❌ [{datetime.now()}] ⚠️ 执行异常: {e} (耗时: {duration:.2f}ms)")
            raise
    return wrapper

使用示例

@log_execution
def calculate_sum(a, b):
    time.sleep(0.1)  # 模拟耗时操作
    return a + b

result = calculate_sum(5, 3)
print(f"最终结果: {result}")

输出:

🟢 [2024-04-05 14:30:22.123456] 🔍 调用函数: calculate_sum
✅ [2024-04-05 14:30:22.223456] 🕒 执行耗时: 100.00ms
最终结果: 8

小贴士:@functools.wraps(func) 保留了原函数的元数据(如 __name____doc__),避免被覆盖。

第二步:支持多种日志级别与配置

我们进一步升级,引入日志等级(debug、info、warning、error),并支持配置。

配置类设计

from enum import enum

class loglevel(enum):
    debug = "debug"
    info = "info"
    warning = "warning"
    error = "error"

class loggerconfig:
    def __init__(self, level=loglevel.info, output="console"):
        self.level = level
        self.output = output  # console / file
    
    def should_log(self, level):
        levels = {
            loglevel.debug: 1,
            loglevel.info: 2,
            loglevel.warning: 3,
            loglevel.error: 4
        }
        return levels[level] >= levels[self.level]

升级后的装饰器

def log_with_config(config=none):
    if config is none:
        config = loggerconfig()

    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 等级判断
            if not config.should_log(loglevel.info):
                return func(*args, **kwargs)

            start_time = time.time()
            log_msg = f"📊 [{datetime.now()}] {func.__name__} 启动"
            if config.should_log(loglevel.debug):
                log_msg += f" | 参数: args={args}, kwargs={kwargs}"
            
            print(log_msg)

            try:
                result = func(*args, **kwargs)
                end_time = time.time()
                duration = (end_time - start_time) * 1000

                if config.should_log(loglevel.info):
                    print(f"✅ [{datetime.now()}] 🕒 成功执行,耗时: {duration:.2f}ms")

                return result
            except exception as e:
                end_time = time.time()
                duration = (end_time - start_time) * 1000
                error_msg = f"❌ [{datetime.now()}] ⚠️ 异常: {str(e)} (耗时: {duration:.2f}ms)"
                print(error_msg)
                raise
        return wrapper
    return decorator

使用示例

# 高级别日志(仅显示info+)
config_high = loggerconfig(level=loglevel.info)
@log_with_config(config_high)
def divide(a, b):
    return a / b

divide(10, 2)

# 详细日志(包含debug)
config_debug = loggerconfig(level=loglevel.debug)
@log_with_config(config_debug)
def process_data(data):
    time.sleep(0.05)
    return sum(data)

process_data([1, 2, 3])

输出:

📊 [2024-04-05 14:35:10.500] divide 启动
✅ [2024-04-05 14:35:10.505] 🕒 成功执行,耗时: 5.00ms
📊 [2024-04-05 14:35:10.510] process_data 启动 | 参数: args=([1, 2, 3],), kwargs={}
✅ [2024-04-05 14:35:10.560] 🕒 成功执行,耗时: 50.00ms

第三步:支持异步函数的日志记录

现代 python 应用越来越多地使用 async/await。我们需要让装饰器支持异步函数。

异步装饰器实现

import asyncio

def async_log_execution(config=none):
    if config is none:
        config = loggerconfig()

    def decorator(func):
        @functools.wraps(func)
        async def wrapper(*args, **kwargs):
            if not config.should_log(loglevel.info):
                return await func(*args, **kwargs)

            start_time = time.time()
            print(f"🟢 [{datetime.now()}] 🌀 异步函数启动: {func.__name__}")

            try:
                result = await func(*args, **kwargs)
                end_time = time.time()
                duration = (end_time - start_time) * 1000
                print(f"✅ [{datetime.now()}] 🕒 异步执行完成,耗时: {duration:.2f}ms")
                return result
            except exception as e:
                end_time = time.time()
                duration = (end_time - start_time) * 1000
                print(f"❌ [{datetime.now()}] ⚠️ 异步异常: {e} (耗时: {duration:.2f}ms)")
                raise
        return wrapper
    return decorator

异步使用示例

@async_log_execution()
async def fetch_data(url):
    print(f"📥 正在请求: {url}")
    await asyncio.sleep(1)
    return f"✅ 数据已获取: {url}"

# 运行异步任务
async def main():
    data = await fetch_data("https://api.example.com/data")
    print(data)

# 启动事件循环
asyncio.run(main())

输出:

🟢 [2024-04-05 14:40:00.100] 🌀 异步函数启动: fetch_data
📥 正在请求: https://api.example.com/data
✅ [2024-04-05 14:40:01.100] 🕒 异步执行完成,耗时: 1000.00ms
✅ 数据已获取: https://api.example.com/data

✅ 该装饰器能无缝处理 async def 函数,保持异步特性不变。

第四步:集成性能监控与统计

除了日志,我们还可以用装饰器收集性能指标,比如调用次数、平均耗时。

性能统计装饰器

from collections import defaultdict

performance_stats = defaultdict(lambda: {"count": 0, "total_time": 0})

def monitor_performance(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func_name = func.__name__
        
        try:
            result = func(*args, **kwargs)
            end_time = time.time()
            duration = (end_time - start_time) * 1000
            
            # 更新统计
            performance_stats[func_name]["count"] += 1
            performance_stats[func_name]["total_time"] += duration
            
            return result
        except exception as e:
            end_time = time.time()
            duration = (end_time - start_time) * 1000
            performance_stats[func_name]["count"] += 1
            performance_stats[func_name]["total_time"] += duration
            raise
    return wrapper

# 查看统计信息
def show_performance():
    print("\n📊 性能统计报告:")
    for func_name, stats in performance_stats.items():
        avg_time = stats["total_time"] / stats["count"]
        print(f"   📌 {func_name}: 调用 {stats['count']} 次, 平均耗时 {avg_time:.2f}ms")

使用示例

@monitor_performance
def slow_function(n):
    time.sleep(0.2)
    return n * 2

for i in range(5):
    slow_function(i)

show_performance()

输出:

📊 性能统计报告:
   📌 slow_function: 调用 5 次, 平均耗时 200.00ms

这种模式可用于生产环境的性能埋点,无需侵入业务代码。

用 mermaid 展示装饰器工作流程图

该图表清晰展示了装饰器在调用链中的作用:拦截 → 增强 → 传递

第五步:支持多装饰器组合

在实际项目中,我们可能需要同时启用多个功能,例如:日志 + 性能监控 + 权限检查

组合装饰器使用

@log_with_config(loggerconfig(level=loglevel.debug))
@monitor_performance
@async_log_execution()
async def api_handler(user_id, action):
    print(f"👤 处理用户 {user_id} 的 {action} 请求")
    await asyncio.sleep(0.3)
    return f"✅ {action} 成功执行"

# 测试
asyncio.run(api_handler(123, "login"))

输出:

🟢 [2024-04-05 14:50:00.000] 🌀 异步函数启动: api_handler
📊 [2024-04-05 14:50:00.001] api_handler 启动 | 参数: args=(123, 'login'), kwargs={}
👤 处理用户 123 的 login 请求
✅ [2024-04-05 14:50:00.301] 🕒 异步执行完成,耗时: 301.00ms
✅ login 成功执行

装饰器按从下到上的顺序应用,即:@log -> @monitor -> @async_log,形成一层层的“包裹”。

总结:装饰器在日志记录中的价值

通过本篇实战,我们实现了:

  • ✅ 无侵入式日志记录
  • ✅ 支持同步/异步函数
  • ✅ 多级别日志控制
  • ✅ 性能监控与统计
  • ✅ 装饰器组合能力

装饰器不仅是语法糖,更是架构设计的利器。它让我们能够以“插件式”方式增强函数行为,极大提升代码的可维护性与可复用性。

附加技巧:如何快速创建通用日志装饰器?

你可以将上述功能封装成一个可复用的模块:

# logger_utils.py(仅示意)
def create_logger(level=loglevel.info, enable_monitoring=false):
    config = loggerconfig(level=level)
    
    def decorator(func):
        if enable_monitoring:
            func = monitor_performance(func)
        func = log_with_config(config)(func)
        return func
    return decorator

然后轻松使用:

@create_logger(level=loglevel.debug, enable_monitoring=true)
def my_api():
    return "ok"

结语

日志不是“事后补救”,而是开发过程中的第一道防线。而装饰器,正是我们构建这道防线的最佳工具。

当你下次需要为某个函数加日志时,不妨想想:能不能用装饰器来解决?

答案是:完全可以!

让你的代码更优雅,让日志更智能,从一个小小的装饰器开始吧!

以上就是使用python装饰器实现日志记录功能的详细内容,更多关于python装饰器日志记录的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com