NewRelic ブラウザモニタリングのソースマップで色々ハマった話

こんにちは。エンジニアの中畑(@yn2011)です。千葉県は最高です。

今回はNewRelic ブラウザモニタリングを使用して JavaScript のエラー収集を行おうとした際に、NewRelic のソースマップアップロード機能の仕様で色々とハマってしまったというお話をします。

ソースマップアップロード API について

NewRelic ブラウザモニタリングでは、ソースマップというファイルを利用して発生した JavaScript エラーのスタックトレースを取得することができます。

ソースマップは、以下のような内容のファイルです。

{
    "version": 3,
    "file": "static/chunks/254-be419541614271942b8c.js",
    "mappings": "gFAAoEA,...
}

NewRelic ブラウザモニタリングにはソースマップのバージョン管理機能があり、ソースマップにユニークな識別子をアップロード時に付与することができます。提供されているソースマップのアップロード API を利用してアップロード時に識別子の付与ができます。

publishSourcemap({
  sourcemapPath: './dist/bundle.js.map', 
  javascriptUrl: 'https://example.com/assets/bundle.js',
  ...
  releaseName: 'OPTIONAL RELEASE NAME', // 追加
  releaseId: 'OPTIONAL RELEASE ID', // 追加
}, function (err) { console.log(err || 'Source map upload done')})

releaseNamereleaseId を指定できることに違和感を持った方もいるかもしれません。これは次項の伏線です。

ハマリポイント

releaseId と releaseName は両方必須

早速伏線を回収します。NewRelic ブラウザモニタリングでバージョン管理を行う場合は、releaseNamereleaseId の両方が必須になります。

ドキュメントに記載はないように認識していますが、 @newrelic/publish-sourcemap の実装を確認すると、しっかり条件式に含まれていました。

if (releaseName && releaseId) {
  console.log('Using release name:', releaseName, 'and release id:', releaseId)
  request = request.field('releaseName', releaseName)
  request = request.field('releaseId', releaseId)
}

コミットハッシュを活用する場合など、どちらか 1 つの項目を利用できれば十分なことが多いと思います。なぜこのような仕様になっているのかは分かりませんでした。

コンフリクトエラー

ソースマップのバージョン管理を行わない場合は、releaseNamereleaseId を指定する必要はありません。しかし、1 度これらの項目を空でアップロードしてしまうと、次にアップロードする際に releaseIdreleaseName を指定してアップロードしてもコンフリクトエラーというレスポンスが返り、アップロードが失敗します。

コンフリクトエラーは、NewRelic に同一のソースマップをアップロードした場合に発生する仕様となっています。releaseNamereleaseId が異なる場合は別のソースマップとして解釈されるためアップロードが可能です。

バージョン管理を行う場合は、1度、releaseNamereleaseId が空のソースマップを削除し、再度アップロードする必要があります。

ブラウザ側で addRelease を呼び出す必要がある

ソースマップのバージョン管理を行う場合、ブラウザ側で browser agent API から次のメソッドを呼び出す必要があります。

newrelic.addRelease(string $release_name, string $release_id)

このメソッドを呼び出さないと、発生した JavaScript エラーを正しいバージョンのソースマップにマッピングすることができません。メソッドを呼び出さずに JavaScript エラーを発生させた場合、NewRelic の画面上では releaseNamereleaseId は空になります。

addRelease の呼び出しの実装としては、スニペットの末尾への追加が可能です。 NewRelic ブラウザモニタリングを利用する場合は、New Relic から提供されるスニペットをブラウザで実行する必要があります。このスニペットの実行後に、browser agent API が利用可能になるため、以下のように末尾に呼び出しを追加します。

// 省略...
applicationID:"${config.applicationID}",sa:1};
newrelic.addRelease("foo", "bar"); // 追加

addRelease の呼び出しは、類似サービスである Sentry では不要であったため、検証時に気づかずハマってしまいました。

まとめ

NewRelic ブラウザモニタリングのソースマップに関するハマりポイントを 3 つ書きました。

最終的に、プロダクトではソースマップバージョン管理機能の導入は見送りましたが、今後必要に応じて対応を検討する予定です。

最後までお読み頂きありがとうございました。