[PYTHON] Veuillez arrêter l'impression et importer la journalisation pour la sortie du journal

introduction

http://docs.python.jp/3/howto/logging.html

Les articles d'introduction à Python vous montrent généralement comment appeler les fonctions fournies avec le module logging, telles que logging.debug (), dans l'introduction aux fonctionnalités de journalisation de Python.

Le "tutoriel de base" de logging fourni par la famille de têtes Python ne fait pas beaucoup de différence à cet égard. Dans le didacticiel de base de la famille Python, la méthode d'utilisation de print est également efficace en tant qu'option de journalisation, et il est dit que print et` `` logging.debug () '' doivent être utilisés correctement en fonction de la tâche. Il est décrit dans le flux.

Afficher la sortie de la console couramment utilisée dans les scripts et programmes de ligne de commande: print ()

Ce n'est qu'après une telle explication "basique" que le didacticiel "avancé" peut commencer à expliquer le mécanisme de journalisation fourni avec le langage Python. Dans "Advanced", 4 + 1 types de structures de données sont introduits, et ici vous pouvez trouver l'identité de logging.debug () `` `, qui était souvent utilisé dans" Basic ".

La journalisation se fait en appelant une méthode sur une instance de la classe Logger (ci-après Logger). Chaque instance a un nom et est organisée de manière conceptuelle dans une hiérarchie d'espace de noms, avec des points (points) comme séparateurs. Par exemple, un enregistreur nommé «scan» est le parent des enregistreurs «scan.text», «scan.html» et «scan.pdf». Le nom de l'enregistreur peut être tout ce que vous voulez et indique l'emplacement du message enregistré. .. La racine de la hiérarchie des enregistreurs est appelée l'enregistreur racine. C'est le logger utilisé par les fonctions debug (), info (), warning (), error () et critical (). Ces fonctions appellent simplement la méthode de l'enregistreur racine du même nom. Ces fonctions et méthodes ont la même signature. Le nom de l'enregistreur racine est affiché en tant que «root» dans la sortie du journal.

Il existe en fait des applications Python pratiques qui utilisent print pour la sortie du journal. Probablement "tout à fait".

L'auteur précédent a également utilisé «print» pour afficher le journal. Mais maintenant, j'évite presque de me connecter avec print, sauf dans des cas comme de minuscules scripts pour confirmation avec moins de 10 lignes.

Personnellement, je ne pense pas que ** print ou`` `logging``` devrait être enseigné ou recommandé aux débutants en Python du tout **. Au moins, je ne pense pas que ce soit le bon ordre pour enseigner le "Tutoriel de base" officiel de Python.

Cet article tente d'expliquer pourquoi vous en êtes venu à penser de cette façon.

Précautions lors de la lecture de ce qui suit

L'auteur de cet article n'est pas aussi compétent qu'un committer Python (c'était au moment de la sortie de la première édition et au moment de la révision). S'il vous plaît laissez-nous savoir s'il y a des erreurs dans le contenu.

Aussi, le fait que "je n'ai pas lu correctement le tutoriel pendant un certain temps après avoir connu le module" journalisation "", qui devrait être considéré comme un problème individuel de l'auteur, a également déclenché cette phrase. .. Veuillez me pardonner le fait qu'une partie du contenu ne ressemble pas à "hurlement des débutants", mais c'est un problème côté document.

Si vous souhaitez simplement connaître les meilleures pratiques, lisez les Meilleures pratiques de journalisation Python.

Pourquoi pas: imprimer

Je parlerai de l'implémentation d'une application Python spécifique du point de vue des autres.

Un des problèmes avec la sortie du journal avec print est" Je ne sais pas si la chaîne de caractères affichée est la sortie du journal ou les informations que l'outil de ligne de commande veut vraiment présenter à l'utilisateur ". Peut être fait.

Il n'y a aucun problème à utiliser «print» de Python lui-même «sauf si c'est à des fins de journalisation». Par exemple, supposons que vous implémentiez vous-même la commande Linux tee. Ce ne serait pas nécessairement une erreur d'écrire la sortie standard avec print tout en écrivant les données reçues avec l'entrée standard dans un fichier. Ceci est un exemple de "la sortie que vous voulez vraiment".

La "sortie vraiment désirée" ici est le "quelque chose" du côté de la sortie quand le programme était un outil qui "reçoit des entrées et produit quelque chose".

