golangアプリでログを収集して一元化する方法

作成者:カランカラン
💡

質問やフィードバックがありましたら、フォームからお願いします

目次

  1. その他

本文は台湾華語で、ChatGPT で翻訳している記事なので、不確かな部分や間違いがあるかもしれません。ご了承ください

この文章は、How to collect, standardize, and centralize Golang logs | Datadog を読んだ後のまとめです。

ログを使用する際には、いくつか注意すべき点があります:

  1. ログをパラメーターとして渡す必要があり、必要なときにパラメーターを渡す。
  2. 一貫して context でラップし、使用する際には context から取り出す。
  3. logger をパッケージとしてラップし、他のパッケージが使用できる変数を公開する。

明らかに、最初の方法はすぐに問題に直面します。つまり、パラメーターが非常に奇妙な形になることです。例えば:

func (p *Post) CreatePost(name string, content string, logger *log.Logger) {
  ///
  if err != nil {
    logger.Fatal("error!")
  }
}

CreatePost のロジックで logger を渡さなければならないのは非常に煩雑で、パラメーターが汚れてしまう可能性があります。また、logger を層層に渡すことになるかもしれません。この方法の最大の利点は、依存関係が透明であり、関数を通じて logger が使用されることが明確にわかることです。テストも容易に logger をモックできます。

次の方法として、main で明示的に context を渡し、その中に logger を入れることができます。必要なときは log.Logger.FromContext(ctx) を使用します。特に明らかな欠点は思いつきません。

const (
  ContextKeyLogger = "logger"
)
func main() {

  ctx := context.Background()
  loggerCtx := context.WithValue(ctx, ContextKeyLogger, log.Logger)
  
}

現在私が実践している第三の方法は、logger をパッケージとしてラップし、他のパッケージが使用できる変数を公開することです。この方法の最大の利点は便利さで、すぐに使用できる点です。ただし、テストする際に少し難しくなります。なぜなら、パラメータ化されていないため、logger をモックすることが難しいからです。(他に良い解決策があるかもしれませんが)

package logging

var Logger *log.Logger

func init() {
  Logger = &log.Logger{
    // your setting
  }
}

次に、この記事の提案を見てみましょう:

  1. logrus の使用をお勧めします。logrus は非常に使いやすいロギングライブラリで、ネイティブの log を完全にサポートしているため、スムーズに移行できます。フック機能を使うことで、Datadog や Sentry などのサードパーティの報告プラットフォームとも簡単に接続できます。
  2. ログファイルのフォーマットとして JSON を使用すること:JSON は非常に解析しやすく、多くの言語でサポートされており、サードパーティプラットフォームにも適しています。logrus では、直接 SetFormatter(&logrus.JSONFormatter{}) で出力形式を設定できます。
  3. 統一インターフェースを使用する。
  4. goroutine 内で logger を呼び出さないようにする。並行性の問題を考慮する必要があるだけでなく、logger の内部実装も goroutine を走らせる可能性があるため、全体のメカニズムを把握しにくくなります。
  5. ログをローカルファイルに保存する。他のプラットフォームを使用している場合でも、ネットワークの問題で記録が失われることがないため、常にログファイルを見つけられることを保証できます。
  6. クラスタのような構造を使用している場合、syslog を使用してログを一台のログサーバーに集中させる必要があるかもしれません。
  7. Docker のようなコンテナサービスを使用している場合、Docker の STDOUT を監視する必要があるかもしれません。

その他

log.Fatal()log.Panic() の違いについてですが、Fatal は内部でこっそり os.Exit(1) を呼び出します。ドキュメントに記載されていることは知っていますが、多くの人が見ていないかもしれません。一方、Panic は内部で panic を呼び出しますので、使用する際には特に注意が必要です。

この記事が役に立ったと思ったら、下のリンクからコーヒーを奢ってくれると嬉しいです ☕ 私の普通の一日が輝かしいものになります ✨

Buy me a coffee

目次

  1. その他