[PYTHON] Bitte beenden Sie das Drucken und importieren Sie die Protokollierung für die Protokollausgabe

Einführung

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

In einführenden Python-Artikeln erfahren Sie im Allgemeinen, wie Sie die Funktionen aufrufen, die mit dem Protokollierungsmodul geliefert werden, z. B. "logging.debug ()", in der Einführung zu den Protokollierungsfunktionen von Python.

Das von der Python-Head-Familie bereitgestellte "grundlegende Tutorial" zum "Protokollieren" macht in dieser Hinsicht keinen großen Unterschied. Im grundlegenden Tutorial der Python-Familie ist die Methode zur Verwendung von "print" auch als Protokollierungsoption wirksam. Es wird gesagt, dass "print" und "logging.debug ()" entsprechend der Aufgabe ordnungsgemäß verwendet werden sollten. Es wird im Ablauf beschrieben.

Konsolenausgabe anzeigen, die häufig in Befehlszeilenskripten und -programmen verwendet wird: print ()

Erst nach einer solchen "grundlegenden" Erklärung kann das "erweiterte" Tutorial beginnen, den Protokollierungsmechanismus zu erklären, der mit der Python-Sprache geliefert wird. In "Advanced" werden 4 + 1 Arten von Datenstrukturen eingeführt, und hier können Sie die Identität von "logging.debug ()" herausfinden, die häufig in "Basic" verwendet wurde.

Die Protokollierung erfolgt durch Aufrufen einer Methode für eine Instanz der Logger-Klasse (im Folgenden: Logger). Jede Instanz hat einen Namen und ist konzeptionell in einer Namespace-Hierarchie angeordnet, mit Punkten (Punkten) als Trennzeichen. Ein Logger mit dem Namen "scan" ist beispielsweise das übergeordnete Element der Logger "scan.text", "scan.html" und "scan.pdf". Der Name des Protokollierers kann beliebig sein und zeigt an, wo die protokollierte Nachricht aufgetreten ist. .. Die Wurzel der Logger-Hierarchie wird als Root-Logger bezeichnet. Dies ist der Logger, der von den Funktionen debug (), info (), warning (), error () und Critical () verwendet wird. Diese Funktionen rufen einfach die gleichnamige Methode des Root-Loggers auf. Diese Funktionen und Methoden haben dieselbe Signatur. Der Name des Root-Loggers wird in der Protokollausgabe als "root" angezeigt.

Es gibt tatsächlich praktische Python-Anwendungen, die "print" für die Protokollausgabe verwenden. Wahrscheinlich "ganz".

Der vorherige Autor hat auch print verwendet, um das Protokoll anzuzeigen. Aber jetzt vermeide ich es fast, mich mit "print" anzumelden, außer in Fällen wie einem winzigen Skript zur Bestätigung mit weniger als 10 Zeilen.

