Madogiwa Blog

主に技術系の学習メモに使っていきます。

RubyonRails: WebpackerなRailsアプリケーションでSourceMapをRollbarにアップロードするMEMO

WebpackerでRailsアプリケーションでエラー管理にRollbarを使用しているときに、デフォルトだとエラーが発生してもminify等がされたjsにリンクされてしまい何が起きているのか、よくわかりません。。。

そんなときにSourceMapをRollbarにアップロードするとエラー発生箇所が特定しやすくなるので、そのへんのやり方をメモしておきます📝

ちなみに今回の環境は以下です。

  • rails: 6.0.3.4
  • webpacker: 5.2.1

また前提として以下のドキュメントの通りBrowserJsのRollbarの設定は完了しているものとします。

docs.rollbar.com

SourceMapとは

ソースマップ は変換後のソースと元のソースを関連付けるファイルであり、ブラウザーが元のソースを再構成して、そのソースをデバッガーに提供できます。

ソースマップを使用する - 開発ツール | MDN

Webpackを利用したminified等、jsのソースコードは実際に実行されるときには元のソースコードから変換されていることが多いので、元のソースコードを生成するための情報をブラウザに提供するものといった感じと理解しました👀

SourceMapをアップロードする

SourceMapをアップロードするにはRollbarの特定のEndpointにminifiedしているjsのファイルごとにリクエストを投げる必要があります。

docs.rollbar.com

単一のjsにまとめているような運用なら以下のようなCI系の機能を使えば簡単に出来そうなのですが、Webpackerのデフォルトのようにエンドポイントごとにentryを分けるような設定の場合には、entryごとにリクエストを投げる必要があるので、結構たいへんです😓

github.com

circleci.com

そんなときに役に立つのがrollbar-sourcemap-webpack-pluginです📦

github.com

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

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の行数で見ることが出来るようになりました🙌

f:id:madogiwa0124:20201129180228p:plain

参考

engineer.crowdworks.jp

qiita.com