4
votes

Journalisation Python - nouveau fichier journal à chaque itération de boucle

Je voudrais générer un nouveau fichier journal à chaque itération d'une boucle en Python en utilisant le module de journalisation. J'analyse des données dans une boucle for, où chaque itération de la boucle contient des informations sur un nouvel objet. Je souhaite générer un fichier journal par objet.

J'ai regardé la documentation du module de journalisation et il est possible de modifier le fichier journal à des intervalles de temps ou lorsque le fichier journal se remplit, mais je ne vois pas comment générer de manière itérative un nouveau fichier journal avec un nouveau nom. Je sais à l'avance combien d'objets sont dans la boucle.

Mon pseudo-code imaginé serait:

import logging

for target in targets:
    logfile_name = f"{target}.log"
    logging.basicConfig(format='%(asctime)s - %(levelname)s : %(message)s',
                        datefmt='%Y-%m/%dT%H:%M:%S',
                        filename=logfile_name,
                        level=logging.DEBUG)


    # analyse target infomation
    logging.info('log target info...')

Cependant, les informations de journalisation sont toujours ajoutées au premier fichier journal de la cible 1.

Existe-t-il un moyen de forcer un nouveau fichier journal au début de chaque boucle?


0 commentaires

4 Réponses :


0
votes

Voici une version fonctionnelle de ce problème. Je n'ai pu le faire fonctionner que si les cibles avaient déjà .log avant d'entrer dans la boucle, vous pouvez donc en ajouter un de plus avant d'entrer dans les cibles et remplacer toutes les cibles avec l'extension .log

import logging

targets = ["a.log","b.log","c.log"]
for target in targets:

    log = logging.getLogger(target)
    formatter = logging.Formatter('%(asctime)s - %(levelname)s : %(message)s', datefmt='%Y-%m/%dT%H:%M:%S')
    fileHandler = logging.FileHandler(target, mode='a')
    fileHandler.setFormatter(formatter)
    streamHandler = logging.StreamHandler()
    streamHandler.setFormatter(formatter)
    log.addHandler(fileHandler)
    log.addHandler(streamHandler)

    log.info('log target info...')


0 commentaires

3
votes

Ce n'est peut-être pas la meilleure solution, mais cela créera un nouveau fichier journal pour chaque itération. Ce que cela fait, c'est ajouter un nouveau gestionnaire de fichiers à chaque itération.

import logging
targets = ["a", "b", "c"]
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

for target in targets:
    log_file = "{}.log".format(target)
    log_format = "|%(levelname)s| : [%(filename)s]--[%(funcName)s] : %(message)s"
    formatter = logging.Formatter(log_format)

    # create file handler and set the formatter
    file_handler = logging.FileHandler(log_file)
    file_handler.setFormatter(formatter)

    # add handler to the logger
    logger.addHandler(file_handler)

    # sample message
    logger.info("Log file: {}".format(target))


0 commentaires

5
votes

Plutôt que d'utiliser directement la journalisation , vous devez utiliser des objets de journalisation. Consultez la documentation ici .

Créez un nouveau objet logger comme première instruction de la boucle. Voici une solution de travail.

import logging
import sys


def my_custom_logger(logger_name, level=logging.DEBUG):
    """
    Method to return a custom logger with the given name and level
    """
    logger = logging.getLogger(logger_name)
    logger.setLevel(level)
    format_string = ("%(asctime)s — %(name)s — %(levelname)s — %(funcName)s:"
                    "%(lineno)d — %(message)s")
    log_format = logging.Formatter(format_string)
    # Creating and adding the console handler
    console_handler = logging.StreamHandler(sys.stdout)
    console_handler.setFormatter(log_format)
    logger.addHandler(console_handler)
    # Creating and adding the file handler
    file_handler = logging.FileHandler(logger_name, mode='a')
    file_handler.setFormatter(log_format)
    logger.addHandler(file_handler)
    return logger


if __name__ == "__main__":
    for item in range(10):
        logger = my_custom_logger(f"Logger{item}")
        logger.debug(item)

Ceci écrit dans un fichier journal différent pour chaque itération.


4 commentaires

J'ai marqué cela comme la réponse car elle donne la solution la plus propre des trois présentées à l'époque. Merci beaucoup pour votre aide à ce sujet. Cela fonctionne parfaitement.


Une fonction logger définie de cette manière sera-t-elle interceptée par logger = logging.getLogger () si je veux l'utiliser pour enregistrer différents modules? Que faire si je souhaite créer un fichier pour chaque élément ?


@muammar, pour réutiliser ceci, vous devez passer cet objet de journalisation à la classe souhaitée. Ici, nous créons un enregistreur pour item .


@Mithilesh_Kunal Je l'ai résolu comme décrit ci-dessous stackoverflow.com/a/56409646/1995261 . Merci pour votre réponse!



1
votes

Ce n'est pas nécessairement la meilleure réponse mais a fonctionné pour mon cas, et je voulais juste la mettre ici pour de futures références. J'ai créé une fonction qui ressemble à ceci:

if __name__ == "__main__":
    for i in range(1, 11, 1):
        directory = "_{}".format(i)

        if not os.path.exists(directory):
            os.makedirs(directory)
        filename = directory + "/training.log"
        logger(filename=filename)

Comme vous pouvez le voir (vous devrez peut-être faire défiler le code ci-dessus pour voir la ligne return logger ), je j'utilise logging.basicConfig () . Tous les modules que j'ai dans mon paquet qui enregistrent des trucs, ont ce qui suit au début des fichiers:

import logging
import other stuff

logger = logging.getLogger()


class SomeClass(object):
    def some_method(self):
        logger.info("Whatever")
        .... stuff

Lors d'une boucle, j'ai appelé les choses de cette façon: p>

def logger(filename, level=None, format=None):
    """A wrapper to the logging python module

    This module is useful for cases where we need to log in a for loop
    different files. It also will allow more flexibility later on how the
    logging format could evolve.

    Parameters
    ----------
    filename : str
        Name of logfile. 
    level : str, optional
        Level of logging messages, by default 'info'. Supported are: 'info'
        and 'debug'.
    format : str, optional
        Format of logging messages, by default '%(message)s'.

    Returns
    -------
    logger
        A logger object.
    """

    levels = {"info": logging.INFO, "debug": logging.DEBUG}

    if level is None:
        level = levels["info"]
    else:
        level = levels[level.lower()]

    if format is None:
        format = "%(message)s"

    # https://stackoverflow.com/a/12158233/1995261
    for handler in logging.root.handlers[:]:
        logging.root.removeHandler(handler)

    logger = logging.basicConfig(filename=filename, level=level, format=format)

    return logger

J'espère que cela vous sera utile.


0 commentaires