我不知道有什么东西可以做到这一点,但我确实为一个项目写了一些东西,该项目通过简单地将装饰器添加到相关函数来实现这一点。
我创建了一组装饰器,用于测量函数的运行时间、测量 DB 访问函数的时间等。
这种装饰器的一个例子是:
def func_runtime(method):
@functools.wraps(method)
def wrapper(self, *args, **kwargs):
start_time = datetime.datetime.utcnow()
try:
class_name = type(self).__name__
method_name = method.__name__
return method(self, *args, **kwargs)
finally:
end_time = datetime.datetime.utcnow() - start_time
time_taken_ms = end_time.microseconds / 1000
if _statsd:
# Send the data to statsD, but you can do that for CopperEgg or anything else
self.stats.timing("func.runtime.%s.%s" % (class_name, method_name), time_taken_ms)
稍后你会像这样使用它:
@func_runtime
def myfunc(a, b, c):
pass
我还为从数据库读取的函数和写入数据库的函数添加了一个装饰器,这样我就可以得到关于代码等待读取数据或写入数据所花费的时间以及我称之为“读取”的次数的图表操作和“写”操作。
所以,总而言之,我有以下装饰器: - @func_runtime - 测量函数的运行时间 - @func_dbread - 放置在执行读取的函数上。增加一个 database.reads 计数器并将计时数据发送到 read_timing - @func_dbwrite - 与 @func_dbread 相同,但用于写入 - @func dbruntime - 用于测量 DB 特定函数的运行时间以及调用次数和总计时所有数据库功能
您可以组合装饰器,它们以最接近函数的顺序运行,例如:
@func_dbruntime
@func_dbread
def some_db_read_function(a, b, c,d):
pass
所以,@func_dbread 在@func_dbruntime 之前运行。
总而言之,它易于定制且非常强大,您可以将其扩展为支持 3rd 方服务以及添加代码以在相关时动态打开和关闭这些计数器。据我所知,性能损失充其量是最小的。
只是关于向 CopperEgg 和其他服务等地方发送数据的通知,StatsD 使用 UDP,由于它的统计数据,您可能会丢失一些数据,但仍然可以获得有意义的见解,它不会阻止任何事情。如果您想将数据发送到像 CopperEgg 这样的 3rd 方站点,我会考虑将数据发送到本地队列,然后使用不同的流程将其推送到 CopperEgg,以便将 3rd 方服务问题与您自己的问题解耦。
就个人而言,对于此类数据,StatsD 非常棒,graphite 为您提供了所有您需要的东西,包括 90th percentile、average、max、绘图能力等,并且基本上具有您需要的大多数计数器类型。