Je ne suis pas au courant de quelque chose qui fait exactement cela, mais j'ai écrit quelque chose il y a quelque temps pour un projet qui fait cela en ajoutant simplement des décorateurs aux fonctions pertinentes.
J'ai créé un ensemble de décorateurs pour mesurer le temps d'exécution des fonctions, mesurer le temps des fonctions d'accès à la base de données, etc.
Voici un exemple d'un tel décorateur :
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)
Plus tard, vous l'utiliserez comme ceci :
@func_runtime
def myfunc(a, b, c):
pass
J'ai également ajouté un décorateur pour les fonctions qui lisent à partir de la base de données et les fonctions qui écrivent dans la base de données afin que je puisse obtenir des graphiques sur le temps que le code a passé à attendre pour lire des données ou écrire des données ainsi que le nombre de fois où j'ai appelé des opérations de "lecture" et des opérations d'"écriture".
Donc, en tout et pour tout, j'ai eu les décorateurs suivants : - @func_runtime - pour mesurer le temps d'exécution d'une fonction - @func_dbread - placé sur les fonctions qui effectuent des lectures. Augmente le compteur database.reads et envoie des données de synchronisation à read_timing. - @func_dbwrite - identique à @func_dbread mais pour les écritures. - @func dbruntime - utilisé pour mesurer le temps d'exécution des fonctions spécifiques à la BD ainsi que le nombre d'appels et le temps total de toutes les fonctions de la BD.
Vous pouvez combiner les décorateurs et ils s'exécutent dans l'ordre le plus proche de la fonction, par exemple :
@func_dbruntime
@func_dbread
def some_db_read_function(a, b, c,d):
pass
Ainsi, @func_dbread s'exécute avant @func_dbruntime.
Dans l'ensemble, il est facilement personnalisable et TRÈS puissant, et vous pouvez l'étendre pour prendre en charge des services tiers ainsi qu'ajouter du code pour activer et désactiver dynamiquement ces compteurs lorsque cela est nécessaire. D'après ce que j'ai pu constater, l'impact sur les performances est au mieux minime.
Juste une remarque à propos de l'envoi de données à des endroits comme CopperEgg et d'autres services, StatsD utilise UDP et comme il s'agit de statistiques, vous pouvez perdre quelques données tout en obtenant des informations significatives et il ne bloquera rien. Si vous voulez envoyer des données à des sites tiers comme CopperEgg, j'envisagerais d'envoyer les données dans une file d'attente locale, puis de les pousser avec un processus différent vers CopperEgg, juste pour découpler les problèmes des services tiers des vôtres.
Personnellement, pour ce type de données, StatsD est excellent et Graphite vous donne tout ce dont vous avez besoin, y compris le 90ème percentile, la moyenne, le maximum, les capacités graphiques, etc. et dispose de la plupart des types de compteurs dont vous avez besoin.