BASEプロダクトチームブログ

ネットショップ作成サービス「BASE ( https://thebase.in )」、ショッピングアプリ「BASE ( https://thebase.in/sp )」のプロダクトチームによるブログです。

New Relic User Group Vol.0で登壇しました #NRUG

BASE BANKでエンジニアをしている @budougumi0617 です。

先日行われたNew Relic User Group Vol.0でGoでNew Relic APMを活用するためのOSSを紹介するLT発表をさせていただきました。

New Relic User Group Vol.0

New Relic User Group(NRUG)はNew Relicを活用するユーザーの集いです。NRUGはヌルグと読むとのことです。
コロナ禍後初開催となるVol.0は2021年9月15日にオンライン形式で次のコンテンツが行われました。

  • New Relic One 最新機能紹介
  • Nerd Life Talk (LT)
  • ネットワーキング

関連ハッシュタグは#NRUGです。

BASE BANKを含めBASEグループでも2020年9月よりNew Relic Oneを利用した開発・運用体制を敷いており、今回LT発表の機会をいただくことができました。

発表資料

私の当日の発表資料は次のスライドになります。

私の発表では、BASE BANKのGoアプリケーションでNew Relic Oneを活用するために私が開発し、OSSとして公開している3つのツールについて紹介しました。

当日紹介したOSS

スライド中で紹介したOSSは次の3点です。

github.com/budougumi0617/nrseg

nrsegコマンドはGoアプリケーションの関数・メソッドにNew Relic APMでSpanを生成するためのNew Relicライブラリの呼び出しを自動挿入するツールです。

GoアプリケーションへNew Relic APMを導入する際、Goでは実行時間を計測したい関数・メソッド全てで次のようなライブラリの呼び出しをする必要があります。

defer txn.StartSegment("mySegmentName").End()

nrsegコマンドは指定ディレクトリ配下の全てのGoのコードに含まれる関数やメソッド1にスパンを生成するために必要なコードを自動挿入します。

import (
        "context"
        "fmt"
        "net/http"
+
+       "github.com/newrelic/go-agent/v3/newrelic"
 )

 func (f *FooBar) SampleMethod(ctx context.Context) {
+       defer newrelic.FromContext(ctx).StartSegment("foo_bar_sample_method").End()
        fmt.Println("end function")
 }

 func SampleFunc(ctx context.Context) {
+       defer newrelic.FromContext(ctx).StartSegment("sample_func").End()
        fmt.Println("end function")
 }

 func SampleHandler(w http.ResponseWriter, req *http.Request) {
+       defer newrelic.FromContext(req.Context()).StartSegment("sample_handler").End()
        fmt.Fprintf(w, "Hello, %q", req.URL.Path)
 }

// nrseg:ignore ignoreコメントをしておけば無視します。
func IgnoreHandler(w http.ResponseWriter, req *http.Request) {
  fmt.Fprintf(w, "Hello, %q", req.URL.Path)
}

既存アプリケーションの関数やメソッド全てに上記のような呼び出しを手動で挿入するのは手間なのでこちらを利用しております。
内部実装的にはASTから関数名を取得したり関数の位置を読み取って先頭行にコードを挿入したりと楽しい静的解析になっております。

action-newrelic-segment-lint actions

action-newrelic-segment-lint はNew RelicのSpan対応漏れがある関数・メソッドがPull Request(PR)に含まれていたときに警告コメントをするGitHub Actionsです。

既存コードに対してはnrsegコマンドでNew Relicの対応ができます。
しかし、我々のGoアプリケーションは機能追加が活発に行われており、毎日関数やメソッドが追加されています。
新しく追加された関数やメソッドがNew Relicの対応をしていなかった時警告コメントをしてくれます。

f:id:budougumi0617:20210917045336p:plain
PR上でNew Relic対応漏れの関数にコメント

github.com/budougumi0617/nrzap

nrzapはNew RelicのTrace IDSpan IDuber-go/zapのログに埋め込むためのヘルパーです。

New Relicには分散トレースとログを紐付けるLogs in contextという機能があります。

しかし、New Relicの公式Goライブラリはlogrusというロガーパッケージしか現在はLogs in contextに対応していません。
弊社のGoアプリケーションで利用しているロガーパッケージはuber-go/zapです。
Logs in contextに必要なNew RelicのTrace IDSpan IDuber-go/zapのログに埋め込むためのヘルパーがnrzapです。GetNrMetadataFields関数を使うとcontext.ContextオブジェクトにNew Relic関連情報が含まれていればuber-go/zapのログに適切なJSONキーでNew RelicのTrace IDなどの情報を含めることができます。

func ExampleHandler(w http.ResponseWriter, r *http.Request) {
    logger, _ := zap.NewProduction()
    defer logger.Sync()
    // nrgorillaなどでcontextから*newrelic.Transactionが取れる前提
+    nrfs := nrzap.GetNrMetadataFields(r.Context())
    logger.Info("failed to fetch URL", nrfs...)
}

会に参加して

会ではNew Relicのコンサルタントの皆様よりPixieなどのNew Relic Oneの最新機能を紹介していただきました。

また、他社の皆様には開発組織へのNew Relic導入活動のコツを教えていただいたり、本番ダッシュボードを実際に拝見させていただけました。
懇親会では紹介したOSSを実際に利用してくださっている方と話しかけていただき、とてもモチベーションが高まりました。
どのOSSもまだまだバギーなところがあるので時間を見つけて改善を重ねておこうと思います。

終わりに

NRUGの次回開催は12月を予定されているようです。今回とても有意義な時間だったのでぜひまた参加する予定です。
New Relicの最新機能、現場の生の声を聞ける貴重な会なので現在活用中の方、導入を検討されている方とも12月にお会いできればと思います。


  1. 正確には引数にcontext.Context オブジェクトまたは*http.Requestオブジェクトを持つ関数/メソッドです。