【Go】これが俺なりのnrslog【New Relic APM】
TL;DR
-
nrslogではAPM Agent単体でslog.Attrを転送できない - なので俺なりのnrslogを作りました
nrslogとは
New Relic公式が公開しているgo-agentのサブモジュールで
log/slogでLogs in Context[1]を実現するためのパッケージです
NRHandlerをslog.Loggerのハンドラに設定することで簡単に計装することができます
詳しくはexample参照
なぜslog.Attrが転送されないのか
その理由はNRHandlerの実装にあります
Go Agentを利用したログ転送はあくまでTransaction.RecordLogを通じてNew Relicに送信されるEventの一種で、io.Writerの出力をそのままローテーションしているわけではない
というのが筆者の認識です
上記実装ではログレベル、タイムスタンプ、メッセージのみをTransaction.RecordLogに渡しているため、後続の処理でシリアライズされるslog.Attrもとい...argsは含まれていません
(2024/03/01 追記)
ただしこれは後述するキー項目を確実に含ませる意図があっての実装だと思われます
参考にnewrelic/go-agent/v3/integrations/logcontext-v2/nrzapの実装ですが
nrslog同様に構造化データを含んでいません
上記についてはイシューが挙がっていますが、メンテナーからは前向きな回答がありました
slog.Attrを転送するには
肝心のslog.Attrはslog.commonHandler.handle内で
- マーシャリング
-
slog.Record.Messageとマージ
の後に[]byteとしてio.Writer.Writeに渡されています
Writeメソッド内でTransaction.RecordLogを呼び出すio.Writer実装をslog.commonHandlerに設定するしかなさげです
その他 Logs in Contextを実現する上での留意点
ログデータ(ログイベント)にはキーとなるいくつかの項目を含む必要があります
今回そちらの説明は割愛しますが、参考にしたリンクを貼っておきます
作ったもの
実際に作ったライブラリです
現状用意しているハンドラはTransactionalHandlerの一種のみです
TransactionalHandlerを使用する上ではTransaction単位でslog.Loggerを生成して持ちまわす必要があります
なので、HTTPリクエストごとに
-
slog.Loggerの生成 -
context.Contextへの格納
を行うカスタムミドルウェアを作って貰うのが一番使いやすいかなと思ってます
蛇足な気もしつつ、context.Contextからの出し入れ用の関数だけ用意しました
具体的な使い方はREADMEもしくは、pkg.go.devのExamplesセクションを参照してください
以下が実際にaltnrslogで転送されたログです
実行環境はECS on Fargate

それでは、よきオブザーバビリティを
Discussion