Lassen Sie uns über die Protokollierung sprechen

Dieser Beitrag ist vom Go Forum- Thema inspiriert, das von Nate Finch gestartet wurde. Dieser Beitrag konzentriert sich auf Go, aber wenn Sie darüber hinausgehen, sind die hier vorgestellten Ideen meiner Meinung nach weit verbreitet.

Warum gibt es keine Liebe?


Das Protokollpaket in Go hat keine Ebenen für Protokolle. Sie können die Präfixe DEBUG, INFO, WARN und ERROR manuell hinzufügen. Der Logger-Typ in Go kann diese Ebenen für ausgewählte Pakete nicht separat aktivieren oder deaktivieren. Schauen wir uns zum Vergleich einige Ersetzungen von Drittentwicklern an.

Bild

Google Glog hat Ebenen:

  • Info
  • Warnung
  • Fehler
  • Schwerwiegend (beendet das Programm)

Schauen wir uns eine andere Bibliothek an, loggo , die für Juju entwickelt wurde und in der Levels verfügbar sind:

  • Trace
  • Debuggen
  • Info
  • Warnung
  • Fehler
  • Kritisch

Loggo kann auch den Detaillierungsgrad des Protokolls für die gewünschten Pakete individuell festlegen.

Hier sind zwei Beispiele, die eindeutig unter dem Einfluss anderer Bibliotheken für die Protokollierung in anderen Sprachen erstellt wurden.

Tatsächlich kann ihr Ursprung auf Syslog (3) zurückgeführt werden, möglicherweise sogar früher. Und ich denke, sie sind falsch.

Ich möchte eine kontroverse Position einnehmen. Ich denke, alle Protokollbibliotheken sind schlecht, weil sie zu viele Funktionen bieten. Eine atemberaubende Reihe von Funktionen, die den Programmierer in dem Moment verblüffen, in dem er klar darüber nachdenken muss, wie er mit dem Leser der Zukunft kommunizieren kann und mit wem diese Magazine angezeigt werden.

Ich behaupte, dass erfolgreiche Protokollpakete viel weniger Funktionen und natürlich weniger Ebenen erfordern.

Sprechen wir über Warnungen (WARNUNG)


Beginnen wir mit dem einfachsten. Niemand benötigt die Protokollstufe WARNUNG (Warnung).

Niemand liest Warnungen, weil per Definition nichts Schlimmes passiert ist. Vielleicht kann in Zukunft etwas schief gehen, aber es klingt wie jemand anderes, nicht mein Problem.

Wenn Sie eine mehrstufige Protokollierung verwenden, warum müssen Sie außerdem die WARNING-Ebene festlegen? Sie würden den Pegel auf INFO oder ERROR setzen. Das Einstellen der WARNING-Ebene bedeutet, dass Sie wahrscheinlich Fehler auf der WARNING-Ebene melden.

Warnstufe ausschließen - dies ist entweder eine Informationsmeldung oder ein Fehler.

Lassen Sie uns über das Ausmaß des schwerwiegenden Fehlers sprechen


Die FATAL-Ebene protokolliert die Nachricht tatsächlich und ruft dann os.Exit (1) auf. Im Prinzip bedeutet dies:

  • verzögerte Ausdrücke in anderen Routinen (Goroutinen) werden nicht ausgeführt;
  • Puffer werden nicht gespült;
  • Temporäre Dateien und Verzeichnisse werden nicht gelöscht.

Im Wesentlichen ist log.Fatal weniger ausführlich, aber semantisch gleichbedeutend mit Panik.

Es ist allgemein anerkannt, dass Bibliotheken keine Panik1 verwenden sollten. Wenn jedoch der Aufruf von log.Fatal2 den gleichen Effekt hat, sollte er auch deaktiviert werden.

Die Annahme, dass dieses Bereinigungsproblem durch Registrieren von Shutdown-Handlern im Logger gelöst werden kann, stellt eine enge Beziehung zwischen dem verwendeten Logger und jedem Ort her, an dem Bereinigungsvorgänge stattfinden. Es verstößt auch gegen die Trennung von Interessen.

Zeichnen Sie keine Nachrichten mit der Stufe FATAL auf, sondern geben Sie stattdessen einen Fehler an den Anrufer zurück. Wenn der Fehler main.main erreicht, ist dies der richtige Ort, um eine Bereinigung durchzuführen, bevor Sie das Programm schließen.

Lassen Sie uns über den Fehler sprechen (ERROR-Level)


Fehlerbehandlung und Protokollierung sind eng miteinander verbunden, daher sollte die Fehlerstufenprotokollierung (ERROR) auf den ersten Blick leicht zu rechtfertigen sein. Ich bin nicht einverstanden.

Wenn in Go der Aufruf einer Funktion oder Methode einen Fehlerwert zurückgibt, haben Sie zwei Möglichkeiten:

  • Behandle den Fehler.
  • Geben Sie einen Fehler an den Anrufer zurück. Sie können einen Fehler in der Geschenkverpackung (Wrap) wunderbar einpacken, dies ist jedoch für diese Diskussion nicht wichtig.

Wenn Sie den Fehler durch Schreiben in das Protokoll verarbeiten möchten, handelt es sich per Definition nicht mehr um einen Fehler - Sie haben ihn verarbeitet. Das Registrieren des Fehlers selbst ist die Verarbeitung des Fehlers. Daher ist es nicht mehr ratsam, ihn als Fehler in das Protokoll zu schreiben.

