Calendarを書いた時はGo3までだったのに、今年はGo7まであり、Go言語の盛り上がりを感じます。以前書いたGo言語のエラーハンドリングの記事がじわじわと反響をいただいており、とても嬉しく思います。上の記事を書いた当時は趣味でGo言語を嗜んでいた程度ですが、ここ1年は仕事でGoの開発に関わり、エラーハンドリングとロギングの重要性を思い知らされた次第です。自分では適切なエラーハンドリングやロギングをしたつもりでも、いざリリースしてみるとログが不足していて調査に手間取ったり、逆に過剰で精査に時間がかかったり...本記事はここ1年Goで書いたプログラムを運用してみて得た知見を記事に起こしたものです。TL;DRエラーはWrapしつつ適切なメッセージを付与して返すといいよ!カスタムエラー型を作って活用しよう!ログは極力まとめて出した方がいいよ!本文の前にGo1.13から外部パッケージで行なっていたエラー処理が標準パッケージで出来るようになっていますが、本記事ではpkg/errorsを使います。1.13時代のエラー実装者のお作法という記事を投稿された方がおられるので、新しいパッケージでの処理についてはそちらを見ていただけると・・・!本記事では便宜上、標準のlogパッケージを利用していますが、ログレベルを設定できないなど本番運用で利用するには不便なのでcologなどの外部ライブラリを利用したほうがいいです。API(外部パッケージ)のerrorをそのまま返す。API(外部パッケージ)のerrorをそのまま返す。nil}ちょっと色々詰め込みすぎて極端な例ですが、このコードではエラーハンドリングしたエラーをそのまま返却し、五月雨にログ出力をしています。以下のような問題を抱えています。nil}エラーをWrapするpkg/errorsパッケージのWrapとWrapfを使います。定義は以下の通りです。errorerrors.Wrap(f)は第1引数に与えられたerrorを保持しつつ、新しいerrorを返す関数です。ログは以下のように吐かれます。[Wrapしたエラーメッセージ]実際書いてみるとこんな感じになります。エラー3のように若干冗長気味になってしまうので注意が必要です。errors.WrapでWrapしたエラーはerrors.Causeで取り出すことができます。"(*>△<)<ナーンナーンっっ"}}errors.Causeは上記のような定義になっています。errorが実装されていないエラーまで辿ってくれるので、どんなに深い階層で発生したエラーでもWrapし続けている限り取れます。カスタムエラーを活用しよう標準のerrorは文字列しか保持できませんが、エラーコードなどの特別な値をもたせたい場合や、型によってエラーハンドリングの処理を変えたい場合に有用です。カスタムエラーについては、手前味噌ですが別の記事で詳しく解説しているのでそちらをご覧ください。Go言語のエラーハンドリングについて#errorインタフェースを実装した構造体を返却するもちろんカスタムエラーもerrors.Causeで取り出せます。errors.Causeしたあとカスタムエラー型で型キャストしてみて成功したらその型のエラーが返ってきたことになるので、下記の例だとe変数に型キャストされたHogehogeErrorのデータが入ります。ログはここで全て出す!}}}ログを出力する階層は(なるべく)揃える極力、mainに近い方でログ出力をする辿りやすくなる実際は適当なアーキテクチャやフレームワークを採用して開発するでしょうから、それに即したロギングが重要アーキテクチャなら特定の層のみでログ出力をするとかechoではエラーハンドリング関数HTTPErrorHandlerが用意されているのでそこにまとめるとか最後にプログラムは作ったら終わりではなく運用というフェーズが付きまといます。