Persönlich denke ich nicht, dass ** print oder`` logging``` Python-Anfängern überhaupt beigebracht oder empfohlen werden sollte **. Zumindest denke ich nicht, dass es die richtige Reihenfolge ist, um das offizielle Python "Basic Tutorial" zu unterrichten.

Dieser Artikel versucht zu erklären, warum Sie so gedacht haben.

Vorsichtsmaßnahmen beim Lesen der folgenden

Der Autor dieses Artikels kennt sich nicht so gut aus wie ein Python-Committer (zum Zeitpunkt der Veröffentlichung der ersten Ausgabe und zum Zeitpunkt der Überarbeitung). Bitte lassen Sie uns wissen, wenn der Inhalt fehlerhaft ist.

Auch die Tatsache, dass "ich das Tutorial eine Weile nicht richtig gelesen habe, nachdem ich das" Logging "-Modul gekannt hatte", was als individuelles Problem des Autors angesehen werden sollte, hat mich dazu inspiriert, diesen Satz zu schreiben. .. Bitte verzeihen Sie mir die Tatsache, dass ein Teil des Inhalts nicht wie "Heulen der Anfänger" aussieht, aber es ist ein Problem auf der Dokumentseite.

Wenn Sie nur die Best Practices kennenlernen möchten, lesen Sie Best Practices für die Python-Protokollierung.

Warum nicht: print

Lassen Sie uns über die Implementierung einer bestimmten Python-App aus der Sicht anderer sprechen.

Eines der Probleme bei der Protokollausgabe mit "print" ist "Ich weiß nicht, ob die angezeigte Zeichenfolge eine Protokollausgabe ist oder welche Informationen das Befehlszeilentool dem Benutzer wirklich präsentieren möchte". Kann gemacht werden.

Es ist kein Problem, Pythons "print" selbst zu verwenden, "es sei denn, es dient zu Protokollierungszwecken". Angenommen, Sie implementieren den Linux-Befehl "tee" selbst. Es wäre nicht unbedingt ein Fehler, die Standardausgabe mit "print" zu schreiben, während die mit der Standardeingabe empfangenen Daten in eine Datei geschrieben werden. Dies ist ein Beispiel für "die Ausgabe, die Sie wirklich wollen".

Die "wirklich gewünschte Ausgabe" ist hier das "Etwas" auf der Ausgabeseite, als das Programm ein Werkzeug war, das "einige Eingaben empfängt und etwas ausgibt".

Andererseits ist ein Protokoll ein "Datensatz", in dem ein im Prozess erzeugtes Programm ausgeführt wird.

In diesem Artikel möchte ich "für die Protokollausgabe" sagen, dh wenn Sie "Ich bin verrückt. Ich bin verrückt hier, ich sage Ihnen ~" aufnehmen möchten, stoppen Sie den rohen "Druck" -basierten Ansatz. Das ist.

Wenn dies ein Skript mit 10 bis 20 Zeilen ist, ist es immer noch besser, und wie ich am Anfang geschrieben habe, verwende ich auch "print", wenn dies der Fall ist.

Wenn Sie beispielsweise Beispielcode schreiben, der das Verhalten bei Division durch 0 kennt,

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

Es wird kein Problem mit dem Schreiben wie geben. Dieser "Druck" ist eigentlich eher ein Protokoll als eine gewünschte Ausgabe, eine "Aufzeichnung" der Programmoperation. Es ist jedoch offensichtlich, dass es dumm ist, das Protokollierungsmodul mit Code dieser Größe zu verwenden.

Andererseits haben relativ komplizierte Bibliothekstools wie zweistellige Dateien möglicherweise ihr eigenes "druckbasiertes" Protokollierungssystem abgeschlossen.

Lassen Sie uns über eine Python-Bibliothek sprechen, auf die ich gestoßen bin (zumindest war es eine relativ bekannte Bibliothek, als ich sie fand). In dieser Bibliothek habe ich meine eigene basierend auf "print" implementiert, die durch die Kombination von "Logger" und "Handler" des "Logging" -Moduls leicht realisiert werden kann. Es gab keinen Mechanismus, der der Protokollstufe entsprach. Es gab einen Mechanismus wie ein Tag zum Trennen der Protokolltypen, aber das Tag wird nur verwendet, wenn verzweigt wird, ob ausgegeben werden soll oder nicht, und wenn es in "print" angezeigt wird, ist es Teil der Zeichenfolge. Es wird gemischt.

Es gibt viele Probleme mit einem solchen bibliotheksspezifischen Protokollierungsmechanismus. Zunächst kann nicht festgestellt werden, ob es sich bei dem Inhalt des Ausgabeprotokolls um ein "schweres Protokoll" oder eine "Debug-Protokollausgabe" handelt. .. Je nachdem, zu welcher Kategorie der Fehler gehört, müssen die rohen Zeichenfolgen mit regulären Ausdrücken usw. neu sortiert werden. Dies gibt Ihnen keine angemessene Kontrolle über das Protokoll.

Außerdem müssen Benutzer, die mit Python vertraut sind, einen Protokollierungsmechanismus verwenden, der sich von Pythons "Protokollierung" unterscheidet, und es müssen zusätzliche Schritte unternommen werden, um die Absichten und Einschränkungen dieses Mechanismus zu verstehen. Wenn Ihnen die Python-Module fehlen, ist es am schlimmsten, wenn Sie nur eine verschlechterte Version erstellen können.

Nicht auf Python beschränkt, sollten Sie denken, dass ** nur das Trennen von stdout und stderr als moderner Protokollierungsmechanismus keine Punktzahl ergibt **.

Das Umschreiben einer App, die ursprünglich auf "print" basiert, um die Funktionen von "logger" zu nutzen, ist ziemlich mühsam oder vielleicht sehr mühsam. Auf der Empfangsseite ist es möglicherweise möglich, den Inhalt von stderr zu "retten" und an "logger" zurückzusenden, dies ist jedoch problematisch. In jedem Fall ist es ehrlich gesagt unfruchtbar.

Aus der Sicht des Benutzers sieht der auf "Drucken" basierende Ansatz wie folgt aus: "Ich habe alles in das Abwasser gespült, also holen Sie es bei Bedarf."

Wenn auf GitHub ein Tool veröffentlicht wurde und die Debug-Welt "print" bei Interesse entfaltet wurde, kratzte sich der Benutzer am Kopf, ohne die Essenz des Tools zu berühren. Werden. Ich wurde.

Erstens war der ursprüngliche Protokollierungsmechanismus der Python-Bibliothek so schlecht und schockiert, dass ich diesen Artikel geschrieben habe.

Warum nicht: logging

Python-Logger haben eine hierarchische Struktur und eine Baumstruktur. In der Metapher eines Baums werden mehrere Protokolle (eine Instanz der Klasse "LogRecord"), die vom Happa ankommen, an dem Punkt empfangen, an dem sie auf einen Zweig treffen ("Logger") und den Root-Logger ("Root-Logger") erreichen. Der Logger kann ein Log wiederholt verarbeiten. Sie können auch verhindern, dass sich das Protokoll von einem Zweig zum nächsten (näher am Stamm) Zweig ausbreitet (Attribut propagate). Für Details lesen Sie bitte Advanced Tutorial.

Hier,

logging.debug()

Schreiben bedeutet, dass selbst in der Protokollbaumstruktur von Python Informationen direkt in den Root- "Root-Logger" eingefügt werden.

Der Root-Logger ist auch das Root des Logging-Mechanismus für alle Module, die von der gestarteten Python-Laufzeit aufgerufen wurden, und ist die "globale Variable" selbst.

Wenn jede Bibliothek diese Funktionen (sowie "logging.info ()" usw.) aufruft, die direkt mit dem "logging" -Modul geliefert werden, verschmutzt dies implizit die Welt (den Namespace) anderer Module. Werden.

Wenn Sie die Protokollstufe des Root-Loggers auf DEBUG setzen, um das Protokoll der Bibliothek A anzuzeigen, wird auch das DEBUG-Protokoll des Root-Loggers, das andere Bibliotheken (Bibliothek B, Bibliothek C ...) eingegeben haben, untrennbar angezeigt. .. Es ähnelt dem unbeschreiblichen Protokoll, das mit print in stderr gegossen wurde, da es untrennbar miteinander verbunden war.

In Quellen wie fortgeschrittenen Tutorials und Python-Kochbüchern (für fortgeschrittene Benutzer und höher?) Sollten Sie in Betracht ziehen, Logger zu verwenden, anstatt "beim Erstellen einer Bibliothek" zu protokollieren.

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

Natürlich beschreibt das grundlegende Tutorial auch diesen Bereich.

Dieses Muster in mylib.py kann auf mehrere Module verallgemeinert werden. Beachten Sie, dass Sie in diesem einfachen Verwendungsmuster die Ereignisbeschreibung anhand der Protokolldatei anzeigen können, jedoch nicht, woher die Nachricht in der Anwendung stammt. Wenn Sie den Speicherort Ihrer Nachrichten verfolgen möchten, benötigen Sie eine Dokumentation, die über diese Lernprogrammstufe hinausgeht - siehe Tutorials zur erweiterten Protokollierung.

Es ist nicht so kurz, seit ich Python benutze, aber es ist erst ein paar Jahre her, seit ich es zum ersten Mal gesehen habe. Es war ungefähr zur gleichen Zeit, als ich die wahre Bedeutung verstehen konnte. Nachdem ich einige streunende Artikel gesehen hatte, war ich überzeugt, dass "Ja ... das stimmt, die Funktion direkt unter" Protokollierung "ist nicht gut", und als ich das Tutorial noch einmal las, wurde es tatsächlich geschrieben.

Beispiel für einen streunenden Artikel: [Best Practice für Python-Protokollierung](shttp: //pieces.openpolitics.com/2012/04/python-logging-best-practices/)

Ich persönlich fand es sehr ärgerlich ** Nach einer kurzen Erklärung im Tutorial, dass Sie sich mit "logging.debug ()" oder "print" abmelden können, ist eine bessere Best Practice Es bedeutet, dass es geschrieben ist **.

Rückblickend habe ich das Gefühl, dass die früher eingeführte Methode in erster Linie sehr wenig Geschmack hat. Und ich beschloss, alles mit aller Kraft neu zu schreiben.

Sogar "Import Logging" ist ärgerlich

Es ist mir peinlich, weil ich oft Fehler mache ...

Nachdem ich einige der oben genannten Themen verstanden hatte und zu der allgemeinen Meinung gelangt war, dass logging.debug () nicht verwendet werden sollte, schrieb ich am Anfang jedes Moduls logger = logging.getLogger (__name__). Ich schrieb wie , und der gesamte Code danach begann Logger zu verwenden.

Aber mitten im Schreiben

logger.debug()

Wann

logging.debug()

Ich schreibe durch Mischen. Es fliegt an einen anderen Ort!

Sie mögen denken, dass es keine große Sache ist, aber wenn Sie sich die Protokolle ansehen und die Ursache eines Fehlers verfolgen, können Sie den trivialen Unterschied zwischen ** logger und logging und dem Ziel der Funktion übersehen. Ich weiß nicht was es ist **. Je mehr Sie eine stark strukturierte Protokollbaumstruktur erstellen, desto mehr zeigt "logging.debug ()" auf, vorausgesetzt, Sie verweisen auf eine "Logger" -Instanz mit einer Protokollstufe oder einer Protokolldateispezifikation, für die Sie "logger" möchten. Root Logger sind in der Regel Holzfiguren, die nichts ausgeben. logger.debug () gibt eine aussagekräftige Zeichenfolge in eine Datei aus und logging.debug () hinterlässt heimlich eine Nachricht in "Danmari" oder irgendwo anders und verfolgt sie aus der Protokolldatei. Wird schwierig oder unmöglich sein.

Wenn Sie nicht interaktiv mit Haltepunkten debuggen, werden Sie den trivialen Unterschied zwischen den Zeichenfolgen "logger" und "logging" möglicherweise erst am Ende bemerken. ** Menschen sind nicht gut darin, ähnliche Zeichenfolgen zu unterscheiden **. Leider ist zum Zeitpunkt der "Importprotokollierung" auch kein Grammatikfehler aufgetreten. Erwarten Sie eine andere Hervorhebungsfarbe des Editors? ??

Es gibt eine einfache Problemumgehung.

#Beschädigt
import logging
logger = logging.getLogger(__name__)

Bedeutet "nicht schreiben".

from logging import getLogger
logger = getLogger(__name__)

Ist zu schreiben.

Ich war schockiert, als ich diese einfache Problemumgehung fand. Es ist peinlich, dass ich es nicht bemerkt habe.

Ich habe mich immer gefragt, warum ich nicht daran denken kann

import logging
logging.debug()

Es muss gewesen sein, weil ich geführt wurde. Ich beschuldige andere.

Das erste Mal, dass ich dieses Ersatzproblem für "schlecht" hielt, war, als ich die oben genannten "Protokollierung" und "Protokollierung" fälschlicherweise beim Erstellen eines Dienstes implementiert habe, der lange Zeit mit Django (Webframework) ausgeführt wird. tat.

Als ich der Implementierung der Funktion nachjagte, gab es einen Moment, in dem aus irgendeinem Grund kein Protokoll ausgegeben wurde, und ich sah mit einem Gesicht auf, das sagte: "Warum wird es nicht ausgegeben, hey, warum gibt es hier kein Protokoll ... (゚ Д ゚)" ... Es war wirklich ein kostenloser Tippfehler. Ich kann weinen Wiederum ** sind Menschen nicht gut darin, ähnliche Zeichenfolgen zu unterscheiden **.

Hier wage ich es, die "Import-Protokollierung" selbst als Problem zu betrachten. Für die Funktionen direkt unter diesem Modul

Die beiden Funktionen sind gemischt. Es ist sehr gemischt.

Ersteres sollte nur sehr begrenzte und begrenzte Auswirkungen auf das gesamte Programm haben. Letzteres sollte nur verwendet werden, wenn Sie sich sicher sind.

In beiden Fällen ist es zu subtil, um zu Beginn die vollständige Primzahl der "Importprotokollierung" zuzulassen, aber das Tutorial erklärt dies zuerst. Es ist, als würde man Anfängern empfehlen, Fehler zu machen.

Um menschliche Fehler zu vermeiden, können Sie die Verwendung des Objektnamens "logger" beenden und "log.debug ()" verwenden. Ich mag es jedoch nicht, weil es schwer zu sagen ist, ob es sich um Protokollierung oder Protokollierung handelt.

Die Hauptfunktion empfängt übrigens "Logger". Sie können standardmäßig Ihren eigenen Logger verwenden

Wenn sich die Funktion darauf vorbereitet, "Logger" zu akzeptieren, z. B. über ein optionales Argument, erhalten Sie mehr Flexibilität, wenn Sie versuchen, es als Bibliothek zu verwenden. Dies ist eine sogenannte Abhängigkeitsinjektion.

def do_some_great_stuff(arg_a, arg_b, logger=None):
    logger = logger or _your_default_logger
    #Erstaunliche Sache

Für Python3 können Sie ein optionales Argument erzwingen. Lieber!

def do_some_great_stuff(arg_a, arg_b, *, logger=None):
    logger = logger or _your_default_logger
    #Erstaunliche Sache

In Python3 wird es nach dem bloßen "*" zu einem "Nur-Schlüsselwort-Argument". Das Python2-System verfügt nicht über diese Syntax, daher wird es dynamisch mit ** kwargs verarbeitet. Weitere Informationen finden Sie unter "Punkt 21: Erhöhen der Klarheit durch Nur-Schlüsselwort-Argumente" und Glossar in "Effektives Python".

Wenn Sie das Logger-Objekt selbst verwalten und es nicht nach außen offenlegen, können Sie die Protokolle nicht einheitlich verwalten, indem Sie die Logger dieses Moduls nach Bedarf durch andere ersetzen.

Angenommen, Entwickler A verwendet die API der externen Bibliothek B, während er eine Reihe von Prozessen mit dem von getLogger ('service_a.do_something') erstellten Logger ausführt. Wenn diese Bibliothek den Logger über getLogger (service_b.do_bad_thing) erhält und Sie ihn nicht ersetzen können, werden Handler und Format wahrscheinlich separat verwaltet. Dies ist sehr unpraktisch, um den Ausführungsprozess einer Funktion zu verfolgen. Aus Sicht des Entwicklers A lautet die Tendenz "Lassen Sie mich hier meinen Logger verwenden".

Es gibt Fälle, in denen es für einen Außenstehenden sehr praktisch ist, jede Funktion in der Bibliothek einem anderen Logger für einen anderen Zweck zuzuordnen.

Sofern Sie sich nicht wirklich um andere Umstände (Leistung usw.) kümmern, möchte ich auf jeden Fall, dass Sie eine Struktur haben, die die Verarbeitung für jeden Logger trennen kann, und selbst wenn Sie sie selbst verwalten, verwenden Sie die Logger-Baumstruktur gut, um die Serie zu benennen Ich möchte, dass du dich teilst.

Nachtrag (2017-07-07): Wenn davon ausgegangen wird, dass die Funktion usw. von Außenstehenden als Bibliothek verwendet wird, sollte hier kein anderer Handler als "NullHandler" zu "_your_default_logger" hinzugefügt werden. Empfohlen. Übrigens gibt ein Logger, der keinen Handler enthält, grundsätzlich eine Warnung aus.

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

Außerdem möchte ich, dass Sie diese Unterstützungsstufe ausführen, wenn Sie sie auf GitHub veröffentlichen.

Für den Autor möchte ich, dass Sie in der Lage sind, "Logger" zu verwenden, wenn Sie dies bereits in der einfachen Veröffentlichungsphase von "Ich habe es mit meinem eigenen Skript geschrieben, ich habe es vorerst geschrieben!" Bemerken.

Personen, die das aktuelle Tutorial "schnell" lesen, wählen "Drucken" oder "Protokollieren". Sie sollten jedoch in der Lage sein, "Protokollierer" mit nur geringfügigen Änderungen in der Reihenfolge der Erklärung zu verwenden. Auf der "Ebene, die ich ausprobiert habe" habe ich das Gefühl, dass sich die Kosten für "Drucken" und "Logger" nicht wesentlich ändern.

Hier ist ein Beispiel.

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')

Es endet einfach. Ich denke, es gibt viele "magische" Zeilen, aber ich habe das Gefühl, dass ich es schaffen kann, weil ich kopieren und einfügen kann.

Persönlich denke ich, dass es besser ist, die Kritik zu erheben, dass setLevel () hier zweimal vorkommt. Oh, diese Schuld habe ich vor ein paar Tagen gerufen. Ausgelassen, wenn es zu hals ist.

Wenn Sie in diesem Fall das Protokoll nicht ausspucken möchten, verwenden Sie einfach "NullHandler" anstelle von "StreamHandler". Wenn Sie die Protokollrotation entsprechend der Größe durchführen möchten, gibt es "RotatingFileHandler". Wenn Sie mehr als die Fehlermeldung per E-Mail versenden möchten, gibt es "SmtpHandler"!

Die Behauptung hier lautet: "Ich möchte, dass Sie mir am Anfang eine so magische Formulierungsebene beibringen." Umgekehrt sollten Sie nicht einmal schreiben, dass "print" oder "logging.debug ()" in Protokollierungs-Tutorials in Ordnung ist.

Hinweis: Die Behauptung hier lautet nicht "fordern wir von Anfängern schweres Gewicht". Die Geschichte lautet: "Nehmen Sie keine Wörter in das Tutorial auf, die es Ihnen leicht machen, in eine Sackgasse zu geraten." Egal was passiert, ich benutze "Drucken" in Situationen, in denen ich es benutze. Weil es einfach ist. Sie müssen die Nutzung einfach nicht steigern. Am Ende werden Sie feststellen, dass eine solche Methode in einigen Fällen praktisch ist.

Hinweis 2 (Nachtrag vom 17.11.2016): Wenn die obige DI durchgeführt wird, kann das DEBUG-Protokoll (möglicherweise Passwort usw.) von einem Außenstehenden willkürlich angezeigt werden, sodass ich mir ein wenig Sorgen um die Sicherheit mache. Ich frage mich, ob es eine Richtung gibt. Ich frage mich jedoch, was ich in einer Sprache sage, in der die Instanz praktisch keine privaten Variablen enthält.

Anmerkung 3 (2017-07-07 postscript): Es gibt auch die Idee, basicConfig () zuerst zu verwenden, wenn die Einstellung des Startteils als Skript geschrieben wird, und tatsächlich kann es präziser geschrieben werden (siehe Kommentar) ). Ich persönlich denke jedoch, dass Root-Logger zu diesem Zeitpunkt in den frühesten Stadien nicht verwendet werden sollten, daher habe ich beschlossen, sie nicht zu verwenden. Bei der Überprüfung dieser Zeit stellte ich fest, dass ich den Geschmack nur sehen konnte, wenn ich "logger.propagate = False" tat, also fügte ich ihn hinzu.

"Problem der Unterrichtsordnung"

Er redet weiter über "Unterrichte nichts wie" print "oder" logging.debug () "zuerst."

Wann immer ich etwas debuggen möchte, lese ich einfach die Dokumentation mit größter Anstrengung, um den Fehler zu beseitigen.

Zu diesem Zeitpunkt möchte ** der Entwickler nicht das gesamte System lernen **.

Sie sollten glauben, dass am Anfang des Dokuments die Methode steht, die jeder für die prägnanteste und vielleicht anständigste hält. Zumindest erwarte ich nicht, dass es so etwas wie "Entschuldigung, es ist nicht der richtige Weg, es zu tun!" Sagt.

Andererseits erweckt die aktuelle Python-Protokollierung den Eindruck, dass wichtige Dinge am Ende geschrieben werden, mit der Erwartung, dass sie das System bis zum Ende lernen. Oder selbst wenn es mehrere Methoden gibt (obwohl es zu diesem Zeitpunkt für Python NG zu sein scheint), ist die Struktur so, dass der Leser überzeugt ist und geht, wenn die erste aufgerufen wird (die Basis ist "fortgeschritten"). Es steht geschrieben).

Obwohl der später geschriebene Inhalt angemessener ist, wird die Methode beschrieben, die zuvor nicht empfohlen wurde, und nur die Methode, die nicht empfohlen wird, wenn ein Anfänger das Dokument in der Mitte verlässt, wird von der Person gespeichert ...

Einige Zeit, nachdem der Benutzer die Dokumentation zum ersten Mal auf diese Weise gelesen hat, vergisst er, was er getan hat und warum er diese Protokollierungsmethode angewendet hat, und ruft auch die ersten 10 Zeilen des Tutorials zu logging.debug ( ) Verwenden Sie ...

Oder im schlimmsten Fall haben Sie Ihren eigenen Protokollmechanismus eingebaut, während Sie falsch verstehen, dass "Drucken" in Ordnung ist ...

Wenn es um die Protokollierung geht, bin ich der festen Überzeugung, dass diese Methode, die am Anfang des Dokuments eine Lösung zu haben scheint, in dieser Hinsicht sehr schlecht ist. Die Lehrmethode ist in erster Linie "okashii".

Auf diese Weise richtet der Benutzer den Protokollierungsmechanismus falsch aus und veröffentlicht das Tool. Wenn das Tool bis zu einem gewissen Grad verfeinert wird, werden es viele andere sehen, aber ... Es kann zu spät sein. Ich glaube nicht, dass der Entwickler etwas falsch macht.

Noch problematischer ist, dass das Problem, das der Entwickler oder Benutzer des Tools wirklich lösen möchte, normalerweise nicht direkt mit dem Protokollierungsmechanismus verbunden ist. Es löst das Problem, aber weil es einen schrecklich verzerrten Protokollmechanismus enthält, heißt es: "Ich habe was ich will, aber ... etwas ... es ist schwer zu benutzen !?" Wenn Sie von Anfang an nicht die richtige Antwort wählen, sind diese Probleme nicht motivierend, sie zu beheben.

Natürlich ist es möglich, Korrekturen an der veröffentlichten Quelle vorzunehmen. Protokolle rufen normalerweise nur eine Funktion auf, die irgendwo im Code eine Zeichenfolge erstellt und anzeigt. Ein Außenstehender sagt daher: "Dieser auf Druck basierende Protokollierungsmechanismus befindet sich im Standard-Python-Modul. Sie können eine PR (Pull Request) durchführen und sagen: "Sie können alles durch Logger ersetzen."

Es wäre jedoch unfruchtbar, die Korrektur der Protokollausgabelogik zu diesem Zeitpunkt zu veröffentlichen ... Nein, es wäre schön, wenn Sie nur den Kopf des Teufels nehmen wollten.

** Ich denke, dass die Welt viel sauberer ist, wenn Sie sagen "Sie müssen die Details der Python-Protokollierung nicht kennen, also können Sie" logger = getLogger (__ name__) "verwenden, das war's!" . Es ist immer noch einfach, es zu einem Argument einer Funktion zu machen, und es in ein " kwargs" oder ein optionales Argument zu ziehen, wäre keine große Sache.

Wurde länger

Wenn Sie mit der Python-Protokollierung noch nicht vertraut sind, werden die anfänglichen Einstellungen des Protokollierers beim Schreiben eines einzelnen Ausführungsskripts vorgenommen

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')

Das ist alles zum Schreiben.

Nachtrag (2017-07-07): Eine Alternative wird am Ende dieses Eintrags vor dem Hintergrund des Kommentars angezeigt. Außerdem wird im Fall einer Bibliothek darauf hingewiesen, dass es schädlich ist, diesen Code vorerst zu schreiben. Deshalb habe ich den Satz "Für die anfängliche Einstellung des Loggers beim Schreiben eines einzelnen Ausführungsskripts" hinzugefügt. Weitere Informationen finden Sie im folgenden Postskriptum.

Übrigens, warum war es so ein langer Satz, nur um das zu vermitteln ...

Seit jeher sind Python-Protokollierungs-Tutorials strukturiert, daher bin ich nicht daran interessiert, darüber zu sprechen, was passiert, wenn ich dies jetzt schreibe. Es gibt keine wirkliche Motivation, die Oberfamilie zu schlagen. Ich denke jedoch, dass einige wichtige Punkte zu beachten sind.

Wenn Sie an Python interessiert sind, das Protokoll aber nicht gut verstehen, lassen Sie bitte nur getLogger (__name __) in der Ecke Ihres Kopfes. Wenn es zumindest in Ihrem Kopfwinkel hängen bleibt, ist es weniger wahrscheinlich, dass Sie das Tutorial in der Mitte nicht mehr lesen.

Beziehung

Update (17.11.2016)

Ich las den Inhalt noch einmal und versuchte, einige Teile zu ergänzen und den Teil zu korrigieren, in dem Japanisch chaotisch war. Ich kenne Python3 und füge konkreten Code hinzu.

Ich fand jedoch auch, dass der "Schwung", den der Autor zu dieser Zeit hatte, wichtig war, so dass die überflüssigen Sätze selbst unberührt blieben.

Ich werde einen separaten Satz schreiben, der nur die Methoden extrahiert, die ich für die besten Praktiken halte.

Update (2017-07-05)

Die folgenden Kesselplatten stehen als Referenz zur Verfügung.

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

Ich habe dies bemerkt, aber im obigen Beispiel ist der Root-Logger verschmutzt.

Update (2017-07-06, 2017-07-07)

Es wurde darauf hingewiesen, dass ich mit dem Ausschnitt im Abschlussabschnitt dieses Eintrags nicht zufrieden war, also habe ich ihn hinzugefügt.

Zunächst habe ich dem Code im Text logger.propegate = False hinzugefügt, da die Umstände in 2017-07-05 beschrieben sind.

Darüber hinaus muss zunächst die Prämisse "Wenn Sie mit dem Schreiben eines einzelnen Skripts beginnen" und die folgenden Alternativen vorgestellt werden.

from logging import basicConfig, getLogger, DEBUG

#Schreiben Sie dies nur in die Hauptdatei
basicConfig(level=DEBUG)

#Schreiben Sie dies in alle Dateien
logger = getLogger(__name__)

logger.debug('hello')

Wenn Sie eine "Bibliothek" schreiben, ist die Situation völlig anders und "Bereiten Sie einen Logger mit nur" NullHandler`` set "vor, ist korrekt, sodass der im Text dargestellte Code" falsch "ist.

Ich denke, der Unterschied in der Haltung lässt sich in Ihrer Meinung zu diesem Satz zusammenfassen, auf den Sie hingewiesen haben.

ich bin so

Ich habe das Gefühl, dass meine Position von den "Standard" -Positionen abweicht, die aus den Dokumenten angenommen und abgeleitet werden. Aber das interessiert mich nicht.

Wenn Sie jedoch einen Root-Logger benötigen, müssen Sie ihn manchmal aktiv verwenden. Wenn Sie also wechseln müssen, wechseln Sie Ihre Ideen. Abgesehen davon sage ich nicht, dass "der Root-Logger sterben wird" (das sollte ich im Text nicht sagen).

Außerdem, selbst wenn das Protokoll von print () geschrieben wird, werde ich nach all dem Fluch das notwendige Signal aufnehmen, wenn es da ist. Ende letzten Jahres sah ich ein solches Beispiel als ziemlich schrecklich an. Ich weiß es nicht.

Außerdem dachte ich irgendwie, dass meine Haltung je nach Maßstab überhaupt nicht etabliert werden würde. Wenn das Protokoll an einem Tag in der TB-Klasse eingeht, wird es von Anfang an an den Root-Logger gesendet und in einer anderen Ebene analysiert. Ich dachte auch, dass das Ausmaß des Problems, mit dem ich mich befasste, immer relativ klein war.

Wenn Sie an den detaillierten Themen interessiert sind, lesen Sie bitte die Kommentare. Persönlich ist in der obigen Haltung "basicConfig ()" ruhig für diejenigen, die es (vorerst) nicht verwenden, aber in der Haltung der Root-Logger-Empfehlung wird "basicConfig ()" nicht verwendet Der Grund wird auf dieser anfänglichen Codeebene nicht gefunden.

Übrigens hatte ich, bis ich darauf hingewiesen wurde, zunächst nicht die Idee, die Gesichtspunkte "Bibliothek", "Skript", "Loggereinstellung" und "Logger verwenden" zu trennen. Vielen Dank, dass Sie @nya.

(Nein, Kommentare können noch fortgesetzt werden)

Update (2018-08-31)

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

Die "Protokollierungs" -Bibliothek, die in der von mir eingeführten Kesselplatten-Site verwendet wird, wurde von der Standardbibliothek auf die für den Drittanbieter "logzero" geändert.

Ich denke, das ist in Ordnung, aber im Allgemeinen, wenn Sie ein anderes Modul als die Standardbibliothek verwenden, achten Sie bitte auf Sicherheit usw. Details werden hier weggelassen, da sie erheblich vom Inhalt dieses Eintrags abweichen.

Recommended Posts

Bitte beenden Sie das Drucken und importieren Sie die Protokollierung für die Protokollausgabe
Doppelschleife für Anweisung und dann Drucken des Anweisungsverhaltens
Erfahren Sie mehr über die Druckfunktion und die Zeichenfolgen von Python für Anfänger.
Schließen Sie den ersten Import des Moduls an und drucken Sie den Modulpfad
Fallstricke und Problemumgehungen für pandas.DataFrame.to_sql
Lerne nicht Java und C ++! !! Sprachen, die Anfänger lernen sollten [sorgfältiger ausgewählt]
Kommentar zu Unparteilichkeit und Beständigkeit für diejenigen, die sich nicht verlieben