Lassen Sie sich von mir mit diesem Code überzeugen:

err := somethingHard() if err != nil { log.Error("oops, something was too hard", err) return err // what is this, Java ? } 

Sie sollten niemals etwas auf der Fehlerebene registrieren, da Sie den Fehler entweder behandeln oder an den Anrufer weitergeben müssen.

Sie müssen klar verstehen, ich sage nicht, dass Sie nicht in das Protokoll schreiben sollten, dass eine Statusänderung stattgefunden hat:

 if err := planA(); err != nil { log.Infof("could't open the foo file, continuing with plan b: %v", err) planB() } 

In Wirklichkeit haben log.Info und log.Error dasselbe Ziel.

Ich sage nicht "Fehler nicht registrieren"! Stattdessen stelle ich die Frage, was die kleinstmögliche API für die Protokollierung ist. Und wenn es um Fehler geht, glaube ich, dass die überwiegende Mehrheit der auf ERROR-Ebene aufgezeichneten Dinge einfach gemacht wird, weil sie mit dem Fehler zusammenhängen. Tatsächlich sind sie nur informativ, sodass wir die Fehlerprotokollierung (ERROR) aus unserer API entfernen können.

Was bleibt übrig?


Wir haben WARNING ausgeschlossen, argumentiert, dass nichts auf der Fehlerebene (ERROR) protokolliert werden sollte, und haben gezeigt, dass nur die Anwendung der obersten Ebene eine Art Protokoll haben sollte. Schwerwiegendes Verhalten. Was bleibt übrig?

Ich glaube, dass es nur zwei Dinge gibt, bei denen Sie sich anmelden sollten:

  • Dinge, die Entwicklern wichtig sind, wenn sie ein Programm entwickeln oder debuggen;
  • Dinge, die Benutzer bei der Verwendung Ihres Programms interessieren.

Offensichtlich handelt es sich hierbei um Debugging-Ebenen (DEBUG) bzw. Informationsebenen (INFO).

log.Info sollte nur diese Zeile in die Protokollausgabe schreiben. Es sollte nicht möglich sein, es zu deaktivieren, da der Benutzer nur sagen sollte, was für ihn nützlich ist. Wenn ein Fehler auftritt, der nicht verarbeitet werden kann, sollte er in main.main angezeigt werden, wo das Programm beendet wird. Die geringfügige Unannehmlichkeit, das FATAL-Präfix vor der endgültigen Protokollnachricht einfügen oder mit fmt.Fprintf direkt in os.Stderr schreiben zu müssen, ist kein ausreichender Grund, das Paket mit der log.Fatal-Methode zu erweitern.

log.Debug, das ist eine ganz andere Sache. Ein Entwickler oder Support-Ingenieur benötigt es, um das Programm zu steuern. Während der Entwicklung sollten Debug-Ausdrücke zahlreich sein, ohne auf die Trace-Ebene oder Debug2 zurückzugreifen (Sie wissen, wer Sie sind). Das Protokollierungspaket muss eine granulare Steuerung unterstützen, um Debug-Ausdrücke für die gewünschten Pakete im Paket oder möglicherweise sogar in einem engeren Bereich zu aktivieren oder zu deaktivieren.

Fazit


Wenn es eine Twitter-Umfrage wäre, würde ich Sie bitten, zwischen zu wählen

  • Protokollierung ist wichtig
  • Protokollierung ist schwer

Tatsache ist jedoch, dass die Protokollierung beides ist. Die Lösung für dieses Problem MUSS darin bestehen, unnötige Ablenkungen zu zerstören und gnadenlos zu reduzieren.

Was meinen Sie? Ist es extravagant genug, um zu arbeiten, oder ist es nur extravagant?

Anmerkungen


Einige Bibliotheken verwenden möglicherweise Panik / Wiederherstellung als internen Kontrollflussmechanismus, aber das Hauptmantra lautet, dass sie nicht zulassen sollten, dass diese Kontrollflussoperationen aus der Paketgrenze austreten.

Ironischerweise verfügt das Standard-Go-Protokollierungspaket über Fatal- und Panic-Funktionen, obwohl es keinen DEBUG-Ausgangspegel hat. In diesem Paket überschreitet die Anzahl der Funktionen, die zum plötzlichen Beenden des Programms führen, die Anzahl der Funktionen, die dies nicht tun.

Über den Autor


Der Autor dieses Artikels, Dave Cheney , ist Autor vieler beliebter Pakete für Go, zum Beispiel github.com/pkg/errors und github.com/davecheney/httpstat . Sie können die Autorität und Erfahrung des Autors selbst bewerten.

Vom Übersetzer


Viele Entwickler sind besorgt über die Protokollierung. Einige haben das Hinzufügen einer Logger-Schnittstelle zur Standard-Go-Bibliothek erörtert , um die Protokollierung in Bibliotheken zu optimieren und ihre Entwickler auf diese Weise zu stimulieren. Die Jungs haben sogar ihren Vorschlag ausgearbeitet und das Papier zur Diskussion gestellt.

Plus Präsentationsreflexion Brauchen wir einen neuen Logger und was soll er sein? von Chris Hines.

Es gibt mehrere Implementierungen von Daves Go-Log- Ideen und ein wenig Off-Topic zum Thema ERROR-Level sowie ein ausführlicheres Logr- Paket.

Source: https://habr.com/ru/post/de440200/


All Articles