🔭

フロントエンドに広がりつつある OpenTelemetry:Browser SDK の現在地

に公開3
50
17

OpenTelemetry と聞くと、サーバーサイドのトレースやメトリクスを集めるためのもの、という印象を持っている人は多いと思います。実際、バックエンドでは OpenTelemetry を使った計装をよく見かけるようになりました。

一方で、フロントエンドの監視は Sentry や Datadog のような SaaS の SDK に任せることが多く、OpenTelemetry をブラウザの計装に利用する場面はまだ少ないです。ただ、最近は OpenTelemetry のブラウザ向け SDK の開発が進んでおり、この状況も少しずつ変わりはじめています。

この記事では、OpenTelemetry Browser の開発状況と、実用に向けて残っている課題について調べたことをまとめます。

この記事の3行まとめ

  • OpenTelemetry では、ブラウザ向けの SDK の開発が進んでいる
  • ユーザー操作や Core Web Vitals など、ブラウザ固有のテレメトリを収集する仕組みが実装されはじめている
  • エラーの symbolication や Session Replay など、SaaS の RUM SDK を置き換えるには課題も残っている

OpenTelemetry が解決する課題

OpenTelemetry は、トレース・メトリクス・ログといったテレメトリを扱うための共通仕様です。

監視ツールはベンダーごとに SDK やデータ形式が異なるので、そのまま使うとアプリケーションの実装が特定のサービスに依存しやすくなります。OpenTelemetry は、計装の API とデータ形式を標準化することで、この依存を減らすことを目指しています。

マイクロサービスアーキテクチャの普及などによって重要性は増しており、2026 年 5 月には CNCF の Graduated Project に認定されました。

https://opentelemetry.io/ja/blog/2026/otel-graduates/

Graduated Project には Kubernetes や Prometheus、Fluentd といったプロジェクトが名を連ねており、OpenTelemetry もクラウドネイティブの領域では欠かせない存在になっています。

フロントエンドの監視でよく使われる SaaS の SDK

フロントエンドの監視は、現状だと Sentry や Datadog などの SaaS が提供する SDK を利用するのをよく見かけます。これらの SDK には、フロントエンドの監視で欲しくなる機能がひととおり揃っています。

  • ブラウザで起きる JavaScript のエラーの収集
  • Core Web Vitals やページ表示速度の計測
  • ユーザー操作からバックエンドの処理までをつなぐ分散トレーシング
  • Session Replay によるユーザー操作の記録と再現

Session Replay の動きについては、Sentry の紹介動画を見るとイメージしやすいと思います。

https://youtu.be/-yqZcPm9aIE?si=TwxHgWlDzjMCFOAP

一方で、OpenTelemetry では、これらの機能がすべて安定版として提供されているわけではありません。ブラウザ向けのトレーシング SDK である @opentelemetry/sdk-trace-web は安定版ですが、その他のパッケージについてはまだ experimental の段階です。

https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-sdk-trace-web

そのため、SaaS の RUM (Real User Monitoring) SDK と同じ感覚で導入すれば、一通りの監視機能が揃うという段階には至っていないのが現状です。

クライアント向けの議論は前からあった

OpenTelemetry では、以前からブラウザを含むクライアント向けの計装について議論されていました。

Client SDK and Instrumentation SIG (Special Interest Group) では、ブラウザやモバイルを含むクライアント向けの SDK と計装が議論されてきました。議事録を見る限り、そのやり取りは 2021 年ごろから続いています。

https://docs.google.com/document/d/16Vsdh-DM72AfMg_FIt9yT9ExEWF4A_vRbQ3jRNBe09w/edit?tab=t.0#heading=h.n5vcc992gs6y

一方で、この SIG が対象とするクライアントはブラウザだけではありません。Android や iOS も含まれており、それぞれ実行環境やライフサイクル、取得できる情報が異なります。これらを共通の設計に落とし込むには多くの論点を整理する必要があり、ブラウザ固有の SDK や計装パッケージの開発は進みづらい状況が続いていました。

Browser SDK として独立して動き始めた

状況が変わったのは、2025 年後半にブラウザ向け SDK を独立して開発する流れが生まれたことです。開発は open-telemetry/opentelemetry-browser というリポジトリで進んでいます。

