2013-07-07 6 views
1

Je suis en train de prototyper un framework d'application web en Python (principalement à des fins éducatives) et je suis bloqué sur une fonctionnalité que je voulais depuis longtemps: le niveau de journalisation par route.Niveau de journalisation dépendant du contexte en Python

Le but de cette fonctionnalité est d'identifier certains points d'entrée spécifiques pour lesquels nous effectuons des diagnostics. Par exemple, je souhaite savoir ce qui se passe lorsque les appelants cliquent sur POST /sessions/login. Maintenant, je veux obtenir 100% des entrées de journal pour le code touché par le traitement de la demande pour cette URL. Et cela signifie tout, y compris ce qui se passe dans les applications tierces.

Exemple: l'application fictive a deux voies: /sessions/login et /sessions/info. Les deux gestionnaires de requêtes touchent le même code de base de données dans le lot users, qui utilise le consignateur myapp.users.db. Le traitement de la demande pour /sessions/login doit émettre des messages de journal sur le consignateur myapp.users.db, mais pas le traitement de la demande pour /sessions/info. Le problème est que cela ne cadre pas bien avec la bibliothèque de journalisation de Python, qui décompose la journalisation d'une manière hiérarchique, ce qui est agréable pour la superposition (par exemple le contrôle du niveau de journalisation par les couches d'application).

Ce que je veux vraiment, c'est un niveau de journalisation dépendant du contexte. L'implémentation naturelle qui vient à l'esprit est que logger.getEffectiveLevel() renvoie un niveau de consignation thread-local (avec le middleware de débogage abaissant de manière conditionnelle le niveau de consignation au débogage si l'URL de la requête est soumise au débogage). Cependant, je regarde le logging flow dans la documentation de Python, et je ne comprends pas comment implémenter cela en utilisant l'un des différents types de crochets de configuration.


Question: comment voulez-vous mettre en œuvre un niveau de journal dépendant du contexte en Python?


Mise à jour: J'ai trouvé une solution partielle.

context = threading.local() 

class ContextualLogger(logging.Logger): 
    def getEffectiveLevel(self): 
     global context 
     level = getattr(context, 'log_level', logging.NOTSET) 
     if level == logging.NOTSET: 
      level = super(ContextualLogger, self).getEffectiveLevel() 
     return level 

logging.setLoggerClass(ContextualLogger) 

Toutefois, cela ne fonctionne pas pour l'enregistreur racine. Des idées?


Mise à jour: il est également possible de singe patcher la fonction getEffectiveLevel().

context = threading.local() 

# Monkey patch "getEffectiveLevel()" to consult the current setting in the 
# `context.log_level` thread-local storage. If that value is present, use 
# it to override the current value; else, compute the level using the usual 
# infrastructure. 
default_getEffectiveLevel = logging.Logger.getEffectiveLevel 
def patched_getEffectiveLevel(self): 
    level = getattr(context, 'log_level', logging.NOTSET) 
    if level == logging.NOTSET: 
     level = default_getEffectiveLevel(self) 
    return level 
logging.Logger.getEffectiveLevel = patched_getEffectiveLevel 

Maintenant, cela fonctionne même pour l'enregistreur de racine. Je dois admettre que je suis un peu mal à l'aise avec monkey corrigeant cette fonction, mais là encore, il retombe sur l'infrastructure habituelle, donc ce n'est pas aussi sale que ça en a l'air.

Répondre

0

Vous êtes mieux d'utiliser un logging.Filter qui est attaché à vos enregistreurs (ou gestionnaires) qui utilise le contexte soit abandonner l'événement (en retournant False de la méthode filter) ou permettre d'être consigné l'événement (en repositionnant True de la méthode filter).

Bien que ce ne soit pas exactement pour votre cas d'utilisation, j'ai illustré l'utilisation de filtres avec contexte local-thread dans this post.

+0

Étant donné que cette solution me permet uniquement d'appliquer un niveau de journalisation plus strict que celui déjà appliqué (le filtre peut appliquer le 'logging.WARNING' lorsque le niveau actuel est' logging.DEBUG', mais pas l'inverse), Je suppose que je vais devoir configurer tous les enregistreurs au niveau 'logging.DEBUG' et ensuite contrôler le niveau de journal seulement de la variable de fil alors? Comparez cela avec la solution partielle dans mes questions, ce qui vous permet de remplacer complètement le niveau de journal effectif, quel que soit le niveau actuel. –

Questions connexes