2015-11-24 6 views
8

Ich habe bisher die Verwendung von log.Fatal vermieden, aber ich habe vor kurzem zufällig diese Fragen entdeckt; code-coverage und tests-using-log-fatal.Sollte ein Go-Paket jemals log.Fatal verwenden und wann?

Einer der Kommentare aus den 100 Code-Coverage-Fragen sagt:

... In der überwiegenden Mehrzahl der Fälle log.Fatal sollte nur in Haupt- oder init-Funktionen verwendet werden (oder möglicherweise einige Dinge gemeint genannt werden, nur direkt von ihnen)“

Es gehen mir zu denken, so begann ich an der Standard-Bibliothek Code mit Go zur Verfügung gestellt zu sehen. Es gibt viele Beispiele, wo die Test Code in der Bibliothek der Nutzung macht log.Fatal scheint gut zu sein

// net/http/transport.go 
func (t *Transport) putIdleConn(pconn *persistConn) bool { 
    ... 
    for _, exist := range t.idleConn[key] { 
     if exist == pconn { 
      log.Fatalf("dup idle pconn %p in freelist", pconn) 
     } 
    } 
    ... 
} 

Wenn seine beste Praxis zu vermeiden Verwendung von log.Fatal ist, warum ist es überhaupt in den Standardbibliotheken verwendet, ich erwartet hätte: ein paar Beispiele außerhalb des Testcodes, wie in net/http, unten gib einfach einen Fehler zurück. Es erscheint dem Benutzer der Bibliothek unfair, os.Exit angerufen zu werden und keine Möglichkeit zu bieten, dass die Anwendung aufräumt.

Ich kann naiv sein, daher meine Frage als eine bessere Praxis scheint zu log.Panic zu sein, die wiederhergestellt werden kann und meine theoretische lang laufende stabile Anwendung könnte eine Chance haben, aus der Asche zu steigen.

Also was wäre Best-Practice sagen für Go wann sollte log.Fatal verwendet werden?

+3

Meine Hoffnung wäre, dass dieser Code absolut unerreichbar ist. Dass ein Fehler, der dazu führt, dass sich eine inaktive Verbindung immer noch in der inaktiven Liste befindet, während sie gleichzeitig als aktive Verbindung verwendet wird, sollte nicht etwas sein, was jemals passieren sollte, und das sollte katastrophal sein. Aber da sie scheinen, Mutexe richtig um die freie Liste und so weiter zu verwenden, habe ich keine Idee, warum diese Schleife und der Code überhaupt notwendig wären. Warum sie Ihr Programm lieber sofort beenden würden als Panik zu verbreiten, ist ein weiteres Rätsel. Große Frage. – captncraig

+0

Kann einer der Tests in diesem Paket diese Linie erreichen? – captncraig

+0

Gute Frage, hatte ein wenig Blick und kann nichts sehen, das aussieht wie sein speziell entwickelt, um diese Linie zu erreichen. Noch nicht schlüssig ... – miltonb

Antwort

8

