golangアプリでログを収集して一元化する方法
この文章は、How to collect, standardize, and centralize Golang logs | Datadog を読んだ後のまとめです。
ログを使用する際には、いくつか注意すべき点があります:
- ログをパラメーターとして渡す必要があり、必要なときにパラメーターを渡す。
- 一貫して context でラップし、使用する際には context から取り出す。
- 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
}
}
次に、この記事の提案を見てみましょう:
- logrus の使用をお勧めします。logrus は非常に使いやすいロギングライブラリで、ネイティブの
logを完全にサポートしているため、スムーズに移行できます。フック機能を使うことで、Datadog や Sentry などのサードパーティの報告プラットフォームとも簡単に接続できます。 - ログファイルのフォーマットとして JSON を使用すること:JSON は非常に解析しやすく、多くの言語でサポートされており、サードパーティプラットフォームにも適しています。logrus では、直接
SetFormatter(&logrus.JSONFormatter{})で出力形式を設定できます。 - 統一インターフェースを使用する。
- goroutine 内で logger を呼び出さないようにする。並行性の問題を考慮する必要があるだけでなく、logger の内部実装も goroutine を走らせる可能性があるため、全体のメカニズムを把握しにくくなります。
- ログをローカルファイルに保存する。他のプラットフォームを使用している場合でも、ネットワークの問題で記録が失われることがないため、常にログファイルを見つけられることを保証できます。
- クラスタのような構造を使用している場合、
syslogを使用してログを一台のログサーバーに集中させる必要があるかもしれません。 - Docker のようなコンテナサービスを使用している場合、Docker の STDOUT を監視する必要があるかもしれません。
その他
log.Fatal() と log.Panic() の違いについてですが、Fatal は内部でこっそり os.Exit(1) を呼び出します。ドキュメントに記載されていることは知っていますが、多くの人が見ていないかもしれません。一方、Panic は内部で panic を呼び出しますので、使用する際には特に注意が必要です。
関連記事
- 測定が目標になったとき:窓税から Pull Request 数まで 僕はかつて、小さなツールを書いて自分が四半期にどれだけ PR を出し、どれだけ review を残し、どれだけ ticket を解決したかを集計し、数字で上司に成果を示そうとした。上司はただ、評価は成果だけで決まるわけではないと言った。数年後になって僕はようやく理解した——測定が目標になった瞬間、それはもはや良い測定ではなくなるのだと。イギリスの窓税からハノイのネズミ懸賞金、そして今日の PR 数による開発者評価まで、仕組みはまったく同じである。
- 画像のストレージと変換を Cloudflare Images に任せる Web ページに画像を一枚置くのはフロントエンドで一番簡単なことだ。でもそれをちゃんとやる——リサイズし、各フォーマットを生成し、トラフィックにも耐える——となると、実はひとつの解決策まるごとになる。だから僕は結局、原画一枚だけ渡して全部 Cloudflare Images に任せた。
- Access Keyはもう使うな Access KeyはAWSで見落とされがちなセキュリティリスクだ。OIDCとIAM Roleを組み合わせれば、GitHub Actionsはsecretなしで安全にAWSリソースを操作できる
- データベースの主キー: AUTO_INCREMENT、UUID、UUIDv7 バックエンド開発では主キーをどうするかをよく決める必要がある。auto increment か UUID か、衝突はどうするか、UUIDv7 と created_at + index の性能差はどれくらいか。実際に 2000 万件のデータで検証し、設計判断までまとめる。