D'autre part, un journal est un "enregistrement" dans lequel un programme généré dans le processus fonctionne.

Dans cet article, j'aimerais dire "pour la sortie du journal", c'est-à-dire si vous voulez enregistrer "Je suis fou. Je suis fou ici, je vais vous dire ~", arrêtez l'approche basée sur print. C'est.

Si c'est un script de 10 à 20 lignes, c'est encore mieux, et comme je l'ai écrit au début, j'utilise aussi print si c'est le cas.

Par exemple, si vous écrivez un exemple de code qui connaît le comportement lorsqu'il est divisé par 0,

print('started')
a = 1/0
print('ended')

Il n'y aura aucun problème avec l'écriture comme. Cette "impression" est en fait un journal, plutôt qu'une sortie souhaitée, un "enregistrement" du fonctionnement du programme. Mais il est évident qu'il est insensé d'utiliser le module logging avec du code de cette taille.

D'un autre côté, des outils de bibliothèque relativement compliqués, tels que des fichiers à deux chiffres, peuvent avoir complété leur propre système de journalisation basé sur «impression».

Parlons d'une bibliothèque Python que j'ai rencontrée (au moins c'était une bibliothèque relativement connue quand je l'ai trouvée). Dans cette bibliothèque, j'ai implémenté par moi-même sur la base de «print» qu'il peut être facilement réalisé en combinant «Logger» et «Handler» du module «logging». Il n'y avait pas de mécanisme équivalent au niveau de journalisation. Il y avait un mécanisme comme une balise pour séparer les types de journaux, mais la balise n'est utilisée que pour les branchements, que ce soit pour la sortie ou non, et lorsqu'elle est affichée dans print, elle fera partie de la chaîne de caractères. Ce sera mélangé.

Il existe de nombreux problèmes avec un tel mécanisme de journalisation spécifique à la bibliothèque. Tout d'abord, il n'est pas possible de déterminer si le contenu du journal de sortie est un "journal sévère" ou "une sortie de journal de débogage". .. Il sera nécessaire de re-trier les chaînes de caractères brutes avec des expressions régulières, etc., en fonction de la catégorie à laquelle l'erreur appartient. Cela ne vous donne aucun contrôle décent sur le journal.

De plus, pour les utilisateurs familiers avec Python, ils sont obligés d'utiliser un mécanisme de journalisation différent de celui de Python, et il est nécessaire de prendre des mesures supplémentaires pour comprendre l'intention et les limites de ce mécanisme. Si vous vous sentez à court de modules Python, c'est le pire si vous pouvez simplement créer une version dégradée.

Non limité à Python, vous devriez penser que ** séparer simplement stdout et stderr ne donne pas de score de passage en tant que mécanisme de journalisation moderne **.

La réécriture d'une application construite à l'origine sur print pour utiliser les fonctions de logger est assez gênante, voire très gênante. Il peut être possible du côté récepteur de "récupérer" le contenu de stderr et de le renvoyer à logger, mais c'est gênant. De toute façon, c'est honnêtement stérile.

Du point de vue de l'utilisateur, l'approche basée sur print ressemble à" J'ai tout vidé dans les égouts, alors récupérez-le si nécessaire. "

S'il y avait un outil publié sur GitHub et que le monde de débogage print était déplié lorsque quelqu'un était intéressé, l'utilisateur se gratterait la tête sans même toucher à l'essence de l'outil. Devenir. Je suis devenu.

En premier lieu, le mécanisme de journalisation d'origine de la bibliothèque Python était si mauvais et choqué que j'ai écrit cet article.

Pourquoi pas: logging

Les enregistreurs Python ont une structure hiérarchique et arborescente. Dans la métaphore d'un arbre, plusieurs journaux (une instance de la classe LogRecord) qui arrivent du Happa sont reçus au point où ils atteignent une branche ( Logger), et atteignent le root logger ("root logger"). L'enregistreur peut traiter un journal à plusieurs reprises. Vous pouvez également empêcher le journal de se propager d'une branche à la branche suivante (plus proche de la racine) (attribut propagate). Pour plus de détails, il est bon de lire Tutoriel avancé.

ici,

logging.debug()

L'écriture signifie que même dans l'arborescence des journaux de Python, les informations sont directement insérées dans le "root logger" racine.

L'enregistreur racine est également la racine du mécanisme de journalisation pour tous les modules appelés depuis le runtime Python lancé, et est la "variable globale" elle-même.

