Heim >Backend-Entwicklung >Python-Tutorial >Einfache Python-Protokollierung – und ein Exkurs über Abhängigkeiten, Vertrauen und Kopieren/Einfügen von Code
Header-Bild (C) Tai Kedzierski
Gehe zum Snippet
Dieser Beitrag ist eigensinnig.
Pythons Standardprotokolleinrichtung ist nicht hilfreich; Es widerspricht dem Ansatz „Batterien im Lieferumfang enthalten“, den wir mittlerweile erwarten.
Anhand einer nützlichen Protokollnachricht möchte ich wissen, wann, auf welchem Niveau und welche Informationen. Vielleicht möchte ich es auf der Konsole, vielleicht möchte ich es in einer Datei.
Das sollte einfach sein – aber in Python muss ich jedes Mal nachschlagen, wie ich ein vollständiges Protokollierungsdienstprogramm mit benutzerdefinierter Dateiverwaltung und Zeichenfolgenformatierung erstellen kann.
Es sollte so einfach sein wie logger = getLogger(), aber aus unbekannten Gründen besteht das Standardverhalten darin, eine völlig nutzlose Formatierung bereitzustellen und keine Abkürzung für eine sinnvolle Standardeinstellung.
Das oder ich muss ein PIP-Paket unbekannter Herkunft herunterladen, darauf vertrauen, dass es nicht namentlich gekapert wurde, oder eine verschleierte Exfiltration durchführen. Da fällt mir der Leftpad-Vorfall aus dem Jahr 2016 ein, ebenso wie der Revival-Hijack-Angriff aus dem Jahr 2024, der im Wesentlichen das gleiche Problem in einem anderen Repo-System darstellte.
Tatsächlich ist jedes Benutzer-Repo ohne Namensraum dafür anfällig: Node's npm, Python's pip, Arch's AUR, Canonical's snap ... um nur eine Handvoll zu nennen, die Benutzern einfach erlauben, alles hochzuladen. Nicht einmal die Angabe von Namensräumen ist eine Garantie für Vertrauen – ich bin auf Projekte gestoßen, die ihre Software über diese Kanäle nicht über den Projektnamen, sondern über den Spitznamen eines beliebigen Entwicklers vertreiben, was Zweifel an der Authentizität des Pakets aufkommen lässt. Ich habe in einem früheren Beitrag über die Verwendung von Synchronisierung in einer Arbeitsumgebung meine Gedanken darüber dargelegt, wie ich entscheiden soll, ob ich einer Quelle vertrauen soll.
Externe Abhängigkeiten in benutzergesteuerten Repos sind der Teufel und sollten nur in Betracht gezogen werden, wenn die Lösung eines Problems komplex ist. Und im Allgemeinen sollten einfache Lösungen einfach direkt in der Codebasis vorhanden sein – idealerweise selbst geschrieben, aber manchmal dringt das Problem nur in den „umständlichen“ Bereich ein, sodass sich eine Abhängigkeit sowohl vernünftig als auch eklig anfühlt.
Die Antwort: Schreiben Sie es einmal, verstauen Sie es in einem Github-Gist oder in einem eigenen „Nützliche Snippets“-Repo. Kopieren und einfügen.
Kopieren Einfügen? Puh!
Das „Kopieren und Einfügen“ von Code löst bei jedem erfahrenen Programmierer wahrscheinlich Alarmglocken aus. „Wiederholen Sie sich nicht“, „verwenden Sie einen Paketmanager“, „einmal schreiben, überall aktualisieren.“ Das sind gute Instinkte, aber von Fall zu Fall ist es auch gut zu wissen, wann Kopieren und Einfügen vorzugsweise ist.
In diesem Fall besteht die Anforderung darin, unnötige externe Abhängigkeiten zu vermeidenfür eine einfache Lösung für ein einfaches Bedürfnis . Im Leftpad wie bei diesem Mini-Logger ist das erforderliche Code-Snippet kurz und leicht verständlich; Es ist kein Verlust, es bei Bedarf erneut zu implementieren. Es ist auch entsprechend lizenziert (ja, es kann sich nur um einen Ausschnitt handeln; es wird jedoch weiterhin empfohlen, sicherzustellen, dass das, was Sie kopieren, tatsächlich zulässig ist. Seien Sie vorsichtig beim Kopieren zufälliger Code-Blobs.)
Ich füge unten einen Codeausschnitt für ein Mini-Logger-Dienstprogramm ein, das einen einzelnen Aufruf mit minimaler Konfiguration ermöglicht:
from minilog import SimpleLogger LOG = SimpleLogger(name="mylog", level=SimpleLogger.INFO) LOG.info("this is useful")
Was auf der Konsole gedruckt wird:
2024-11-20 10:43:44,567 | INFO | mylog : this is useful
Kopieren Sie dies in eine minilogger.py-Datei in Ihrem Projekt. Tada – keine externe Abhängigkeit erforderlich. Unangetastet bleibt es für immer dasselbe. Keine Namensentführung. Keine Supply-Chain-Injektion.
# For completeness: # (C) Tai Kedzierski - Provided under MIT license. Go wild. import logging class SimpleLogger(logging.Logger): FORMAT_STRING = '%(asctime)s | %(levelname)s | %(name)s : %(message)s' ERROR = logging.ERROR WARN = logging.WARN INFO = logging.INFO DEBUG = logging.DEBUG def __init__(self, name="main", fmt_string=FORMAT_STRING, level=logging.WARNING, console=True, files=None): logging.Logger.__init__(self, name, level) formatter_obj = logging.Formatter(fmt_string) if files is None: files = [] elif isinstance(files, str): files = [files] def _add_stream(handler:logging.Handler, **kwargs): handler = handler(**kwargs) handler.setLevel(level) handler.setFormatter(formatter_obj) self.addHandler(handler) if console is True: _add_stream(logging.StreamHandler, stream=sys.stdout) for filepath in files: _add_stream(logging.FileHandler, filename=filepath)
Mit der MIT-Lizenz können Sie im Wesentlichen „damit machen, was Sie wollen“. Keine Bedingungen geknüpft.
Da sind wir. Ein einfaches Protokoll ?
Das obige ist der detaillierte Inhalt vonEinfache Python-Protokollierung – und ein Exkurs über Abhängigkeiten, Vertrauen und Kopieren/Einfügen von Code. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!