WebpackerでRailsアプリケーションでエラー管理にRollbarを使用しているときに、デフォルトだとエラーが発生してもminify等がされたjsにリンクされてしまい何が起きているのか、よくわかりません。。。
そんなときにSourceMapをRollbarにアップロードするとエラー発生箇所が特定しやすくなるので、そのへんのやり方をメモしておきます📝
ちなみに今回の環境は以下です。
- rails: 6.0.3.4
- webpacker: 5.2.1
また前提として以下のドキュメントの通りBrowserJsのRollbarの設定は完了しているものとします。
SourceMapとは
ソースマップ は変換後のソースと元のソースを関連付けるファイルであり、ブラウザーが元のソースを再構成して、そのソースをデバッガーに提供できます。
Webpackを利用したminified等、jsのソースコードは実際に実行されるときには元のソースコードから変換されていることが多いので、元のソースコードを生成するための情報をブラウザに提供するものといった感じと理解しました👀
SourceMapをアップロードする
SourceMapをアップロードするにはRollbarの特定のEndpointにminifiedしているjsのファイルごとにリクエストを投げる必要があります。
単一のjsにまとめているような運用なら以下のようなCI系の機能を使えば簡単に出来そうなのですが、Webpackerのデフォルトのようにエンドポイントごとにentryを分けるような設定の場合には、entryごとにリクエストを投げる必要があるので、結構たいへんです😓
そんなときに役に立つのがrollbar-sourcemap-webpack-plugin
です📦
this.getAssets(compilation)
でソースファイルとSourceMapを集めて、それぞれRollbarにUploadしてくれます📮
// [https://github.com/thredup/rollbar-sourcemap-webpack-plugin/blob/master/src/RollbarSourceMapPlugin.js#L131-L141] uploadSourceMaps(compilation) { const assets = this.getAssets(compilation); /* istanbul ignore next */ if (assets.length > 0) { process.stdout.write('\n'); } return Promise.all( assets.map(asset => this.uploadSourceMap(compilation, asset)) ); }
rollbar-sourcemap-webpack-plugin
は以下のような形でinstallします。
$ yarn add rollbar-sourcemap-webpack-plugin
私は、以下ような感じにconfig/webpack/production.js
を修正しました。
各設定値の詳細はREADMEを参照してください📝
process.env.NODE_ENV = process.env.NODE_ENV || "production"; const RollbarSourceMapPlugin = require("rollbar-sourcemap-webpack-plugin"); // NOTE: `post_server_item`以上のscopeを持つtokenでないと権限エラーになる。 const token = process.env.ROLLBAR_POST_SERVER_ITEM_ACCESS_TOKEN; // NOTE: 最新のcommit hashを設定 const codeVersion = process.env.SOURCE_VERSION; // NOTE: minifiedされたソースコードの配置先 const publicPath = process.env.PUBLIC_PATH + "/packs"; const RollbarSourceMapPluginConfig = require("./plugins/rollbarSourceMapConfig"); const environment = require("./environment"); RollbarSourceMapPluginConfig = new RollbarSourceMapPlugin({ accessToken: token, version: codeVersion, publicPath: publicPath, ignoreErrors: true, // NOTE: uploadに失敗してもdeployが失敗しないようにエラーを無視 }); // NOTE: SourceMapが無効になっているとupload時に以下のエラーが発生するっぽいので`hidden-source-map`を設定 // Rollbar: Error: Source map missing property 'names' environment.config.merge({ devtool: "hidden-source-map", }); environment.plugins.prepend("RollbarSourceMapPlugin", RollbarSourceMapPluginConfig);
process.env.SOURCE_VERSION
にはdeploy時の最新のcommit hashを SourceMapをuploadするwebpackのbuild前に設定しておく必要があります。
CI系のサービスを利用してdeployしている場合には、すでに環境変数に入っているものもあるようです👀
CircleCI
CIRCLE_SHA1 The SHA1 hash of the last commit of the current build. https://circleci.com/docs/2.0/env-vars/#built-in-environment-variables
GITHUB_SHA The commit SHA that triggered the workflow. For example, ffac537e6cbbf934b08745a378932722df287a53. https://docs.github.com/en/free-pro-team@latest/actions/reference/environment-variables#default-environment-variables
Heroku
SOURCE_VERSION For git-push builds, this is the git commit SHA-1 of the source being built. https://devcenter.heroku.com/changelog-items/630
これで本番のWebpackのビルド時にSourceMapが送信されるようになりました🎉
RollbarにアップロードしたSourMapは、Project > Settings > Source Maps
で見ることが出来ます。
UploadしたSourMapを利用するように既存のRollbarの設定を修正
SourceMapがアップロードされるようになったら、次はError通知時にSourceMapが利用されるように設定を変更していきます⚙
変更した設定が以下の通りです、client
部分が追加した設定になります。
詳細は以下のURLから公式ドキュメントを確認してください📝
https://docs.rollbar.com/docs/source-maps#2-configure-the-rollbarjs-sdk-to-support-source-maps
Rollbarはpayload.client.code_version
の値とアップロードされたSourceMapのversion
で紐付けているようです🤝
const token = process.env.ROLLBAR_POST_CLIENT_ITEM_ACCESS_TOKEN; const railsEnv = process.env.RAILS_ENV; const codeVersion = process.env.SOURCE_VERSION; const rollbarParamsValidation = () => !(railsEnv === "test") && token; if (rollbarParamsValidation()) { let _rollbarConfig = { accessToken: token, captureUncaught: true, captureUnhandledRejections: true, payload: { environment: railsEnv, client: { javascript: { source_map_enabled: true, code_version: codeVersion, guess_uncaught_frames: true, }, }, }, }; // Rollbar Snippet // ... // End Rollbar Snippet
これで以下のような感じでSourceMapを活用して、minified前の実際にエラーの発生したfileの行数で見ることが出来るようになりました🙌