Si chaque bibliothèque appelle ces fonctions (ainsi que logging.info () etc.) qui viennent avec le module logging directement, elle pollue implicitement le monde (espace de noms) des autres modules. Devenir.

Plus précisément, si vous définissez le niveau de journalisation de l'enregistreur racine sur DEBUG pour voir le journal de la bibliothèque A, le journal DEBUG vers l'enregistreur racine que d'autres bibliothèques (bibliothèque B, bibliothèque C ...) ont entré sera également affiché de manière inséparable. .. C'est similaire au journal indescriptible qui a été versé dans stderr avec print en ce sens qu'il était inséparable.

En fait, des sources comme les didacticiels avancés et les livres de recettes Python (pour les utilisateurs avancés et supérieurs ??) indiquent que vous devriez envisager d'utiliser un enregistreur au lieu de journaliser "lors de la construction d'une bibliothèque".

http://docs.python.jp/3/howto/logging.html#configuring-logging-for-a-library

Bien entendu, le didacticiel de base décrit également ce domaine.

Ce modèle dans mylib.py peut être généralisé à plusieurs modules. Notez que dans ce modèle d'utilisation simple, vous pouvez voir la description de l'événement en regardant le fichier journal, mais pas d'où provient le message dans l'application. Si vous souhaitez suivre l'emplacement de vos messages, vous aurez besoin d'une documentation au-delà de ce niveau de didacticiel - voir Didacticiels de journalisation avancés.

Ce n'est pas si court depuis que j'ai commencé à utiliser Python, mais cela ne fait que quelques années que je l'ai vu pour la première fois. De plus, c'est à peu près au même moment que j'ai pu comprendre le vrai sens. Après avoir vu plusieurs articles errants, j'étais convaincu que "Oui ... c'est vrai, la fonction directement sous" journalisation "n'est pas bonne", et quand j'ai relu le tutoriel, il était en fait écrit.

Exemple d'article erroné: [Python Logging Best Practice](shttp: //pieces.openpolitics.com/2012/04/python-logging-best-practices/)

Personnellement, je l'ai trouvé très ennuyeux ** Après une brève explication dans le tutoriel disant que "vous pouvez vous déconnecter avec logging.debug () ʻet imprimer`", il existe une meilleure pratique. Cela signifie qu'il est écrit **.

Avec le recul, je pense que la méthode introduite plus tôt a très peu de goût en premier lieu. Et j'ai décidé de tout réécrire de toutes mes forces.