https://github.com/open-telemetry/opentelemetry-browser

対象をブラウザに絞ったことで、ブラウザ固有の意思決定を素早く進められるようになりました。Grafana Labs や Elastic などのメンバーも加わり、2026 年に入ってからは実装のペースも上がってきています。

どこまで実装されているのか

では、実際にどこまで SDK の実装が進んでいるのでしょうか。OpenTelemetry Browser では、ブラウザ固有のテレメトリを収集するための計装パッケージが形になりはじめています。たとえば、次のような情報を集める仕組みが用意されています。

  • Navigation:初回のページ読み込みや SPA のルート変更を計装する
  • Navigation Timing:ページの読み込みに関するタイミング情報を計装する
  • Resource Timing:画像やスクリプトなど、リソースの読み込みに関するタイミング情報を計装する
  • User Action:クリックなどのユーザー操作を計装する
  • Web Vitals:Core Web Vitals を計装する
  • Console:logwarnerror などの Console API の呼び出しを計装する
  • Errors:未処理のエラーや Promise の reject を計装する

これらは @opentelemetry/browser-instrumentation から利用できます。ただし、現時点では experimental なので、今後 API が変更される可能性があります。

https://github.com/open-telemetry/opentelemetry-browser/tree/main/packages/instrumentation

これらの計装パッケージは、クリックや Web Vitals、エラーなど、ある時点で発生した出来事を構造化された LogRecord として出力するイベントベースの設計になっています。一方、instrumentation-fetchinstrumentation-document-load などは、処理の開始から終了までの期間や親子関係を持つ Span を出力するスパンベースの設計です。両者は競合するものではなく、同じセッションで発生したイベントと処理を関連づけて利用できます。

opentelemetry-jsopentelemetry-js-contrib にあるスパンベースのブラウザ向けの計装パッケージも、今後は opentelemetry-browser への移管や置き換えが検討されています。

公式の Example を動かしてみる

OpenTelemetry Browser のリポジトリには、実際にブラウザ向けの計装を試せる次の 2 つの Example が用意されています。

  • all-instrumentations:OpenTelemetry Browser で開発されているイベントベースの計装を試す
  • with-tracing:イベントベースの計装に加えて、Fetch と XMLHttpRequest のスパンベースの計装も試す

https://github.com/open-telemetry/opentelemetry-browser/tree/main/examples

今回は、イベントベースとスパンベースの計装を組み合わせた with-tracing を動かしてみます。記事の前半で説明した LogRecordSpan の違いを、実際の出力から確認できるためです。

検証に使用したコードと設定は、次のリポジトリで公開しています。

https://github.com/nissy-dev/sandbox/tree/main/otel-browser-sample

OpenTelemetry Collector へ送信する

公式の with-tracing では、収集した LogRecordSpan がブラウザの開発者コンソールに出力されます。これだけでも計装の動作は確認できますが、今回は実際の利用に近い構成を試すため、OTLP/HTTP Exporter を追加し、OpenTelemetry Collector へ送信します。

ブラウザからは OTLP/HTTP を使い、Logs を Collector の /v1/logs、Traces を /v1/traces へ送信します。それぞれの送信には、OTLPLogExporterOTLPTraceExporter を使用し、サービス名には otel-browser-with-tracing を設定しました。

また、OTLP の送信自体が Fetch や XMLHttpRequest のスパンとして計装されないように、Collector の URL を各 Instrumentation の ignoreUrls に指定しています

Docker Compose でモニタリング基盤を用意する

Grafana、Loki、Tempo、OpenTelemetry Collector をまとめて起動できる grafana/otel-lgtm を利用します。これにより、テレメトリの受信から保存、可視化までに必要な環境を 1 つのコンテナで用意できます。

今回使用した docker-compose.yml は次のとおりです。

services:
  lgtm:
    image: grafana/otel-lgtm:0.29.1
    ports:
      - "3000:3000"
      - "4318:4318"
    volumes:
      - lgtm-data:/data

volumes:
  lgtm-data:

