web-dev-qa-db-fra.com

Faire en sorte que les enregistreurs Python transmettent tous les messages à stdout en plus du fichier journal

Existe-t-il un moyen de consigner Python à l'aide du module logging et envoie automatiquement les éléments à stdout en plus dans le fichier journal où ils sont censés aller? Par exemple, je voudrais que tous les appels à logger.warning, logger.critical, logger.error se dirigent vers leurs emplacements souhaités mais sont en outre toujours copiés vers stdout. Ceci afin d'éviter la duplication de messages tels que:

mylogger.critical("something failed")
print "something failed"
384
user248237

Toutes les sorties de journalisation sont gérées par les gestionnaires. ajoutez simplement un logging.StreamHandler() au logger racine.

Voici un exemple de configuration d'un gestionnaire de flux (en utilisant stdout au lieu du paramètre par défaut stderr) et en l'ajoutant au consignateur racine:

import logging
import sys

root = logging.getLogger()
root.setLevel(logging.DEBUG)

handler = logging.StreamHandler(sys.stdout)
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
root.addHandler(handler)
541
Martijn Pieters

Le moyen le plus simple de se connecter à stdout:

import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
427
Eyal

C'est possible en utilisant plusieurs gestionnaires.

import logging
import auxiliary_module

# create logger with 'spam_application'
log = logging.getLogger('spam_application')
log.setLevel(logging.DEBUG)

# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

# create file handler which logs even debug messages
fh = logging.FileHandler('spam.log')
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
log.addHandler(fh)

# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.ERROR)
ch.setFormatter(formatter)
log.addHandler(ch)

log.info('creating an instance of auxiliary_module.Auxiliary')
a = auxiliary_module.Auxiliary()
log.info('created an instance of auxiliary_module.Auxiliary')

log.info('calling auxiliary_module.Auxiliary.do_something')
a.do_something()
log.info('finished auxiliary_module.Auxiliary.do_something')

log.info('calling auxiliary_module.some_function()')
auxiliary_module.some_function()
log.info('done with auxiliary_module.some_function()')

# remember to close the handlers
for handler in log.handlers:
    handler.close()
    log.removeFilter(handler)

Veuillez consulter: https://docs.python.org/2/howto/logging-cookbook.html

53
Alok Singh Mahor

Vous pouvez créer deux gestionnaires pour fichier et stdout, puis créer un journal avec l'argument handlers to basicConfig . Cela pourrait être utile si vous avez le même log_level et le même format de sortie pour les deux gestionnaires:

import logging
import sys

file_handler = logging.FileHandler(filename='tmp.log')
stdout_handler = logging.StreamHandler(sys.stdout)
handlers = [file_handler, stdout_handler]

logging.basicConfig(
    level=logging.DEBUG, 
    format='[%(asctime)s] {%(filename)s:%(lineno)d} %(levelname)s - %(message)s',
    handlers=handlers
)

logger = logging.getLogger('LOGGER_NAME')
47
Anton Protopopov

Le moyen le plus simple de se connecter au fichier et à stderr:

import logging

logging.basicConfig(filename="logfile.txt")
stderrLogger=logging.StreamHandler()
stderrLogger.setFormatter(logging.Formatter(logging.BASIC_FORMAT))
logging.getLogger().addHandler(stderrLogger)
30
Weidenrinde

Comme personne n’a partagé une doublure soignée, je partagerai la mienne:

logging.basicConfig(filename='logs.log', level=logging.DEBUG, format="%(asctime)s:%(levelname)s: %(message)s")
logging.getLogger().addHandler(logging.StreamHandler())
5
Lexander

Voici une solution basée sur la puissante mais mal documentée méthode logging.config.dictConfig] . Au lieu d'envoyer chaque message de journal à stdout, il envoie des messages avec le niveau de journalisation ERROR et les versions supérieures à stderr et tout le reste à stdout. Cela peut être utile si d'autres parties du système écoutent stderr ou stdout.

import logging
import logging.config
import sys

class _ExcludeErrorsFilter(logging.Filter):
    def filter(self, record):
        """Filters out log messages with log level ERROR (numeric value: 40) or higher."""
        return record.levelno < 40


config = {
    'version': 1,
    'filters': {
        'exclude_errors': {
            '()': _ExcludeErrorsFilter
        }
    },
    'formatters': {
        # Modify log message format here or replace with your custom formatter class
        'my_formatter': {
            'format': '(%(process)d) %(asctime)s %(name)s (line %(lineno)s) | %(levelname)s %(message)s'
        }
    },
    'handlers': {
        'console_stderr': {
            # Directs log messages with log level ERROR or higher to stderr
            'class': 'logging.StreamHandler',
            'level': 'ERROR',
            'formatter': 'my_formatter',
            'stream': sys.stderr
        },
        'console_stdout': {
            # Directs log messages with log level lower than ERROR to stdout
            'class': 'logging.StreamHandler',
            'level': 'DEBUG',
            'formatter': 'my_formatter',
            'filters': ['exclude_errors'],
            'stream': sys.stdout
        },
        'file': {
            # Directs all log messages to a file
            'class': 'logging.FileHandler',
            'level': 'DEBUG',
            'formatter': 'my_formatter',
            'filename': 'my.log',
            'encoding': 'utf8'
        }
    },
    'root': {
        # In general, this should be kept at 'NOTSET' to ensure it does
        # not interfere with the log levels set for each handler
        'level': 'NOTSET',
        'handlers': ['console_stderr', 'console_stdout', 'file']
    },
}

logging.config.dictConfig(config)
4
Elias Strehle

Voici un exemple extrêmement simple:

import logging
l = logging.getLogger("test")

# Add a file logger
f = logging.FileHandler("test.log")
l.addHandler(f)

# Add a stream logger
s = logging.StreamHandler()
l.addHandler(s)

# Send a test message to both -- critical will always log
l.critical("test msg")

La sortie affichera "message texte" sur stdout et également dans le fichier.

1
Kiki Jewell

Jetez un coup d'œil au module logur .

from loguru import logger

logger.debug("That's it, beautiful and simple logging!")
1
efirvida