ʻImport logging` même ennuyeux

Je suis gêné car je fais souvent des erreurs ...

Après avoir compris certains des sujets ci-dessus, et une fois que je suis arrivé à l'idée commune que logging.debug () ne devrait pas être utilisé, j'ai écrit logger = logging.getLogger (__name__) au début de chaque module. J'ai écrit comme , et tout le code après cela a commencé à utiliser logger.

Mais au milieu de l'écriture

logger.debug()

Quand

logging.debug()

J'écris en mixant. Il vole vers un endroit différent!

Vous pourriez penser que ce n'est pas un gros problème, mais si vous regardez les journaux et traquez la cause d'un bogue, vous pouvez simplement manquer la différence triviale entre ** logger et logging et où la fonction ira. Je ne sais pas ce que c'est **. Plus vous créez une arborescence de journaux hautement structurée, plus logging.debug () pointe vers, en supposant que vous pointez vers une instance de Logger qui a un niveau de journal ou une spécification de fichier journal que vous voulez logger. Les enregistreurs de racines ont tendance à être des figurines en bois qui ne produisent rien. logger.debug () affichera une chaîne significative dans un fichier et logging.debug () laissera secrètement un message dans "Danmari" ou ailleurs, en suivant le fichier journal. Sera difficile ou impossible.

À moins que vous ne débogiez interactivement avec des points d'arrêt, vous ne remarquerez peut-être pas la différence triviale entre les chaînes «logger» et «logging» jusqu'à la fin. ** Les humains ne sont pas doués pour distinguer des chaînes similaires **. Malheureusement, il n'y a pas non plus d'erreur grammaticale au moment de la journalisation des importations. Vous attendez-vous à ce que la couleur de surbrillance de l'éditeur soit différente? ??

Il existe une solution de contournement simple.

#Endommagé
import logging
logger = logging.getLogger(__name__)

Signifie "ne pas écrire".

from logging import getLogger
logger = getLogger(__name__)

Est d'écrire.

J'ai été choqué quand j'ai proposé cette solution de contournement simple. C'est embarrassant de ne pas l'avoir remarqué.

Je me suis toujours demandé pourquoi je ne pouvais pas y penser

import logging
logging.debug()

Cela a dû être parce que j'étais guidé. Je blâme les autres.

La première fois que j'ai pensé que ce problème de remplacement était «mauvais», c'était lorsque j'ai implémenté par erreur les «logging» et «logger» ci-dessus dans le processus de création d'un service qui fonctionne depuis longtemps avec Django (framework Web). fait.

Lorsque je recherchais l'implémentation de la fonction, il y a eu un moment où aucun journal n'était sorti pour une raison quelconque, et j'ai levé les yeux avec un visage disant «Pourquoi n'est-il pas sorti? C'était vraiment une faute de frappe gratuite. Je peux pleurer. Encore une fois, ** les humains ne sont pas doués pour distinguer des chaînes similaires **.

Ici, j'ose considérer la journalisation des importations comme un problème. Pour les fonctions directement sous ce module

Les deux fonctions sont mixtes. C'est très mélangé.

Le premier devrait avoir un impact très limité et limité sur l'ensemble du programme. Ce dernier ne doit pas être utilisé sauf si vous êtes sûr.

Dans les deux cas, il est trop subtil pour permettre le début complet de la journalisation des importations au début, mais le didacticiel explique cela en premier. C'est comme si ** recommandait aux débutants de faire des erreurs **.

Pour éviter les erreurs humaines, vous pouvez arrêter d'utiliser le nom d'objet logger et utiliser log.debug (). Cependant, je n'aime pas ça car il est difficile de dire s'il s'agit d'un enregistrement ou d'un enregistreur.

À propos, la fonction principale reçoit «logger». Vous pouvez utiliser votre propre enregistreur par défaut

Si la fonction se prépare à accepter logger, par exemple via un argument optionnel, cela vous donne plus de flexibilité lorsque vous essayez de l'utiliser comme bibliothèque. Il s'agit d'une soi-disant injection de dépendance.

def do_some_great_stuff(arg_a, arg_b, logger=None):
    logger = logger or _your_default_logger
    #Chose incroyable

Pour Python3, vous pouvez le forcer à être un argument facultatif. Plutôt!

def do_some_great_stuff(arg_a, arg_b, *, logger=None):
    logger = logger or _your_default_logger
    #Chose incroyable

En Python3, après le simple *, il devient un "argument de mot-clé uniquement". Le système Python2 n'a pas cette syntaxe, il est donc traité dynamiquement avec ** kwargs. Pour plus de détails, reportez-vous à «Point 21: Augmenter la clarté avec des arguments de mots clés uniquement» et au Glossaire dans «Python efficace».

Si vous gérez vous-même l'objet Logger et ne l'exposez pas à l'extérieur, vous ne pourrez pas gérer les journaux de manière unifiée en remplaçant les loggers de ce module selon les besoins par d'autres.

Supposons que le développeur A utilise l'API de la bibliothèque externe B tout en exécutant une série de processus en utilisant le Logger créé par getLogger ('service_a.do_something'). Si cette bibliothèque obtient le Logger via getLogger ('service_b.do_bad_thing') et que vous ne pouvez pas le remplacer, alors le Handler et le Format sont probablement gérés séparément. Ceci est très gênant pour suivre le processus d'exécution d'une fonction. Du point de vue du développeur A, cela a tendance à être "Permettez-moi d'utiliser mon enregistreur ici".

Il y a des cas où il est très pratique pour un étranger d'associer chaque fonction de la bibliothèque à un autre enregistreur dans un autre but.

À moins que vous ne vous souciez vraiment d'autres circonstances (performances, etc.), j'aimerais que vous ayez une structure qui puisse séparer le traitement pour chaque enregistreur, et même si vous le gérez vous-même, utilisez bien l'arborescence de l'enregistreur pour nommer la série. Je veux que tu divises par.

Addendum (2017-07-07): S'il est supposé que la fonction etc. sera utilisée par un étranger en tant que bibliothèque, un gestionnaire autre que NullHandler ne doit pas être ajouté à _your_default_logger ici. Conseillé. Au fait, un Logger qui n'inclut aucun Handler donne essentiellement un avertissement.

https://docs.python.jp/3/howto/logging.html#configuring-logging-for-a-library

De plus, je veux que vous fassiez ce niveau de support lorsque vous le publiez sur GitHub.

Pour l'auteur, je veux que vous soyez en état d'utiliser logger si vous le remarquez même au stade de la publication facile de" Je l'ai écrit avec mon propre script, je l'ai écrit pour le moment! "

Les personnes qui liront «rapidement» le didacticiel actuel choisiront «imprimer» ou «journalisation», mais vous devriez pouvoir utiliser «Logger» avec juste un léger changement dans l'ordre des explications. Au «niveau que j'ai essayé d'utiliser», je pense que les coûts de «print» et «logger» ne changent pas beaucoup.

Voici un exemple.

from logging import getLogger, StreamHandler, DEBUG
logger = getLogger(__name__)
handler = StreamHandler()
handler.setLevel(DEBUG)
logger.setLevel(DEBUG)
logger.addHandler(handler)
logger.propagate = False

logger.debug('hello')

Cela se termine simplement. Je pense qu'il y a beaucoup de lignes "magiques", mais je sens que je peux le faire parce que je peux copier et coller.

Personnellement, je pense qu'il vaut mieux soulever la critique que setLevel () apparaît deux fois ici. Oh, ce blâme est ce que j'ai crié il y a quelques jours. Omis si c'est trop la gorge.

Dans ce cas, si vous ne voulez pas cracher le journal, utilisez simplement NullHandler au lieu de StreamHandler, Si vous souhaitez effectuer une rotation du journal en fonction de la taille, il existe RotatingFileHandler. Si vous voulez envoyer plus que le message d'erreur, il y a SmtpHandler!

L'affirmation ici est: "Je veux que vous m'enseigniez un tel niveau de formulation magique au début." Inversement, vous ne devriez même pas écrire que print ou logging.debug () convient dans les didacticiels de journalisation.

Remarque: L'affirmation ici n'est pas "demandons un poids lourd aux débutants". L'histoire est la suivante: "N'incluez pas dans le didacticiel des mots qui facilitent l'entrée dans une impasse. Quoi qu'il en soit, j'utilise print dans les situations où je l'utilise. Parce que c'est simple. Vous n'avez tout simplement pas besoin d'augmenter son utilisation. À la fin, vous constaterez qu'une telle méthode est pratique dans certains cas.

Note 2 (post-scriptum 2016-11-17): Si le DI ci-dessus est fait, le journal DEBUG (peut vider le mot de passe, etc.) peut être affiché arbitrairement par un étranger, donc je suis un peu inquiet pour la sécurité. Je me demande s'il y a une direction. Cependant, je me demande ce que je dis dans une langue où l'instance n'a pratiquement pas de variables privées.

Note 3 (2017-07-07 postscript): Il y a aussi l'idée d'utiliser basicConfig () '' d'abord lors de l'écriture du paramètre de la partie de démarrage sous forme de script, et en fait il peut être écrit de manière plus concise (voir commentaire) ). Cependant, je pense personnellement que les enregistreurs de racines ne devraient pas être utilisés à ce stade dans les premières étapes, j'ai donc décidé de ne pas les utiliser. En examinant cette fois, j'ai trouvé que je ne pouvais pas voir le goût à moins de faire logger.propagate = False``, alors je l'ai ajouté.

"Problème d'ordre pédagogique"

Il continue de parler de "N'enseignez rien de merde comme" print "ou" logging.debug () "en premier."

Chaque fois que je veux déboguer quelque chose, je viens de lire la documentation avec le plus grand effort pour éliminer le bogue.

À ce moment-là, ** le développeur ne veut pas apprendre tout le système **.

Vous devez croire qu'au début du document se trouve la méthode que tout le monde considère comme la plus concise et peut-être décente. Au moins, je ne m'attends pas à ce qu'il dise quelque chose comme "Désolé, ce n'est pas la bonne façon de le faire!"

D'autre part, la documentation actuelle de journalisation Python donne l'impression que les choses importantes sont écrites à la fin, dans l'espoir qu'ils apprendront le système jusqu'à la fin. Ou même s'il existe plusieurs méthodes (même si cela semble NG pour Python à ce moment-là), la structure est telle que le lecteur sera convaincu et partira lorsque la première sera appelée (la base est "avancée"). Il est écrit).

Bien que le contenu écrit plus tard soit plus approprié, la méthode qui n'est pas recommandée précédemment est décrite, et seule la méthode qui n'est pas recommandée lorsqu'un débutant laisse le document au milieu est mémorisée par cette personne ...

Quelque temps après avoir lu la documentation de cette façon pour la première fois, l'utilisateur oublie ce qu'il a fait et pourquoi il a utilisé cette méthode de journalisation, et a également appelé les 10 premières lignes du tutoriel à `logging.debug ( ) ʻUtiliser ...

