🎄

Datadog RUM × ソースマップで、フロントエンドのエラー調査を快適にする

に公開

はじめに

こんにちは、株式会社アトラエ の Wevox SRE チームでエンジニアをしている平田です。
この記事は、Datadog Advent Calendar 2025 の25日目の記事です。

https://qiita.com/advent-calendar/2025/datadog

フロントエンドのエラーが minify(圧縮・難読化) されて読みづらいという課題を、Datadog へソースマップをアップロードすることで解決した話を紹介します。

この記事の対象者

  • Datadog RUM の導入を検討されている方
  • フロントエンドのエラートレースが難読化されていて困っている方

起きていたこと

Datadog RUM で、ユーザーセッションをリアルタイムで監視しているものの、収集されるエラーが minify されていて読めない状態でした。

Datadog RUM とは

Real User Monitoring の略で、アプリケーションをリアルタイムで監視し、フロントエンドを中心としたデータを収集するサービスです。

http://datadoghq.com/ja/product/real-user-monitoring/

  • RUM SDK: ブラウザ上で実行され、イベントを収集して Intake API に送信する
  • Datadog intake API: データを受信して Datadog 内に保持する

なぜ読めないのか

ビルド時に、ファイルサイズ削減やパフォーマンス最適化のために minify が行われると、変数名や関数名が a, t, n のような短い文字に置換されます。
RUM はブラウザで実行されたコードをそのまま収集するため、エラートレースが minify 後のコードベースになってしまいます。

// Before: 元のコード
class UserService {
  addUser(name, email) { ... }
}

// After: minify後
class UserService{users=[];addUser(e,r){const s={id:this.generateId()...

実際のエラートレース

どこでエラーが発生しているのかわからない...
どのファイルの何行目で落ちている?どのコンポーネント?

本来ならば、ビルド前のソースコードでエラーを確認したいところです。


minify されていて、ファイル名や行番号からはエラー箇所が特定できない状態

これまでは、気合いでバグ調査をしていたというのが正直なところです。

やったこと

datadog-ci を使って、CI/CD パイプライン上で Datadog にソースマップをアップロードしました。
これにより、エラー発生時に Datadog 上のソースマップを用いて、エラートレースが自動的に元のコードへ復元(un-minify) して表示されるようになります。

ざっくり手順:

  1. ビルド時に、ソースマップを生成する設定を追加する
  2. CI で、Datadog にソースマップをアップロードする
  3. アップロード後に、アーティファクトからソースマップを削除(本番公開しないため)

https://docs.datadoghq.com/real_user_monitoring/guide/upload-javascript-source-maps/?tab=webpackjs

ソースマップとは

minify されたコードの「この位置」が、元のソースコードの「どのファイルの何行目」なのかを対応付けるためのファイルのことです。

hidden-source-map の設定

ソースマップを生成しつつ、ブラウザの開発者ツールなどからは参照されないようにするため、 hidden-source-map を使用します。
これにより、生成された JS ファイル末尾の //# sourceMappingURL=... コメントが削除または付与されなくなり、ブラウザによるソースマップの自動ロードを防ぐことができます。

// webpack.config.js
module.exports = {
  devtool: 'hidden-source-map',
};
// vite.config.ts
export default defineConfig({
  build: {
    sourcemap: 'hidden',
  },
});

なぜソースマップを削除するのか

ソースマップには元のソースコードの情報が含まれています。
S3やCDNに公開してしまうと、第三者がソースコードを容易に復元できてしまい、セキュリティリスクになります。
そのため、Datadog にのみアップロードし、本番環境(S3等) には配置しないようにします。

datadog-ci によるアップロード

Datadog が提供している CI/CD パイプライン用の公式 CLI ツールです。

https://github.com/DataDog/datadog-ci/tree/master/packages/datadog-ci/src/commands/sourcemaps

Datadog は以下の3つの情報でソースマップとエラーを照合します。

  • service: アプリケーション名
  • version: リリースバージョン(commit SHA など)
  • minified-path-prefix: 本番環境でのJSファイルのURL

これらが一致しないと、ソースマップがアップロードされていてもエラーの復元ができません。

エラーが読めるようになった

導入後、Datadog のエラートレースで、元のファイル名と行番号が確認できるようになりました。

