コンテンツにスキップ

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 パッケージも同じ構成を使用します:

import { datafluxRum } from "@cloudcare/browser-rum-slim"

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 を生成します:

type = resource
resource.type = websocket

Resource は以下のタイミングで生成されます:

  1. ブラウザが WebSocket close イベントを受信したとき
  2. 現在の RUM Session が期限切れになったとき
  3. ページが beforeunload をトリガーしたとき
  4. SDK が現在の収集インスタンスを停止したとき

WebSocket は長接続です。接続がまだ開いている間は、Network に最終的な RUM Resource が一時的に表示されないのは正常な動作です。SDK は現在、接続のスナップショットを定期的にアップロードすることはありません。

ページのリフレッシュ、クローズ、または遷移時に、SDK は beforeunload フェーズで可能な限り決済して送信します。ページプロセスが強制終了されたり、ブラウザがクラッシュしたり、デバイスの電源が切れたりした場合、JavaScript が実行されない可能性があり、最後の接続 Resource が失われる可能性があります。

正常なクローズ

ブラウザが close を受信した後:

resource.websocket.tracking_end_reason = close_event

イベントには、クローズコード、クローズ理由、および was_clean が含まれます。

Session の期限切れ

Session が期限切れになると、まだ開いている接続は現在のデータで決済されます:

resource.websocket.tracking_end_reason = session_end

このとき、業務の WebSocket はクローズされないため、クローズコード、クローズ理由、および was_clean は存在しない可能性があります。新しい Session が確立されると、SDK は同じ物理接続に対して新しい統計セグメントを開始し、同じ connection_id を保持し、メッセージカウントとセグメント時間をリセットします。

Session が期限切れになり、まだ更新されていない間のメッセージは、いずれの Session にもカウントされません。この期間に新しく作成され、更新時にも開いたままの接続は、新しい Session の更新時点から統計が開始されます。

ページのアンロード

ページが beforeunload をトリガーしたとき:

resource.websocket.tracking_end_reason = page_exit

接続がブラウザの close イベントをトリガーするとは限らないため、クローズフィールドは存在しない可能性があります。

ハンドシェイクの失敗

接続が open をトリガーすることなく close に移行した場合:

resource.websocket.handshake_succeeded = false

この場合、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:現在のセグメント開始時に存在していた View
  • end_view_id:クローズまたは決済時に存在していた View
  • end_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.isWebSocket = true
domainContext.webSocket = ネイティブ WebSocket インスタンス

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 として収集されます。

接続の確認

  1. ブラウザの開発者ツールを開き、業務 WebSocket が接続され、メッセージが生成されていることを確認します。
  2. 明示的に socket.close(1000, "done") を実行します。
  3. Network で /v1/write/rum をフィルタリングします。
  4. リクエストデータ内で resource_type=websocket を検索します。
  5. handshake_succeeded、メッセージ数、バイト数、クローズフィールドを確認します。

接続がまったくクローズされない場合は、Session の期限切れを待って tracking_end_reason=session_end を確認できます。ページをリフレッシュすると、tracking_end_reason=page_exit が表示されるはずです。この送信は、ページ終了フェーズにおけるベストエフォート型のレポートです。

よくある質問

設定後に WebSocket Resource が表示されない

以下の順序で確認してください:

  1. enableExperimentalFeatures が "track_websockets" を含む配列であること
  2. RUM が接続作成前に初期化されていること
  3. 現在の Session が sessionSampleRate にヒットしていること
  4. 接続がクローズされているか、Session が期限切れであること
  5. beforeSend が false を返していないこと
  6. 接続が 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 がありません。

フィードバック

このページは役に立ちましたか?