🟩

【Go】これが俺なりのnrslog【New Relic APM】

2024/02/27に公開

TL;DR

  • nrslogではAPM Agent単体でslog.Attrを転送できない
  • なので俺なりのnrslogを作りました

nrslogとは

https://github.com/newrelic/go-agent/tree/master/v3/integrations/logcontext-v2/nrslog

New Relic公式が公開しているgo-agentのサブモジュールで
log/slogでLogs in Context[1]を実現するためのパッケージです

NRHandlerslog.Loggerのハンドラに設定することで簡単に計装することができます

詳しくはexample参照

なぜslog.Attrが転送されないのか

その理由はNRHandlerの実装にあります

https://github.com/newrelic/go-agent/blob/487703c7e3df7793cdcf0e2ad7a5f25a6ed90ece/v3/integrations/logcontext-v2/nrslog/handler.go#L129-L142

Go Agentを利用したログ転送はあくまでTransaction.RecordLogを通じてNew Relicに送信されるEventの一種で、io.Writerの出力をそのままローテーションしているわけではない
というのが筆者の認識です

上記実装ではログレベル、タイムスタンプ、メッセージのみをTransaction.RecordLogに渡しているため、後続の処理でシリアライズされるslog.Attrもとい...argsは含まれていません

(2024/03/01 追記)
ただしこれは後述するキー項目を確実に含ませる意図があっての実装だと思われます
https://docs.newrelic.com/jp/docs/logs/ui-data/long-logs-blobs/#data-retention

参考にnewrelic/go-agent/v3/integrations/logcontext-v2/nrzapの実装ですが
nrslog同様に構造化データを含んでいません

https://github.com/newrelic/go-agent/blob/487703c7e3df7793cdcf0e2ad7a5f25a6ed90ece/v3/integrations/logcontext-v2/nrzap/nrzap.go#L118-L122

https://github.com/newrelic/go-agent/blob/487703c7e3df7793cdcf0e2ad7a5f25a6ed90ece/v3/integrations/logcontext-v2/nrzap/nrzap.go#L27-L40

上記についてはイシューが挙がっていますが、メンテナーからは前向きな回答がありました
https://github.com/newrelic/go-agent/issues/768

slog.Attrを転送するには

肝心のslog.Attrslog.commonHandler.handle内で

  1. マーシャリング
  2. slog.Record.Messageとマージ

の後に[]byteとしてio.Writer.Writeに渡されています

Writeメソッド内でTransaction.RecordLogを呼び出すio.Writer実装をslog.commonHandlerに設定するしかなさげです

https://github.com/golang/go/blob/2b72395eadcc46120b27b9689bed84338de5141c/src/log/slog/handler.go#L265-L315

その他 Logs in Contextを実現する上での留意点

ログデータ(ログイベント)にはキーとなるいくつかの項目を含む必要があります
今回そちらの説明は割愛しますが、参考にしたリンクを貼っておきます

https://developers.prtimes.jp/2023/09/07/newrelic_extension/#index_id14

https://budougumi0617.github.io/2021/03/21/release_nrzap_for_newrelic_logs_in_context/

作ったもの

実際に作ったライブラリです
現状用意しているハンドラはTransactionalHandlerの一種のみです

https://github.com/miyamo2/altnrslog

TransactionalHandlerを使用する上ではTransaction単位でslog.Loggerを生成して持ちまわす必要があります

なので、HTTPリクエストごとに

  1. slog.Loggerの生成
  2. context.Contextへの格納

を行うカスタムミドルウェアを作って貰うのが一番使いやすいかなと思ってます

蛇足な気もしつつ、context.Contextからの出し入れ用の関数だけ用意しました

https://github.com/miyamo2/altnrslog/blob/44754f8877ecf55853bbd7f9f936ecbaf3e149a1/context.go#L18-L40

具体的な使い方はREADMEもしくは、pkg.go.devのExamplesセクションを参照してください
https://pkg.go.dev/github.com/miyamo2/altnrslog#example-package

以下が実際にaltnrslogで転送されたログです

実行環境はECS on Fargate

実行イメージ

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

脚注
  1. Introduction to logs in context ↩︎

Discussion

Hidden comment