私はこれまでlog.Fatal
の使用を避けてきましたが、最近偶然にこれらの質問を発見しました。 code-coverage および tests-using-log-fatal 。
100コードカバレッジの質問からのコメントの1つは次のように述べています。
...ほとんどの場合、
log.Fatal
はmain関数またはinit関数でのみ使用する必要があります(または、関数から直接のみ呼び出すことを意図したものもあります) "
考えてみたので、Goに付属の標準ライブラリコードを検討し始めました。ライブラリのtestコードがlog.Fatal
を使用しているように見える多くの例があります。以下に示す net/http
のように、テストコードの外にいくつかの例があります。
// 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)
}
}
...
}
log.Fatal
の使用を避けることがベストプラクティスである場合、なぜ標準ライブラリでまったく使用されないのであれば、エラーが返されることを期待していました。ライブラリのユーザーにos.Exit
が呼び出され、アプリケーションがクリーンアップする機会を提供しないのは不当に思われます。
私は世間知らずかもしれないので、より良い実践としての私の質問はlog.Panic
を呼び出すことです。
では、Goのベストプラクティスは何をログに記録する必要があるかということです。
それは私だけかもしれませんが、_log.Fatal
_の使い方を次に示します。 UNIXの規則に従って、エラーが発生したプロセスは、ゼロ以外の終了コードでできるだけ早く失敗するはずです。これにより、次の場合に_log.Fatal
_を使用するためのガイドラインが表示されます…
func init()
のいずれかでエラーが発生します。逆に言えば、ライブラリーまたはcmdが行うことになっている作業単位に直接影響を与えないことだけを行います。たとえば、ロギングを設定し、正常な環境とパラメータがあるかどうかを確認します。無効なフラグがあればmainを実行する必要はありませんよね?適切なフィードバックを提供できない場合は、早期に通知する必要があります。cp
の実装があり、非インタラクティブでディレクトリを再帰的にコピーすることが開始されたとしましょう。ここで、コピー先のファイルと同じ名前(ただし内容が異なる)のファイルがターゲットディレクトリにあると仮定します。ユーザーに何をするかを決定するように求めることができず、このファイルをコピーできないため、問題があります。終了コード0で終了すると、ユーザーはソースディレクトリとターゲットディレクトリが正確なコピーであると想定するため、問題のファイルを単にスキップすることはできません。ただし、情報を破壊する可能性があるため、単純に上書きすることはできません。これは、ユーザーの明示的な要求ごとに回復できない状況なので、_log.Fatal
_を使用して状況を説明し、できるだけ早く失敗するという原則に従います。マーカス、私はあなたの反応に出くわしました、そして私はそれが素晴らしくて非常に洞察力があると思います、そして私はあなたの内訳に同意する傾向があります。一般化するのは非常に難しいですが、私はこれについてもう少し考えていて、初心者として行っています。理論的なレベルでは、OS、パッケージフレームワーク、ライブラリに関係なく、コンピューティングのベストプラクティスを検討している場合、ロガーの責任は単純にログを記録することです。どのレベルでも、ロガーの責任:
ロギングパッケージまたは任意のパッケージは、プログラムが適切に動作している場合、プログラムをクラッシュさせる権限を持っていません。ミドルウェアやライブラリはスロー/キャッチパターンに従う必要があり、呼び出し側がキャッチするall例外がスローされる機会があります。これは、アプリケーション内で従うのに適したパターンでもあります。アプリケーションのさまざまな部分、および場合によっては他のアプリケーションを強化する基盤とパッケージを構築するときに、アプリケーションが直接クラッシュすることはありません。むしろ、プログラムが処理できるように、致命的な例外をスローする必要があります。これは、マーカスのいくつかの点にも対処していると思います。キャッチされなかった場合、致命的なクラッシュとして発信者にすぐに警告するためです。
ほとんどの場合、log.Fatalを直接使用して、直接ユーザーが直面するCLIツールの目的で楽しむことができます。これは、本当に意図されたシンプルさだと思います。パッケージ全体で致命的なエラーを処理する長期的なアプローチとしては意味がないと思います。