【发布时间】:2013-01-17 17:31:47
【问题描述】:
我想在某个类中进行调用时记录调试信息。记录的数据是:
- 函数名
- 函数调用位置的堆栈跟踪
- 函数执行的时间
- args 和 kwargs 传递给函数
我希望包装器相当通用。同时,包装应该在运行时进行。我制作了以下包装类来记录信息并将调用委托给原始实例。
import datetime
import traceback
from functools import partial
from logging_module import db_log
class BaseWrapper(object):
def __init__(self, item):
self._item = item
def __getattr__(self, attr):
return getattr(self._item, attr)
class DBLogWrapper(BaseWrapper):
@staticmethod
def _time_method(method):
name = "{0}.{1}.{2}".format(
method.im_class.__module__,
method.im_class.__name__,
method.__name__
)
def timed_method(self, *args, **kwargs):
begin = datetime.datetime.now()
return_val = method.im_func(self, *args, **kwargs)
end = datetime.datetime.now()
trace = traceback.format_stack()
db_log(
name,
begin,
end,
info={
'args': args,
'kwargs': kwargs,
'trace': trace
}
)
return return_val
return timed_method
def __init__(self, item, methods):
super(DBLogWrapper, self).__init__(item)
for method in methods:
class_method = getattr(item, method)
wrapped_method = DBLogWrapper._time_method(class_method)
wrapped_method = partial(wrapped_method, self._item)
setattr(self, method, wrapped_method)
示例用法:
class MyClass(object):
def hello(self, greeting):
print greeting
def goodbye(self):
print 'Good Bye'
a = MyClass()
if DEBUG:
a = DBLogWrapper(a, ['hello'])
a.hello()
a.goodbye()
在这种情况下,对hello 的调用将被记录,但对goodbye 的调用不会。
但是,对于一个看起来应该很简单的任务来说,这似乎有点过头了。我正在寻找有关如何改进上述代码或完全不同的方法的建议。
【问题讨论】:
-
这有什么过分的?
-
整个解决方案对我来说似乎很复杂。在委托包装器中使用 partial 来使实例方法按预期工作。只是感觉有点太老套了
-
您为什么不简单地编写一个装饰器并将其应用于您想要跟踪的方法?我认为它更简单,更清晰。
-
好吧,它本质上已经是一个装饰器了。但是,出于几个原因,我不想仅仅装饰类方法。首先,因为我无法访问我想要跟踪的方法。它们在第 3 方模块中定义。其次,因为我希望在运行时根据某些标志应用这些装饰器。我不想一直打开它们。
标签: python logging dynamic metaprogramming wrapper