ポート 4318 では内蔵 Collector の OTLP/HTTP receiver、ポート 3000 では Grafana を公開します。LGTM イメージの標準設定では、HTTP スキームのすべてのオリジンからの OTLP/HTTP リクエストが CORS で許可されています。これはローカルでの検証を想定した設定であり、HTTPS オリジンは許可されていません。本番環境では、公開方法や許可するオリジンを別途設計する必要があります。また、Loki と Tempo のデータは lgtm-data ボリュームに保存します。

実際に確認できたトレースやログ

Docker Compose でモニタリング基盤を起動してから、サンプルの Web アプリケーションを起動します。

サンプルの Web アプリケーションには、Fetch と XMLHttpRequest を実行するためのボタンがあります。今回は「Fetch request」をクリックし、ユーザー操作のイベントログと Fetch のスパンを発生させます。

Fetch requestとXHR requestのボタンを備えたサンプルWebアプリケーション
Fetch と XMLHttpRequest を実行できるサンプル Web アプリケーション

実際に Tempo でスパンを見ることができました。

Grafana Tempoで確認したFetchリクエストのHTTP GETスパン
Grafana Tempo で確認した Fetch リクエストの HTTP GET スパン

また、Span の attributes に設定されている session.id を使って Loki のログを絞り込むことで、同じセッションで収集された Core Web Vitals のスコアも確認できました。

Grafana Lokiでsession.idを指定して確認したCore Web Vitalsのログ
Grafana Loki で session.id を指定して確認した Core Web Vitals のログ

実用に向けて気になる点

ここからは、実用を考えたときに気になっている次の 2 点を見ていきます。

  1. minify されたエラーのスタックトレースを「誰が」復元するのか
  2. Session Replay を OpenTelemetry でどう扱うのか

エラーの復元

フロントエンドでは、本番に配信される JavaScript の多くが minify されています。そのため、エラーのスタックトレースをそのまま眺めても、元のコードのどこで何が起きたのかは読み取りづらくなります。

そこで必要になるのが、ソースマップを使って minify 後の位置を元のソースコード上の位置へ対応づける処理です。この処理は symbolication と呼ばれます。

SaaS の RUM やエラー監視サービスでは、次の処理をサービス側が担当します。

  • ビルド時に生成したソースマップのアップロード
  • 収集したスタックトレースとソースマップの対応づけ
  • 元のファイル名や行・列番号への復元

一方で、OpenTelemetry 自体は symbolication の仕組みを提供していません。従来どおり SaaS をバックエンドとして使う場合はサービス側の機能を利用できますが、Loki などを使って自前で構成する場合は、別途 symbolication の仕組みを用意する必要があります。

たとえば、Honeycomb は OpenTelemetry Collector 向けの symbolicator を公開しています。ただし、これも OpenTelemetry の標準機能ではありません。

https://github.com/honeycombio/opentelemetry-collector-symbolicator

フロントエンドのエラーを OpenTelemetry で扱う場合は、ソースマップをどこへ置き、Collector とバックエンドのどちらでスタックトレースを復元するのかまで設計する必要がありそうです。

Session Replay

Session Replay は、ユーザーがどこをクリックし、どう画面を遷移したかを録画のように再現する機能です。エラーが起きた瞬間の前後の操作をそのまま追えるので、フロントエンドの不具合調査ではとても強力です。

Session Replay の実装には、rrweb というライブラリが広く利用されています。

https://github.com/rrweb-io/rrweb

この rrweb をベースにした Session Replay の実装は、イベントの収集やプライバシーに配慮したマスキングだけでなく、セッションの再生や検索まで含めて、各ベンダーのプロダクト体験と強く結びついています。そのため、Session Replay をベンダー非依存な OpenTelemetry と連携させる方法を整理するのは簡単ではなさそうです。

OpenTelemetry Browser のリポジトリにも rrweb のサポートを提案する issue はありますが、いまのところ具体的な仕様や実装の議論には進んでいないようです。

https://github.com/open-telemetry/opentelemetry-browser/issues/32

OpenTelemetry はフロントエンドに広がりつつある

この記事では、OpenTelemetry Browser の開発状況と、実用に向けて残っている課題について紹介しました。ブラウザ向け SDK の開発が独立して動き出し、ユーザー操作や Core Web Vitals などを集める計装パッケージも形になってきています。

