web-dev-qa-db-fra.com

Comment changer de filehandle avec la journalisation Python à la volée avec différentes classes et importations

Je ne peux pas effectuer de changement de fileHandle de journalisation à la volée.

Par exemple, j'ai 3 cours

one.py

import logging
class One():
    def __init__(self,txt="?"):
        logging.debug("Hey, I'm the class One and I say: %s" % txt)

two.py

import logging
class Two():
    def __init__(self,txt="?"):
        logging.debug("Hey, I'm the class Two and I say: %s" % txt)

config.py

import logging
class Config():
    def __init__(self,logfile=None):
        logging.debug("Reading config")
        self.logfile(logfile)

myapp

from one import One
from two import Two
from config import Config
import logging

#Set default logging
logging.basicConfig( 
    level=logging.getLevelName(DEBUG), 
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    filename=None
)

logging.info("Starting with stdout")

o=One(txt="STDOUT")
c=Config(logfile="/tmp/logfile")

# Here must be the code that change the logging configuration and set the filehandler

t=One(txt="This must be on the file, not STDOUT")

Si j'essaie à nouveau loggin.basicConfig(), cela ne fonctionne pas.

33
xkill

En effet, logging.basicConfig ne fait rien si un gestionnaire a déjà été configuré:

Cette fonction ne fait rien si le logger racine a déjà des gestionnaires configurés pour elle.

Vous aurez besoin de remplacer le gestionnaire actuel sur le logger racine:

import logging

fileh = logging.FileHandler('/tmp/logfile', 'a')
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fileh.setFormatter(formatter)

log = logging.getLogger()  # root logger
for hdlr in log.handlers[:]:  # remove all old handlers
    log.removeHandler(hdlr)
log.addHandler(fileh)      # set the new handler

Reportez-vous au chapitre Configuration de la journalisation dans le HOWTO Python Logging.

43
Martijn Pieters

J'ai trouvé un moyen plus facile que la réponse «acceptée» ci-dessus. Si vous avez une référence au gestionnaire, il vous suffit d'appeler la méthode close (), puis de définir la propriété baseFilename. Lorsque vous associez baseFilename, veillez à utiliser os.path.abspath (). Il y a un commentaire dans la source de la bibliothèque qui indique que c'est nécessaire. Je garde mes informations de configuration dans un dict global (), il est donc facile de conserver les objets de référence FileHandler. Comme vous pouvez le voir ci-dessous, il ne faut que 2 lignes de code pour modifier le nom du fichier journal d'un gestionnaire à la volée.

import logging

def setup_logging():
  global config

  if config['LOGGING_SET']:
    config['LOG_FILE_HDL'].close()
    config['LOG_FILE_HDL'].baseFilename = os.path.abspath(config['LOG_FILE'])

    config['DEBUG_LOG_HDL'].close()
    config['DEBUG_LOG_HDL'].baseFilename = os.path.abspath(config['DEBUG_LOG'])
  else:
    format_str = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
    formatter = logging.Formatter(format_str)

    log = logging.getLogger()

    log.setLevel(logging.DEBUG)

    # add file mode="w" to overwrite
    config['LOG_FILE_HDL'] = logging.FileHandler(config['LOG_FILE'], mode='a')
    config['LOG_FILE_HDL'].setLevel(logging.INFO)
    config['LOG_FILE_HDL'].setFormatter(formatter)
    log.addHandler(config['LOG_FILE_HDL'])

    # the delay=1 should prevent the file from being opened until used.
    config['DEBUG_LOG_HDL'] = logging.FileHandler(config['DEBUG_LOG'], mode='a', delay=1)
    config['DEBUG_LOG_HDL'].setLevel(logging.DEBUG)
    config['DEBUG_LOG_HDL'].setFormatter(formatter)
    log.addHandler(config['DEBUG_LOG_HDL'])

    ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    ch.setFormatter(formatter)
    log.addHandler(ch)
    config['LOGGING_SET'] = True
6
user2179204

La réponse fournie par @Martijn Pieters fonctionne bien. Toutefois, le coupeur de code supprime tous les gestionnaires et ne place que le gestionnaire de fichiers. Ce sera gênant si votre application a des gestionnaires ajoutés par d'autres modules. 

Ainsi, l'extrait de code ci-dessous est conçu de manière à ne remplacer que le gestionnaire de fichiers.

La ligne if isinstance(hdlr,log.FileHander) est la clé.

import logging

filehandler = logging.FileHandler('/tmp/logfile', 'a')
formatter = logging.Formatter('%(asctime)-15s::%(levelname)s::%(filename)s::%(funcName)s::%(lineno)d::%(message)s')
filehandler.setFormatter(formatter)
log = logging.getLogger()  # root logger - Good to get it only once.
for hdlr in log.handlers[:]:  # remove the existing file handlers
    if isinstance(hdlr,log.FileHander):
        log.removeHandler(hdlr)
log.addHandler(filehandler)      # set the new handler
# set the log level to INFO, DEBUG as the default is ERROR
logging.setLevel(log.DEBUG)      

J'ai essayé de mettre en œuvre les suggestions sur cette page de @Martijn Pieters combinées avec @Arun Thundyill Saseendran. Je suis trop nouvelle pour pouvoir faire un commentaire et je dois donc poster une réponse corrigée. Dans l'appel isinstance, je devais utiliser "logging" au lieu de "log" pour accéder aux types (log était une instance), puis "FileHander" devait être "FileHandler". J'utilise Python 3.6.

import logging

filehandler = logging.FileHandler('/tmp/logfile', 'a')
formatter = logging.Formatter('%(asctime)-15s::%(levelname)s::%(filename)s::%(funcName)s::%(lineno)d::%(message)s')
filehandler.setFormatter(formatter)
log = logging.getLogger()  # root logger - Good to get it only once.
for hdlr in log.handlers[:]:  # remove the existing file handlers
    if isinstance(hdlr,logging.FileHandler): #fixed two typos here
        log.removeHandler(hdlr)
log.addHandler(filehandler)      # set the new handler
# set the log level to INFO, DEBUG as the default is ERROR
logging.setLevel(log.DEBUG)      
0
T. Haggis