Logging¶
Le module logging
fait parti de la bibliothèque standard de Python depuis la version 2.3. Il est succinctement décrit dans la PEP 282. La documentation est notoirement difficile à lire, à l’exception du basic logging tutorial.
Le logging sert deux buts:
Le logging de diagnostic enregistre les événements liés au fonctionnement de l’application. Si un utilisateur appelle pour signaler une erreur, par exemple, les logs peuvent être recherchés pour avoir un contexte.
logging d’audit enregistre les événements pour l’analyse des affaires. Les transactions d’un utilisateur peuvent être extraites et combinées avec d’autres détails de l’utilisateur pour les rapports ou pour optimiser un objectif d’affaires.
... ou Print?¶
La seule fois que print
est une meilleure option que le logging est lorsque l’objectif est d’afficher une déclaration d’aide pour une application en ligne de commande. D’autres raisons pour lesquelles le logging est mieux que print
:
Le log record, qui a été créé avec chaque événement de logging, contient des informations de diagnostic facilement disponibles tels que le nom du fichier, le chemin complet, la fonction et le numéro de ligne de l’événement de logging.
Les événements loggués dans les modules inclus sont automatiquement accessibles via la racine du logger au flux de logs de votre application, à moins que vous ne les filtriez.
Le logging peut être réduite au silence de manière sélective en utilisant la méthode
logging.Logger.setLevel()
ou désactivée en définissant l’attributlogging.Logger.disabled
àTrue
.
Logging dans une bibliothèque¶
Les notes pour configuring logging for a library sont dans le logging tutorial. Parce que l’utilisateur, pas la bibliothèque, devrait dicter ce qui se passe quand un événement de logging a lieu, une admonition à accepter est de se répéter:
Note
Il est fortement recommandé de ne pas ajouter de handlers autres que NullHandler aux loggers de votre bibliothèque.
Les meilleures pratiques lors de l’instanciation des loggers dans une bibliothèque est de seulement les créer en utilisant la variable globale __name__
: le module logging
crée une hiérarchie de loggers en utilisant la notation point, donc utiliser __name__
assure l’absence de collisions de noms.
Voici un exemple de bonne pratique depuis la requests source – placez ceci dans votre __init__.py
# Set default logging handler to avoid "No handler found" warnings.
import logging
try: # Python 2.7+
from logging import NullHandler
except ImportError:
class NullHandler(logging.Handler):
def emit(self, record):
pass
logging.getLogger(__name__).addHandler(NullHandler())
Logging dans une application¶
Le site twelve factor app, une référence faisant autorité pour les bonnes pratiques dans le développement d’application, contient une section sur les meilleures pratiques de logging. Elle prône avec insistance pour le traitement des événements de journal comme un flux d’événements, et pour envoyer ce flux d’événements à la sortie standard pour être traité par l’environnement d’application.
Il y a au moins 3 manières de configurer un logger:
- En utilisant un fichier formaté sous forme INI
Avantages: possible de mettre à jour la configuration lors de l’exécution en utilisant la fonction
logging.config.listen()
pour écouter sur un socket.Inconvénients: moins de contrôle (par exemple pour des loggers ou filtres comme sous-classes) que possible lors de la configuration d’un logger dans le code.
- En utilisant un dictionnaire ou un fichier formaté sous forme JSON:
Avantages: en plus de la mise à jour tout en exécutant, il est possible de charger à partir d’un fichier en utilisant le module
json
, dans la bibliothèque standard depuis Python 2.6.Inconvénients: moins de contrôle que quand configuration d’un logger dans le code.
- En utilisant du code:
Avantages: contrôle complet sur la configuration.
Inconvénients: modifications nécessitent un changement du code source.
Exemple de configuration via un fichier INI¶
Disons que le fichier est nommé logging_config.ini
. Plus de détails pour le format de fichier se trouvent dans la section logging configuration du logging tutorial.
[loggers]
keys=root
[handlers]
keys=stream_handler
[formatters]
keys=formatter
[logger_root]
level=DEBUG
handlers=stream_handler
[handler_stream_handler]
class=StreamHandler
level=DEBUG
formatter=formatter
args=(sys.stderr,)
[formatter_formatter]
format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s
Ensuite, utilisez logging.config.fileConfig()
dans le code:
import logging
from logging.config import fileConfig
fileConfig('logging_config.ini')
logger = logging.getLogger()
logger.debug('often makes a very good meal of %s', 'visiting tourists')
Exemple de configuration via un dictionnaire¶
A partir de Python 2.7, vous pouvez utiliser un dictionnaire avec les détails de configuration. La PEP 391 contient une liste des éléments obligatoires et optionnels dans le dictionnaire de configuration.
import logging
from logging.config import dictConfig
logging_config = dict(
version = 1,
formatters = {
'f': {'format':
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s'}
},
handlers = {
'h': {'class': 'logging.StreamHandler',
'formatter': 'f',
'level': logging.DEBUG}
},
root = {
'handlers': ['h'],
'level': logging.DEBUG,
},
)
dictConfig(logging_config)
logger = logging.getLogger()
logger.debug('often makes a very good meal of %s', 'visiting tourists')
Exemple de configuration directement dans le code¶
import logging
logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = logging.Formatter(
'%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.debug('often makes a very good meal of %s', 'visiting tourists')