  • エラー発生箇所のファイル名と行番号が確認できる
  • 難読化された JS ではなく、元の TypeScript コードでエラー箇所を特定できる


ソースマップが適用され、元の TypeScript コードと正確な行番号が表示されている状態

学び

私たちは、複数の Web アプリケーションをモノレポで管理し、GitHub Actions でデプロイする構成を採用しています。
この章では、組織力向上プラットフォーム「Wevox(ウィボックス)」 における導入事例と、運用して得た知見を紹介します。

CLI vs プラグイン

ソースマップのアップロードには、Webpack や Vite の Datadog プラグインを使う方法もあります。
今回は、ビルドとアップロードの責務(ロジック) を分離できる CLI 方式を採用しました。

比較:

CLI(datadog-ci) プラグイン(webpack/vite)
タイミング ビルド後に別ステップで実行 ビルドプロセス内で自動実行
設定場所 CI/CD パイプライン ビルド設定ファイル(vite.config.ts等)
メリット ビルド設定を汚さない。失敗時のリトライ制御がCI側で容易。 設定が一箇所で完結する。

CI アクションの共通化

モノレポ運用のため、ソースマップアップロード処理を GitHub Actions の Composite Action として共通化しました。

理由:

  • 各アプリのワークフローでは共通アクションを呼び出すだけで済む
  • アップロードロジックの変更が1箇所で完結する
  • 新しいアプリへの展開が容易になる
# .github/actions/upload-datadog-sourcemaps/action.yml
name: Upload sourcemaps to Datadog
inputs:
  service-name:
    description: "Datadog service name"
    required: true
  release-version:
    description: "Release version"
    required: true
  minified-path-prefix:
    description: "URL prefix for minified files"
    required: true
  dist-path:
    description: "Path to dist directory"
    required: true
  datadog-api-key:
    description: "Datadog API Key"
    required: true

runs:
  using: "composite"
  steps:
    - name: Upload sourcemaps to Datadog
      env:
        DATADOG_API_KEY: ${{ inputs.datadog-api-key }}
        # 必要に応じて DATADOG_SITE を設定
      run: |
        npx @datadog/datadog-ci sourcemaps upload \
          --service=${{ inputs.service-name }} \
          --release-version=${{ inputs.release-version }} \
          --minified-path-prefix=${{ inputs.minified-path-prefix }} \
          ${{ inputs.dist-path }}
      shell: bash

段階的な展開

モノレポ内のすべてのアプリに一度に導入するのではなく、まず1つのアプリで導入・検証し、問題がないことを確認してから他のアプリへ展開しました。

理由:

  • 設定ミスがあった場合の影響範囲を限定できる
  • 各アプリ固有の事情(ビルド設定の違いなど) に気づきやすい
  • 成功事例をもとに他アプリへ展開しやすい

RUM の初期化を環境変数で制御

RUM SDK の初期化を、環境変数で ON/OFF できる設計にしておくと運用が楽になります。

理由:

  • 環境変数にしておくことで、コードを変更せずに RUM の ON/OFF を切り替えられる
  • 以下のようなケースで、環境変数の値を変えるだけで対応できる
    • 開発環境で一時的に ON にしてソースマップの動作を確認したい
    • 検証完了後の OFF への切り戻し
    • 特定環境における有効/無効化
// 環境変数で RUM の有効/無効を制御
const applicationId = process.env.NEXT_PUBLIC_DD_APPLICATION_ID;
const clientToken = process.env.NEXT_PUBLIC_DD_CLIENT_TOKEN;

// IDとTokenがある場合のみ初期化する
if (applicationId && clientToken) {
  datadogRum.init({
    applicationId,
    clientToken,
    service: 'wevox-web',
    version: process.env.NEXT_PUBLIC_RELEASE_VERSION,
    env: process.env.NEXT_PUBLIC_ENV,
    // ...
  });
}

おわりに

ソースマップを Datadog にアップロードすることで、minify されたエラートレースを元のコードで確認できるようになりました。
フロントエンドのエラー調査の効率が格段に向上しますので、ぜひ導入を検討してみてください!

最後までお読みいただき、ありがとうございました。
それでは、素敵なクリスマスと年末年始を🎄🐕

Atrae Tech

Discussion