Ou, dans le pire des cas, je comprends mal que print est correct, et que mon propre mécanisme de journalisation est intégré ...

En matière de journalisation, je crois fermement que cette méthode, qui semble avoir une solution au début du document, est très mauvaise à cet égard. La méthode d'enseignement est «okashii» en premier lieu.

De cette façon, l'utilisateur désaligne le mécanisme de journalisation et publie l'outil, et lorsque l'outil est affiné dans une certaine mesure, beaucoup d'autres le verront, mais ... C'est peut-être trop tard. Je ne pense pas que ce soit juste que le développeur fasse quelque chose de mal.

Plus gênant encore, le problème que le développeur ou l'utilisateur de l'outil souhaite vraiment résoudre n'est généralement pas directement lié au mécanisme de journalisation. Cela résout le problème, mais comme il contient un mécanisme de journalisation terriblement déformé, il dit: "J'ai ce que je veux, mais ... quelque chose ... c'est difficile à utiliser!?" Si vous ne choisissez pas la bonne réponse dès le début, ces problèmes ne sont pas motivants à résoudre.

Bien entendu, il est possible d'apporter des corrections à la source publiée. Les journaux appellent généralement simplement une fonction qui crée et affiche une chaîne quelque part dans le code, donc un étranger dit: «Ce mécanisme de journalisation basé sur l'impression se trouve dans le module Python standard. Vous pouvez faire un PR (Pull Request) en disant: "Vous pouvez tout remplacer par Logger`."

