背景
OpenCensus プロジェクトは、いくつかの言語固有のインストルメンテーション ライブラリを提供しています。これらのライブラリは、アプリケーションからトレースや指標を収集し、Prometheus、Zipkin、Jaeger、Stackdriver
などのトレースおよび監視バックエンドにエクスポートします。
OpenCensus Web ライブラリは、ブラウザで実行されるフロントエンド ウェブ アプリケーションのコードに特化した OpenCensus の実装です。OC Web はウェブページのインストルメンテーションを行い、遅延や分散トレースなどのパフォーマンス データをユーザーサイドで収集します。デベロッパーは、フロントエンドの問題診断とアプリケーション全体の健全性監視のための情報を得ることができます。
なお、OC Web 以上に重要なのは、さらに広範な OpenCensus ファミリーのプロジェクトが OpenTracing を取り込んで
OpenTelemetry になりつつあることです。このプロジェクトの準備が整った時点で、OpenCensus Web の機能は
OpenTelemetry JS に移行される見込みです。その間も、OC Web はアルファ版リリースとして動作し続けます。
アーキテクチャ
OC Web は、次の 3 つのアプリケーション コンポーネントと連係して動作します。
- フロントエンド ウェブサーバー: OC Web のライブラリ コードや構成を含む最初の HTML をブラウザに対してレンダリングします。通常、これは OpenCensus サーバーサイド ライブラリ(Go、Java など)でインストルメンテーションされます。サーバーには、HTTP/JSON トレースを受信して OpenCensus Agent との通信を仲介するエンドポイントを作成することをお勧めします。
- ブラウザの JS: ブラウザで実行される OC Web ライブラリのコードです。このコードは、ユーザー操作の測定とブラウザデータの収集を行い、HTTP/JSON を使って OpenCensus Agent にスパンとして書き込みます。
- OpenCensus Agent: フロントエンド ウェブサーバーのプロキシ エンドポイントから、またはブラウザの JS から直接トレースを受け取り、トレース バックエンド(例: Stackdriver、Zipkin)にエクスポートします。
OC Web には、
OpenCensus Agent が必要です。OpenCensus Agent は、診断データを仲介して任意のバックエンドに再エクスポートします。詳細については、
ドキュメントをご覧ください。
機能
最初のページ読み込みのトレース
OC Web を使うと、最初のページ読み込みのトレースを取得できます。なんと、OC Web ライブラリがブラウザに読み込まれる前に発生したイベントも取得できます。最初のページ読み込みのトレースを行うと、どのリソースがウェブサイトのパフォーマンスを低下させているのかがわかります。また、通常は分散トレース システムで取得できないデータも取得できます。
最初のページ読み込みにおけるすべての相互作用の時間を測定するため、OC Web はドキュメントの load イベントが発生するまで待機し、最初のページ読み込みパフォーマンスを示すタイミングからスパンを生成します。その際に、ブラウザの
Navigation Timing API と
Resource Timing API を使います。以下に示すのは、
最初の読み込みサンプルアプリからキャプチャした OC Web のトレース サンプルを
Zipkin にエクスポートしたものです。ブラウザの load イベントが発行されるまでのユーザーのナビゲーションの全体を表す
‘nav./’ スパンがあることに注目してください。
このサンプルには、クライアント サイドとサーバーサイドで最初の HTML 読み込みを測定した
‘/’ スパンも含まれています。これらのスパンは、
W3C Trace Context 形式で
‘window.traceparent’ 変数を送り返すサーバーによって接続されます。これが必要になるのは、ブラウザは最初のページ読み込みの際に Trace Context ヘッダーを送信しないためです。サーバーサイドのスパンから、テンプレートの解析とレンダリングにかかった時間もわかります。
先ほどのイメージの
long js task スパンは、CPU による制約を受ける JavaScript イベントループに 80.095 ミリ秒かかったことを示しています。これは、
Long Tasks ブラウザ API で計測しています。
DOM イベントとネットワーク イベントのスパンのアノテーション
OC Web が取得するスパンには、詳細なアノテーションも含まれています。たとえば、
`domInteractive` や
`first-paint` などの DOM イベントについてのアノテーションや、domainLookupStart や secureConnectionStart などのネットワーク イベントについてのアノテーションです。次に示すのは、先ほどと同じトレースを
Stackdriver Trace にエクスポートし、アノテーションを展開したものです。
ユーザー操作
単一ページ アプリケーションでは、最初の読み込み後に操作(例: ユーザーがボタンをクリックする、ページの別のセクションに移動する)が発生するのが一般的です。エンドユーザーがブラウザ アプリケーション内で行った操作を測定すると、アプリケーションについて次のような有用なデータが得られます。
- 最初のページのレンダリングとその後のページ内操作を関連付ける
- クリック後にページの応答がなくなるなど、エンドユーザーが認識できる速度低下を可視化する
現在の OC Web は、Angular の
Zone.js ライブラリにモンキーパッチを当てることにより、クリックとルートの遷移をトラックしています。OC Web は、その後の操作によって発生する同期タスクおよび非同期タスク(例: setTimeout、XHR)をトラックします。いくつかの操作が同時に実行された場合でも、トレースが行われます。
クリック イベントの自動トレース
ブラウザの
click イベントは、DOM 要素(例: ボタン)が
クリックされ、クリック対象の要素が無効になっていない限り、すべてトレースされます。ユーザーが要素をクリックすると、新しい
Zone が作成され、操作にかかる合計時間が計測されます。
このルートスパンに名前を付けるため、デベロッパーが要素に
data-ocweb-id 属性を追加して操作の名前をカスタマイズできるようにしています。次の例では、
‘Save edit user info’ という名前になります。
<button type="submit" data-ocweb-id="Save edit user info"> Save changes </button>
OC Web は、
History API にモンキーパッチを適用することで、ページ セクション間のルート遷移をトレースします。OC Web は、
‘Navigation /path/to/page’ というパターンを使ってこの操作に名前を付けます。次のスクリーンショットは、
ユーザー操作サンプルから Stackdriver にエクスポートしたトレースです。ここには 1 つの Navigation トレースが含まれており、ルート遷移が完了する前にいくつかのネットワーク呼び出しが行われています。
カスタム スパンの作成
OC Web では、ユーザーの操作に関連するタスクやコードのカスタムスパンを使ってウェブ アプリケーションのインストルメンテーションを行うことができます。次に示すのは、その方法を例示したコード スニペットです。
import { tracing } from '@opencensus/web-instrumentation-zone';
function handleClick() {
// 現在の操作のルートスパンの子スパンを開始
// これはボタンが実行するコードで実行する必要がある
const childSpan = tracing.tracer.startChildSpan({
name: 'name of your child span'
});
// 何らかのオペレーションを実行...
// オペレーション終了時に子スパンを終了
childSpan.end();
}
詳細については、
OC Web のドキュメントをご覧ください。
OC Web は、ユーザーの操作によって生成される HTTP リクエストを自動的にインターセプトしてスパンを生成します。さらに、OC Web はインターセプトしたそれぞれの HTTP リクエストに
W3C Trace Context 形式の Trace Context ヘッダーを追加します。この処理は、同じオリジンのリクエストまたは提供された正規表現に一致するリクエストに対してのみ行われます。
サーバーで OpenCensus によるインストルメンテーションも行っている場合、バックエンド サービス全体でこれらのリクエストのトレースが継続されます。そのため、問題がフロントエンドにあるのかサーバーサイドにあるのかを知ることができます。
OC Web には、
domainLookupStart や responseEnd などのアノテーションを作成し、
CORS プリフライト リクエストのスパンを生成するための
Performance API データも含まれています。
次のスクリーンショットは、
ユーザー操作のサンプルとして Stackdriver にエクスポートしたトレースを示しています。アノテーションが付加されたスパンが自動生成されているネットワーク呼び出しがいくつか(例:
‘Sent./sleep’)あることがわかります。また、サーバーサイドのスパン(例:
‘/sleep’、
‘ocweb.handlerequest’)や、CORS プリフライトに関連するスパンも存在します。
ユーザー操作と最初のページ読み込みのトレースとの関連付け
OC Web は、属性およびスパンリンクとして、ユーザーの操作に
最初のページ読み込み時のトレース ID を付加します。これにより、1 つの属性に対するクエリでトレースを検索することで、最初の読み込みのトレースとその操作に関連するトレースを探せるようになります。また、あるページを読み込んだ後のアプリケーション内でのユーザーのナビゲーション全体を理解することも可能です。
次のスクリーンショットは、
initial_load_trace_id 属性を使った検索を示しています。これには、最初にページを読み込んだ後のすべてのユーザー操作のトレースが含まれています。
実現する
OC Web を使えば、数行のインストルメンテーションを記述するだけで、ウェブ アプリケーションの分散トレースをエクスポートできます。ぜひ、
最初の読み込みと
ユーザー操作のサンプルを試してみてください。ソースコードに手を入れてみたり、
Gitter からフィードバックを送ったり、プル リクエストで
貢献したりすることも大歓迎です!
投稿者: Cristian González – OpenCensus チーム – 2019 年夏季 Google ソフトウェア エンジニアリング インターン、コロンビア国立大学コンピュータおよびシステム エンジニアリング学部生
OC Web の最初の作成者であり、今回の開発のサポートをしてくれた Dave Raffensperger 氏に格別の感謝を捧げます。