2010-05-02 4 views
5

Je souhaite configurer mon enregistreur Python de manière à ce que chaque instance de l'enregistreur enregistre un fichier portant le même nom que le nom de l'enregistreur lui-même.Nom de fichier dynamique Python

.: par exemple

log_hm = logging.getLogger('healthmonitor') 
log_hm.info("Testing Log") # Should log to /some/path/healthmonitor.log 

log_sc = logging.getLogger('scripts') 
log_sc.debug("Testing Scripts") # Should log to /some/path/scripts.log 

log_cr = logging.getLogger('cron') 
log_cr.info("Testing cron") # Should log to /some/path/cron.log 

Je veux garder générique et ne veux pas coder toutes sortes de noms d'enregistreur que je peux avoir. Est-ce possible?

Répondre

7
import os 
import logging 

class MyFileHandler(object): 

    def __init__(self, dir, logger, handlerFactory, **kw): 
     kw['filename'] = os.path.join(dir, logger.name) 
     self._handler = handlerFactory(**kw) 

    def __getattr__(self, n): 
     if hasattr(self._handler, n): 
      return getattr(self._handler, n) 
     raise AttributeError, n 

logger = logging.getLogger('test') 
logger.setLevel(logging.INFO) 
handler = MyFileHandler(os.curdir, logger, logging.FileHandler) 
logger.addHandler(handler) 
logger.info('hello mylogger') 
+0

Pourrait-il être possible d'ajouter le gestionnaire avant l'appel "getLogger" de sorte que je n'ai pas à l'ajouter à chaque fois que j'appelle getLogger? – sharjeel

+1

@sharjeel: Définit le gestionnaire lors de l'initialisation et tous les futurs appels à 'getLogger()' n'ont pas besoin d'ajouter un gestionnaire. La solution est similaire à celle de ~ unutbu. Dans cet exemple, myLogger devrait être appelé une seule fois pour le fichier, sinon vous aurez des effets secondaires étranges. –

+0

J'aime cette approche. Vous pouvez également garder une trace des fichiers ouverts et pour une nouvelle instance, vérifiez si le fichier est déjà ouvert puis ne rouvrez pas. Cependant, ce genre de science n'est pas requis dans mon cas :-) – sharjeel

13

Que diriez-vous simplement envelopper le code de gestionnaire dans une fonction:

import os 
def myLogger(name): 
    logger = logging.getLogger(name) 
    logger.setLevel(logging.DEBUG) 
    handler = logging.FileHandler(os.path.join('/some/path/', name + '.log'), 'w') 
    logger.addHandler(handler) 
    return logger 

log_hm = myLogger('healthmonitor') 
log_hm.info("Testing Log") # Should log to /some/path/healthmonitor.log 
+1

Ceci est une solution viable, mais je cherche quelque chose de plus Pythonic. Pourrait-il y avoir un moyen d'exploiter la structure de journalisation Python existante plutôt que d'ajouter un wrapper par-dessus? – sharjeel

+0

Il y a un problème avec cette approche. Il ajoute des gestionnaires en double lorsqu'il est appelé plusieurs fois avec le même nom. Et l'ouverture du fichier est en mode écriture pour effacer les données antérieures. –

+0

Il y a aussi quelque chose qui ne va pas chez mon grille-pain, puisque chaque fois que je grille des choses deux fois, elles ne sortent pas comme la première fois. :) – unutbu

0

L'approche utilisée dans la solution ci-dessus est correcte, mais qui a question de l'ajout de gestionnaires en double lorsque appelé plus d'une fois. Voici la version améliorée.

import os 
def getLogger(name): 
    # logger.getLogger returns the cached logger when called multiple times 
    # logger.Logger created a new one every time and that avoids adding 
    # duplicate handlers 
    logger = logging.Logger(name) 
    logger.setLevel(logging.DEBUG) 
    handler = logging.FileHandler(os.path.join('/some/path/', name + '.log'), 'a') 
    logger.addHandler(handler) 
    return logger 

def test(i): 
    log_hm = getLogger('healthmonitor') 
    log_hm.info("Testing Log %s", i) # Should log to /some/path/healthmonitor.log 

test(1) 
test(2)