Cependant, il serait stérile de faire connaître la correction de la logique de sortie du journal à ce stade ... Non, ce serait bien si vous vouliez juste prendre la tête du diable.

** Je pense que le monde est beaucoup plus propre si vous dites "Vous n'avez pas besoin de connaître les détails de la journalisation Python, donclogger = getLogger (__ name__) ʻutilise-le!". Il est toujours facile d'en faire un argument d'une fonction, et le tirer dans un** kwargs` ou un argument optionnel ne serait pas un gros problème.

Est devenu plus long

Si vous êtes nouveau dans la journalisation Python pour le moment, les paramètres initiaux du journal lors de l'écriture d'un script d'exécution unique

from logging import getLogger, StreamHandler, DEBUG
logger = getLogger(__name__)
handler = StreamHandler()
handler.setLevel(DEBUG)
logger.setLevel(DEBUG)
logger.addHandler(handler)
logger.propagate = False

logger.debug('hello')

C'est tout pour écrire.

Addendum (2017-07-07): Une alternative est affichée au bas de cette entrée à partir du fond du commentaire. Aussi, dans le cas d'une bibliothèque, il est signalé qu'il est dangereux d'écrire ce code pour le moment, j'ai donc ajouté la phrase "Pour la configuration initiale du logger lors de l'écriture d'un seul script d'exécution". Veuillez consulter le post-scriptum ci-dessous pour plus de détails.

Au fait, pourquoi était-ce une si longue phrase juste pour transmettre ça ...

Depuis les temps anciens, les didacticiels de journalisation Python ont été structurés maintenant, je ne suis donc pas intéressé par l'histoire de ce qui se passe lorsque j'écris ceci maintenant. Il n'y a pas de réelle motivation pour frapper le chef de famille. Cependant, je pense qu'il y a des problèmes importants à garder à l'esprit.

Si vous êtes intéressé par Python mais que vous ne comprenez pas bien le journal, veuillez ne laisser que getLogger (__name __) dans le coin de votre tête. S'il reste coincé dans le coin de votre tête, au moins, vous serez moins susceptible d'arrêter de lire le didacticiel au milieu.

Relation

Mise à jour (2016-11-17)

J'ai relu le contenu et essayé de compléter certaines parties et de corriger la partie où le japonais était chaotique. Je connais Python3 et j'ajoute du code concret.

Cependant, j’ai également estimé que «l’élan» dont jouissait l’auteur à cette époque était important, de sorte que les phrases redondantes elles-mêmes n’étaient pas modifiées.

J'écrirai une phrase distincte qui extrait uniquement les méthodes qui, à mon avis, sont les meilleures pratiques.

Mise à jour (2017-07-05)

Les plaques de chaudière suivantes sont disponibles pour votre référence.

https://www.python-boilerplate.com/py3+executable+logging

J'ai remarqué cela, mais dans l'exemple ci-dessus, l'enregistreur racine est sale.

Mise à jour (2017-07-06, 2017-07-07)

Il a été souligné que je n'étais pas satisfait de l'extrait dans la section de conclusion de cette entrée, alors je l'ai ajouté.

Tout d'abord, j'ai ajouté `` logger.propegate = False '' au code dans le texte en raison des circonstances décrites dans le 05/07/2017.

En outre, il est d'abord nécessaire de présenter la prémisse que «lors du démarrage de l'écriture d'un seul script», et les alternatives sont les suivantes.

from logging import basicConfig, getLogger, DEBUG

#Écrivez ceci uniquement dans le fichier principal
basicConfig(level=DEBUG)

#Écrivez ceci dans tous les fichiers
logger = getLogger(__name__)

logger.debug('hello')

Si vous écrivez une "bibliothèque", la situation est complètement différente et "Préparer un enregistreur avec seulement" NullHandler`` défini "est correct, donc le code présenté dans le texte sera" incorrect ".

Je pense que la différence de position peut être résumée dans ce que vous pensez de cette phrase que vous avez signalée.

Je suis comme ça

J'ai le sentiment que ma position s'écarte des «standards» supposés et déduits des documents. Mais je m'en fiche.

Cependant, si vous avez besoin d'un enregistreur racine, vous devez parfois l'utiliser activement, donc si vous devez changer, changez d'idée. A part ça, je ne dis pas que "le root logger mourra" (je ne devrais pas dire ça dans le texte).

De plus, même si le journal est écrit par `` print () '', après toute la malédiction, je capterai le signal nécessaire s'il est là. À la fin de l’année dernière, j’ai vu un tel exemple plutôt terrible. Je ne sais pas.

De plus, je pensais en quelque sorte que ma position ne serait pas établie en premier lieu en fonction de l'échelle. Si le journal arrive dans la classe TB en un jour, il sera envoyé à l'enregistreur racine depuis le début et analysé dans une autre couche. J'ai également pensé que l'ampleur du problème auquel je faisais face était toujours relativement très petite.

Si vous êtes intéressé par les problèmes détaillés, veuillez consulter les commentaires. Personnellement, dans la position ci-dessus, basicConfig () est calme pour ceux qui ne l'utilisent pas (pour l'instant), mais dans la position de recommandation de root logger, `` basicConfig () '' n'est pas utilisé La raison n'est pas trouvée à ce niveau de code initial.

Au fait, en premier lieu, jusqu'à ce que l'on me fasse remarquer, je n'avais pas l'idée de séparer les points de vue de «bibliothèque», «script», «paramétrage de l'enregistreur» et «utilisation de l'enregistreur». Merci @nya.

(Non, les commentaires peuvent continuer)

Mise à jour (2018-08-31)

https://www.python-boilerplate.com/py3+executable+logging

La bibliothèque logging utilisée dans le site de la plaque chauffante que j'ai présenté est passée de la bibliothèque standard à celle du tiers appelé logzero.

Je pense que c'est bien, mais en général, lorsque vous utilisez un module autre que la bibliothèque standard, faites attention à la sécurité, etc. Les détails sont omis ici car ils s'écartent considérablement du contenu de cette entrée.

Recommended Posts

Veuillez arrêter l'impression et importer la journalisation pour la sortie du journal
Double boucle dans l'instruction for puis impression du comportement de l'instruction
Découvrez la fonction d'impression et les chaînes de python pour les débutants.
Accrocher à la première importation du module et imprimer le chemin du module
Pièges et solutions de contournement pour pandas.DataFrame.to_sql
N'apprenez pas Java et C ++! !! Langues que les débutants devraient apprendre [plus soigneusement sélectionnées]
Commentaire d'impartialité et de cohérence pour ceux qui ne tombent pas amoureux