89 votes

Python utilisant la méthode basicConfig pour enregistrer dans la console et dans un fichier

Je ne sais pas pourquoi ce code s'imprime à l'écran, mais pas dans le fichier ? Le fichier "exemple1.log" est créé, mais rien n'y est écrit.

#!/usr/bin/env python3
import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(message)s',
                    handlers=[logging.FileHandler("example1.log"),
                              logging.StreamHandler()])
logging.debug('This message should go to the log file and to the console')
logging.info('So should this')
logging.warning('And this, too')

J'ai "contourné" ce problème en créant un objet de journalisation, mais je continue à me demander pourquoi basicConfig() a échoué ?

PS. Si je change l'appel de basicConfig en :

logging.basicConfig(level=logging.DEBUG,
                    filename="example2.log",
                    format='%(asctime)s %(message)s',
                    handlers=[logging.StreamHandler()])

alors tous les journaux sont dans le fichier et rien n'est affiché dans la console.

59voto

kartheek Points 1251

Essayez ceci qui fonctionne bien (testé en python 2.7) pour les deux. console et fichier

# set up logging to file
logging.basicConfig(
     filename='log_file_name.log',
     level=logging.INFO, 
     format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s',
     datefmt='%H:%M:%S'
 )

# set up logging to console
console = logging.StreamHandler()
console.setLevel(logging.DEBUG)
# set a format which is simpler for console use
formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
console.setFormatter(formatter)
# add the handler to the root logger
logging.getLogger('').addHandler(console)

logger = logging.getLogger(__name__)

29voto

J.F. Sebastian Points 102961

Je n'arrive pas à le reproduire sur Python 3.3. Les messages sont écrits à la fois sur l'écran et dans le fichier 'example2.log' . Sur Python <3.3 il crée le fichier mais il est vide.

Le code :

from logging_tree import printout  # pip install logging_tree
printout()

montre que FileHandler() n'est pas attaché au logger Root sur Python <3.3.

Les documents relatifs à logging.basicConfig() dire que handlers est ajouté dans Python 3.3. L'adresse handlers n'est pas mentionné dans la documentation de Python 3.2.

10voto

Wesam Na Points 881

Dans l'exemple ci-dessous, vous pouvez spécifier la destination du journal en fonction de son niveau. Par exemple, le code ci-dessous laisse tous les journaux de niveau supérieur au niveau INFO aller au fichier journal, et tout ce qui précède ERROR niveau va à la console.

import logging
logging.root.handlers = []
logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO , filename='ex.log')

# set up logging to console
console = logging.StreamHandler()
console.setLevel(logging.ERROR)
# set a format which is simpler for console use
formatter = logging.Formatter('%(asctime)s : %(levelname)s : %(message)s')
console.setFormatter(formatter)
logging.getLogger("").addHandler(console)

logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.exception('exp')

9voto

jxramos Points 79

Une autre technique utilisant le basicConfig est de configurer tous vos gestionnaires dans la déclaration et de les récupérer après coup, comme dans...

import logging

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s',
                    handlers=[logging.FileHandler("my_log.log", mode='w'),
                              logging.StreamHandler()])
stream_handler = [h for h in logging.root.handlers if isinstance(h , logging.StreamHandler)][0]
stream_handler.setLevel(logging.INFO)

Il est cependant plus judicieux de construire les instances de votre gestionnaire de flux en dehors et de les configurer comme des objets autonomes que vous passez à la liste des gestionnaires comme dans...

import logging

stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(levelname)s %(module)s %(funcName)s %(message)s',
                    handlers=[logging.FileHandler("my_log.log", mode='w'),
                              stream_handler])

1voto

mike rodent Points 482

WOOAH !

Je viens de passer 20 minutes à être déconcerté par ça.

J'ai fini par comprendre que le StreamHandler était en sortie vers stderr no stdout (dans un écran DOS 'Doze, ils ont la même couleur de police !).

Cela m'a permis d'exécuter le code sans problème et d'obtenir des résultats raisonnables, mais dans une fonction pytest, les choses se sont gâtées. Jusqu'à ce que je change de méthode :

out, _ = capsys.readouterr()
assert 'test message check on console' in out, f'out was |{out}|'

à ça :

_, err = capsys.readouterr()
assert 'test message check on console' in err, f'err was |{err}|'

NB le constructeur de StreamHandler est

class logging.StreamHandler(stream=None)

et, comme les docs dire, "Si stream est spécifié, l'instance l'utilisera pour la sortie de journalisation ; sinon, sys.stderr sera utilisé".

NB : il semble que l'alimentation de la level le mot-clé ne fonctionne pas setLevel sur les gestionnaires : il faudrait itérer sur les gestionnaires résultants et exécuter setLevel sur chacun d'eux, si c'est important pour vous.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X