WebSocket 長接続収集¶
RUM SDK 3.3.6 以降、ブラウザのネイティブ WebSocket 接続を RUM Resource に集約できるようになりました。ハンドシェイク、メッセージトラフィック、インバウンドアイドル、送信バックログ、およびクローズ状態の分析に使用できます。
この機能は現在実験的な機能であり、デフォルトでは無効です。SDK は WebSocket メッセージの本文を読み取ったりアップロードしたりすることはありません。
収集を有効にする¶
NPM¶
import { datafluxRum } from "@cloudcare/browser-rum"
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "websocket-client",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
enableExperimentalFeatures: ["track_websockets"],
})
軽量 RUM パッケージも同じ構成を使用します:
CDN¶
<script
src="https://static.guance.com/browser-sdk/v3/dataflux-rum.js"
type="text/javascript"
></script>
<script>
window.DATAFLUX_RUM &&
window.DATAFLUX_RUM.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "websocket-client",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
enableExperimentalFeatures: ["track_websockets"],
})
</script>
上記の例ではパブリック OpenWay を使用しています。DataKit に直接接続する場合は、site と clientToken を datakitOrigin に置き換えてください。両方のレポートアドレスを同時に構成しないでください。
enableExperimentalFeatures は配列である必要があります。文字列 "track_websockets" を直接指定しても収集は有効になりません。
初期化のタイミング¶
RUM は、業務が WebSocket 接続を作成する前に初期化する必要があります:
datafluxRum.init({
// その他の設定
enableExperimentalFeatures: ["track_websockets"],
})
const socket = new WebSocket("wss://example.com/socket")
以下の接続は収集されません:
- RUM 初期化前にすでに作成された接続
- 初期化前にキャッシュされた元の
WebSocketコンストラクタを使用して作成された接続 - Web Worker または Service Worker 内で作成された接続
window.WebSocketを経由しない他のトランスポート実装WebSocketStreamによって作成された接続
収集を有効にしても、ネイティブの WebSocket の構築方法、静的定数、instanceof、業務イベントリスナー、および send() の戻り値の動作は変更されません。
収集モデル¶
各 WebSocket Session セグメントは、1 つの RUM Resource を生成します:
Resource は以下のタイミングで生成されます:
- ブラウザが WebSocket
closeイベントを受信したとき - 現在の RUM Session が期限切れになったとき
- ページが
beforeunloadをトリガーしたとき - SDK が現在の収集インスタンスを停止したとき
WebSocket は長接続です。接続がまだ開いている間は、Network に最終的な RUM Resource が一時的に表示されないのは正常な動作です。SDK は現在、接続のスナップショットを定期的にアップロードすることはありません。
ページのリフレッシュ、クローズ、または遷移時に、SDK は beforeunload フェーズで可能な限り決済して送信します。ページプロセスが強制終了されたり、ブラウザがクラッシュしたり、デバイスの電源が切れたりした場合、JavaScript が実行されない可能性があり、最後の接続 Resource が失われる可能性があります。
正常なクローズ¶
ブラウザが close を受信した後:
イベントには、クローズコード、クローズ理由、および was_clean が含まれます。
Session の期限切れ¶
Session が期限切れになると、まだ開いている接続は現在のデータで決済されます:
このとき、業務の WebSocket はクローズされないため、クローズコード、クローズ理由、および was_clean は存在しない可能性があります。新しい Session が確立されると、SDK は同じ物理接続に対して新しい統計セグメントを開始し、同じ connection_id を保持し、メッセージカウントとセグメント時間をリセットします。
Session が期限切れになり、まだ更新されていない間のメッセージは、いずれの Session にもカウントされません。この期間に新しく作成され、更新時にも開いたままの接続は、新しい Session の更新時点から統計が開始されます。
ページのアンロード¶
ページが beforeunload をトリガーしたとき:
接続がブラウザの close イベントをトリガーするとは限らないため、クローズフィールドは存在しない可能性があります。
ハンドシェイクの失敗¶
接続が open をトリガーすることなく close に移行した場合:
この場合、setup_duration は、コンストラクションからクローズまたは Session 決済までの時間を示し、正常なハンドシェイクにかかった時間を表すわけではありません。ブラウザは通常、クローズコード 1006 を使用して異常終了を示しますが、具体的な値はブラウザのイベントに依存します。
メッセージ統計¶
SDK はメッセージ数とバイト数のみを統計し、本文は収集しません:
| メッセージタイプ | バイト計算方法 |
|---|---|
| string | UTF-8 バイト数 |
ArrayBuffer |
byteLength |
TypedArray、DataView |
現在の view の byteLength |
Blob |
size |
| 認識できないタイプ | 0 |
例えば、文字列 你好 は UTF-8 で 6 バイトとして統計され、JavaScript の文字列長 2 ではありません。
View の所属¶
1 つの WebSocket Session セグメントは、複数の RUM View にまたがる可能性があります。Resource は追加で以下を記録します:
start_view_id:現在のセグメント開始時に存在していた Viewend_view_id:クローズまたは決済時に存在していた Viewend_view_path:クローズまたは決済時のページパス(RUM SDK 3.3.8 で追加)
セグメント開始時のページパスは、Resource の標準的な View コンテキストを再利用します:beforeSend 内では view.path、最終的な intake フィールドは view_path です。セグメントがページをまたがる場合、開始 View と終了 View の ID およびパスは異なる可能性があります。パスには URL pathname のみが含まれ、query や hash は含まれません。Resource は引き続き、セグメント開始時刻に基づいて RUM イベントパイプラインに投入されます。
レポートフィールド¶
beforeSend では event.resource.websocket を読み取ることができます。最終的な intake では、フィールドは resource_websocket_* に変換されます。
基本 Resource フィールド¶
beforeSend パス |
intake フィールド | 説明 | 単位 |
|---|---|---|---|
resource.type |
resource_type |
固定値 websocket |
- |
resource.url |
resource_url |
ブラウザが解決した ws:// または wss:// URL |
- |
resource.url_host |
resource_url_host |
URL のホスト | - |
resource.url_path |
resource_url_path |
URL のパス | - |
resource.url_query |
resource_url_query |
URL のクエリパラメータ | - |
resource.duration |
duration |
現在の Session セグメントの長さ | ns |
view.path |
view_path |
現在のセグメント開始時に存在していた View のページパス | - |
WebSocket Resource には HTTP レスポンスがないため、resource_status、resource_method、TTFB、ダウンロードサイズ、または HTTP timing はありません。
接続フィールド¶
resource.websocket.* |
intake フィールド | 説明 | 単位 |
|---|---|---|---|
connection_id |
resource_websocket_connection_id |
物理接続の一意の ID。Session セグメント間で不変 | - |
handshake_succeeded |
resource_websocket_handshake_succeeded |
open を受信したかどうか |
boolean |
start_time |
resource_websocket_start_time |
現在のセグメントの開始時間 | Unix ms |
end_time |
resource_websocket_end_time |
クローズまたは決済時間 | Unix ms |
start_view_id |
resource_websocket_start_view_id |
セグメント開始時の View ID | - |
end_view_id |
resource_websocket_end_view_id |
接続終了時の View ID | - |
end_view_path |
resource_websocket_end_view_path |
クローズまたは決済時のページパス | - |
tracking_end_reason |
resource_websocket_tracking_end_reason |
close_event、session_end、または page_exit |
- |
protocol |
resource_websocket_protocol |
サーバーがネゴシエートしたサブプロトコル | - |
setup_duration |
resource_websocket_setup_duration |
最初のセグメントではコンストラクションから open までの時間。更新セグメントでは 0 |
ns |
メッセージフィールド¶
resource.websocket.* |
intake フィールド | 説明 | 単位 |
|---|---|---|---|
messages_in.count |
resource_websocket_messages_in_count |
インバウンドメッセージ数 | count |
messages_in.size |
resource_websocket_messages_in_size |
インバウンドメッセージの総バイト数 | byte |
messages_out.count |
resource_websocket_messages_out_count |
正常に send() を呼び出した回数 |
count |
messages_out.size |
resource_websocket_messages_out_size |
アウトバウンドメッセージの総バイト数 | byte |
time_to_first_message_in |
resource_websocket_time_to_first_message_in |
open から最初のインバウンドメッセージまで |
ns |
time_to_first_message_out |
resource_websocket_time_to_first_message_out |
open から最初のアウトバウンドメッセージまで |
ns |
last_message_in_at |
resource_websocket_last_message_in_at |
最後のインバウンドメッセージの時間 | Unix ms |
longest_inbound_silence |
resource_websocket_longest_inbound_silence |
隣接するインバウンドメッセージ間の最長間隔 | ns |
inbound_idle_duration_before_close |
resource_websocket_inbound_idle_duration_before_close |
最後のインバウンドメッセージからクローズまたは決済までの時間 | ns |
buffered_amount_max |
resource_websocket_buffered_amount_max |
各 send() 呼び出し前に観測された bufferedAmount のピーク値 |
byte |
buffered_amount_max は send() 呼び出し前のサンプリングによるピーク値であり、ブラウザの送信キューの継続的な監視値ではありません。
Resource エクスプローラーでは、view_path を使用して、指定されたページから開始された接続セグメントをフィルタリングできます。RUM SDK 3.3.8 以降を使用している場合は、resource_websocket_end_view_path を使用して、指定されたページで終了した接続セグメントをフィルタリングすることもできます。
クローズフィールド¶
resource.websocket.* |
intake フィールド | 説明 |
|---|---|---|
close_code |
resource_websocket_close_code |
ブラウザの CloseEvent のクローズコード |
close_reason |
resource_websocket_close_reason |
クローズ理由 |
was_clean |
resource_websocket_was_clean |
ブラウザが接続を正常にクローズされたと見なすかどうか |
Session の期限切れまたはページアンロードによる決済時には、これらのフィールドは存在しない可能性があります。
beforeSend の使用¶
WebSocket Resource をチェック、補完、またはフィルタリングできます:
datafluxRum.init({
// その他の設定
enableExperimentalFeatures: ["track_websockets"],
beforeSend(event, domainContext) {
if (
event.type === "resource" &&
event.resource?.type === "websocket"
) {
event.context = {
...event.context,
socket_channel: "notifications",
}
console.debug(
"WebSocket completed",
event.resource.websocket,
domainContext?.webSocket
)
}
return true
},
})
WebSocket Resource の domainContext には以下が含まれます:
domainContext は beforeSend コールバック内でのみ使用され、アップロードされることはありません。
false を返すと、指定された接続を破棄できます:
beforeSend(event) {
if (
event.type === "resource" &&
event.resource?.type === "websocket" &&
event.resource.url.includes("/health-stream")
) {
return false
}
return true
}
プライバシーとセキュリティ¶
SDK は完全な WebSocket URL を収集し、URL のクエリを解析します。パスワード、長期トークン、ID 番号などの機密情報を URL に含めないでください。
収集を有効にしても、ページの CSP connect-src、サーバー側の Origin 検証、またはその他のブラウザセキュリティポリシーがバイパスされることはなく、ハンドシェイクリクエストにカスタムの trace ヘッダーが注入されることもありません。
サードパーティライブラリが RUM 初期化後に window.WebSocket を呼び出す限り、基盤となる接続は収集されます:
- 自動再接続によって新しい接続が作成されるたびに、新しい
connection_idと Resource が生成されます。 - 1 つの接続が複数の業務トピックを再利用する場合、SDK は接続レベルの集約のみを提供します。
- HTTP long polling フェーズは、引き続き XHR または fetch Resource として収集されます。
接続の確認¶
- ブラウザの開発者ツールを開き、業務 WebSocket が接続され、メッセージが生成されていることを確認します。
- 明示的に
socket.close(1000, "done")を実行します。 - Network で
/v1/write/rumをフィルタリングします。 - リクエストデータ内で
resource_type=websocketを検索します。 handshake_succeeded、メッセージ数、バイト数、クローズフィールドを確認します。
接続がまったくクローズされない場合は、Session の期限切れを待って tracking_end_reason=session_end を確認できます。ページをリフレッシュすると、tracking_end_reason=page_exit が表示されるはずです。この送信は、ページ終了フェーズにおけるベストエフォート型のレポートです。
よくある質問¶
設定後に WebSocket Resource が表示されない¶
以下の順序で確認してください:
enableExperimentalFeaturesが"track_websockets"を含む配列であること- RUM が接続作成前に初期化されていること
- 現在の Session が
sessionSampleRateにヒットしていること - 接続がクローズされているか、Session が期限切れであること
beforeSendがfalseを返していないこと- 接続が Worker によって作成されていないこと
WebSocket error を受信したが、まだ Resource がない¶
SDK は close イベントまたは Session 決済時に最終イベントを生成します。error イベントだけで個別に決済することはありません。
handshake_succeeded=false¶
ブラウザが open をトリガーしませんでした。WebSocket URL、TLS 証明書、CSP connect-src、リバースプロキシの Upgrade 設定、サーバー側の Origin 検証、および認証を確認してください。
メッセージの size が 0¶
データタイプが string、ArrayBuffer、TypedArray、DataView、または Blob であることを確認してください。SDK は任意のオブジェクトをシリアライズしてサイズを推定することはありません。
HTTP ステータスコードが表示されない¶
ブラウザの WebSocket API は、ハンドシェイクの HTTP ステータスコードをページに公開しません。そのため、WebSocket Resource には resource_status がありません。