一方で、SaaS の RUM SDK が提供する機能をすべて置き換えるには、まだ課題が残っています。特に、ソースマップを使ったエラーの復元や Session Replay の扱いは、実用上避けて通れないポイントだと思います。

そのため、今すぐフロントエンド監視をすべて OpenTelemetry に寄せるというよりは、まずは open-telemetry/opentelemetry-browser の動きを追いながら、どのテレメトリが標準化されていくのかを確認するのがよさそうです。今後も OpenTelemetry Browser の動向に注目したいです。

GitHubで編集を提案
50
17
サイボウズ フロントエンド

Discussion

junerjuner

むしろフロントエンドだと OpenTelemetry の難しさは span の生成そのものより、非同期処理を跨いだコンテキスト伝播にある印象です。

Node.js なら async / await を跨いだコンテキストを保持する AsyncLocalStorage があるため OpenTelemetry でも利用できますが、ブラウザには同等の標準機構がありません。

自分も以前に ES2022 環境で Zone.js を使わずコンテキストマネージャーを自前実装したことがあります。ただ、Promise のネストや並列実行を考慮し始めると、どの span が current なのか分からなくなってしまい、非同期コンテキスト伝播の難しさを痛感しました。

そのため、JavaScript 言語レベルで async / await を跨いだコンテキスト伝播を提供する AsyncContext proposal が現在議論されています。

https://github.com/tc39/proposal-async-context

また、コールバックベースの AsyncContext.Variable.run() だけでは扱いづらいケース向けに、using(Explicit Resource Management)でコンテキストの enter / exit を管理できる Disposable AsyncContext.Variable proposal も提案されています。

https://github.com/tc39/proposal-async-context-disposable

1
nissy-devnissy-dev

非同期処理を跨いだコンテキスト伝播は、確かに重要なところですね。AsynContext も早く来てほしいです。

ここらへんの話についても SIG のメンバーたちは認識しているようで、AsyncLocalStorage が実装される前から js でのコンテキスト伝搬で一般的だった zone.js を使わないでどうやって実装するのか?という観点について issue は作成されているようです。(既存の実装では zone.js を使ってほしいという思想みたいです。)

https://github.com/open-telemetry/opentelemetry-browser/issues/210

この issue では zone.js に変わるライブラリとして、以下のライブラリなども検討する価値がありそうと話していますね。

https://github.com/unjs/unctx

1
mizchimizchi

サードパーティスクリプトなどを開発していた側の意見です。

サーバーと同じ基準でフロントエンドで OTel のデータを収集するという発想に、自分は強い懸念を覚えます。

ブラウザは、サーバーと違って運営者が管理する計算資源ではありません。計装ライブラリのダウンロード、初期化、フック、属性生成、シリアライズ、圧縮、バッファリング、送信にかかるコストは、すべてユーザーの帯域、CPU、メモリ、バッテリーに転嫁されます。

特に低速回線や低性能端末では、観測のための処理そのものが体験を悪化させます。サーバー側で許容される高カーディナリティなスパンや詳細なログを、そのままブラウザへ持ち込むべきではありません。

自分が実装を見た限りですが、サーバーサイド Node.js のSDKの転用でブラウザパフォーマンス文脈を欠いている実装に見えるので、ここに配慮した実装を出来る人材がいないまま開発されているように見えます。

さらに深刻なのがプライバシーの問題です。

URL、閲覧履歴、端末情報、位置情報、DOMテキスト、入力値、例外メッセージ、HTTPヘッダーなどは、単体では無害に見えても、組み合わせやサービスの文脈によって個人の行動、関心、健康状態、属性を推測できる情報になります。ユーザーの端末で発生する情報はサーバーのものより個人識別につながりやすい強いシグナルです。

OTel自体が無差別なデータ収集を要求しているわけではありませんが、しかし、任意の属性やログを追加できるサーバー向けの計装モデルを、同じ感覚でブラウザに持ち込む設計には危うさがあります。

パフォーマンス面でも個人情報の取り扱いの面でも、無邪気にOTelの発想を持ち込んだ思慮が浅い実装であり、現代のプライバシー要求水準を満たしているとは思えません。

5
ログインするとコメントできます
50
17