Es könnte nur ich sein, aber hier ist, wie ich log.Fatal benutze. Gemäß den UNIX-Konventionen sollte ein Prozess, bei dem ein Fehler auftritt, so früh wie möglich mit einem Nicht-Null-Beendigungscode fehlschlagen. Dies führt mich zu den folgenden Richtlinien log.Fatal zu verwenden, wenn ...

  1. ... ein Fehler in jedem meiner func init() geschieht, da diese passieren, wenn die Importe verarbeitet werden oder vor der Haupt func aufgerufen sind. Umgekehrt mache ich nur Sachen, die nicht direkt die Arbeitseinheit beeinflussen, die die Bibliothek oder cmd ausführen soll. Zum Beispiel konfiguriere ich die Protokollierung und überprüfe, ob wir eine vernünftige Umgebung und Parameter haben. Keine Notwendigkeit, Main zu laufen, wenn wir ungültige Flaggen haben, richtig? Und wenn wir kein richtiges Feedback geben können, sollten wir dies früh sagen.
  2. ... ein Fehler passiert, von dem ich weiß, dass es nicht behebbar ist. Nehmen wir an, wir haben ein Programm, das eine Miniaturansicht einer Bilddatei erstellt, die in der Befehlszeile angegeben wird. Wenn diese Datei nicht existiert oder aufgrund unzureichender Berechtigungen nicht lesbar ist, gibt es keinen Grund, fortzufahren, und dieser Fehler kann nicht wiederhergestellt werden. Also halten wir uns an die Konventionen und scheitern.
  3. ... ein Fehler tritt während eines Prozesses auf, der möglicherweise nicht reversibel ist. Das ist eine Art weiche Definition, ich weiß. Lassen Sie mich das illustrieren. Nehmen wir an, wir haben eine Implementierung von cp, und es wurde begonnen, nicht interaktiv zu sein und ein Verzeichnis rekursiv zu kopieren. Nehmen wir nun an, dass wir im Zielverzeichnis eine Datei finden, die denselben Namen (aber unterschiedlichen Inhalt) hat wie eine Datei, die dort kopiert werden soll. Da wir den Benutzer nicht bitten können, zu entscheiden, was zu tun ist und wir diese Datei nicht kopieren können, haben wir ein Problem. Da der Benutzer davon ausgeht, dass die Quellen- und Zielverzeichnisse exakte Kopien sind, wenn wir mit dem Exit-Code Null fertig sind, können wir die betreffende Datei nicht einfach überspringen. Wir können es jedoch nicht einfach überschreiben, da dies möglicherweise Informationen zerstören könnte.Dies ist eine Situation, die wir nicht durch eine explizite Anfrage des Benutzers wiederherstellen können, und so würde ich log.Fatal verwenden, um die Situation zu erklären und dabei dem Prinzip zu folgen, so früh wie möglich zu versagen.
+1

Ich mag deine Antwort, da sie die Punkte gut erklärt (und mit meinen eigenen Ideen zu diesem Thema übereinstimmt), aber ich fürchte, dass es ein entscheidendes Bit vermisst: Das OP hat ausdrücklich gefragt, ob man 'log.Fatal' * in einem Paket * verwenden könnte. - Das heißt, in einem Stück Code, der nicht von jemandem kontrolliert wird, der 'main()' geschrieben hat. Wie Sie sehen können, verschiebt dies die Frage von einer "wohlverhaltenden Prozess" -Domäne zu der "wohlverhaltenden Paket" -Domäne - eine ganz andere Geschichte für die Frage wird: ob es in Ordnung ist, das Programm einer anderen Person irreversibel zu scheitern? – kostix

+1

Es ist abgedeckt, wenn auch ein bisschen implizit: Ich wenden diese Regeln unabhängig davon an, ob ich ein Paket oder ein cmd schreibe: Ein nicht behebbarer Fehler ist ein nicht behebbarer Fehler. Es liegt in der Verantwortung eines Programms, einem Paket eine bereinigte Eingabe zu geben. Wenn dies nicht möglich ist, sollte ein Fehler zurückgegeben werden, jedoch nur, wenn die Eingabe zuvor nicht bereinigt werden kann. So hilft Fataling, wo es angebracht ist, dem Benutzer eines Pakets tatsächlich, besseren Code zu schreiben. –

+1

Die Sache ist, es ist nicht der Anruf des Paketbetreuers, wenn etwas nicht wiederherstellbar ist oder nicht. Sicher, es ist Ihnen nicht gelungen, ein Thumbnail zu erzeugen, aber ich habe es als kleinen Teil meines Webservers benutzt. Wenn ein Thumbnail-Paket os.Exit aufruft, weil es keine Datei laden kann, wäre ich empört. – captncraig

Verwandte Themen