2015-11-24 7 views
8

私は今までlog.Fatalの使用を避けましたが、最近私はこれらの質問を共同で発見しました。 code-coverageおよびtests-using-log-fatalGoパッケージでlog.Fatalを使用する必要がありますか?

100コード・カバレッジ・質問のコメントの一つは言う:例log.Fatalの大半で

は...メイン、またはinit関数(または多分に意図いくつかのものだけを使用するべきです

それは私が考えて行く「)、そこからのみ直接呼び出すことが、私は行くが提供する標準ライブラリのコードを見て始めました。多くの例では、ライブラリ内のテストコードはを使用するところがあります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と呼ぶように思えます。理論的に長時間安定したアプリケーションが灰から浮かび上がる可能性があります。

だから、ログの告知はいつ行うべきですか?

+3

私の希望は、このコードは絶対に到達できないことです。アイドル状態の接続をアクティブな接続として使用している間にアイドル状態の接続を引き続き引き起こすエラーは、これまでに起こるべきものであってはならず、発生するためには何か壊滅的なものでなければならない。しかし、アイドルリストの周りにmutexを適切に使用しているように見えるので、なぜこのループとコードが必要なのかはわかりません。彼らがなぜあなたのプログラムをすぐに終了するのではなく、別の謎です。素晴らしい質問。 – captncraig

+0

そのパッケージ内のテストはその行に到達できますか? – captncraig

+0

良い質問ですが、少し見て、その行に到達するように特別に設計されたようなものは見えません。まだ確定していません... – miltonb

答えて

8

私だけかもしれませんが、ここではどのように私はlog.Fatalを使用しています。 UNIXの規則に従って、エラーに遭遇するプロセスは、ゼロでない終了コードで可能な限り早く失敗するはずです。これはそれぞれ、輸入が処理されるとき、またはメインFUNCが呼び出される前に、これらのことが起こるようなエラーが、私のfunc init()のいずれかで起こる... ...ときlog.Fatalを使用するには、次のガイドラインに私を導く

  1. 。逆に、私はライブラリやcmdが行うと思われる作業単位に直接影響しないものだけを行います。たとえば、私はロギングを設定し、正常な環境とパラメータを持っているかどうかを確認します。無効なフラグがある場合はメインを実行する必要はありません。また、適切なフィードバックが得られない場合は、早急に伝えてください。
  2. ...私が知っているうちに起こったエラーは、取り返しのつかないものです。コマンドラインで与えられたイメージファイルのサムネイルを作成するプログラムがあるとしましょう。このファイルが存在しないか、アクセス許可が不十分で読み込めない場合は、続行する必要はなく、このエラーは回復できません。だから私たちは規則に従い、失敗します。
  3. ...リバーシブルでないプロセスでエラーが発生しました。これはソフトな定義のようなものです。私はそれを説明しましょう。 cpという実装があり、非対話型であり、再帰的にディレクトリをコピーし始めたとしましょう。ここで、コピー先のファイルと同じ名前(ただし内容は異なる)のファイルがターゲットディレクトリにあるとします。ユーザーに何をすべきかを決めることはできないので、このファイルをコピーすることはできません。問題があります。ユーザーは、終了コード0で終了したときにソースとターゲットのディレクトリが完全にコピーされていると想定するので、問題のファイルを単にスキップすることはできません。ただし、情報を破壊する可能性があるため、単純に上書きすることはできません。これは、ユーザーからの明示的な要求ごとに回復できない状況であるため、できるだけ早く失敗するという原則に従うことで、状況を説明するのにlog.Fatalを使用します。
+1

私はあなたの答えがうまく説明されているように(この話題について私自身のアイデアと共鳴しています)、私は重大な欠点を抱いています:OPは明示的にパッケージ内で 'log.Fatal' *つまり、 'main()'を書いた人が管理していないコードの部分です。あなたが見るように、これは実際に "よく振る舞う"プロセスドメインから "うまく振る舞うパッケージ"ドメインに質問を移します。疑問の全く別の話になります:誰かのプログラムに逆らって失敗するのは大丈夫ですか? – kostix

+1

これは暗黙のうちに書かれていますが、私はパッケージやcmdを書いているにもかかわらず、それらのルールを適用します。回復不可能なエラーは回復不可能なエラーです。パッケージの墨塗りされた入力を与えるのはプログラムの責任です。それが不可能な場合は、入力を事前にサニタイズできない場合のみ、エラーを返す必要があります。実際には適切な場合には実際にはパッケージのユーザーがより良いコードを書くのに役立ちます。 –

+1

何かが回復不能であるかどうかは、パッケージ管理者の呼び出しではありません。確かに、あなたはサムネイルの生成に失敗しましたが、私はそれを私のWebサーバーの小さな部分として使っていました。サムネイルパッケージがファイルをロードできないためにos.Exitを呼び出すと、私は気になるでしょう。 – captncraig

関連する問題