跳转至

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 直连时,将 siteclientToken 替换为 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 分段生成一个 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 归属

一个 WebSocket Session 分段可能跨越多个 RUM View。Resource 额外记录:

  • start_view_id:当前分段开始时所在 View;
  • end_view_id:关闭或结算时所在 View。

分段跨页面时,这两个 ID 可以不同。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 host -
resource.url_path resource_url_path URL path -
resource.url_query resource_url_query URL query 参数 -
resource.duration duration 当前 Session 分段时长 ns

WebSocket Resource 没有 HTTP response,因此没有 resource_statusresource_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 -
tracking_end_reason resource_websocket_tracking_end_reason close_eventsession_endpage_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.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 query。不要在 URL 中放置密码、长期 Token、身份证号等敏感值。

开启采集不会绕过页面 CSP connect-src、服务端 Origin 校验或其他浏览器安全 策略,也不会向握手请求注入自定义 trace header。

第三方库只要在 RUM 初始化后调用 window.WebSocket,底层连接就会被采集:

  • 自动重连每创建一次新连接,就生成新的 connection_id 和 Resource;
  • 一个连接复用多个业务 topic 时,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、DataViewBlob。 SDK 不会序列化任意对象来估算大小。

看不到 HTTP 状态码

浏览器 WebSocket API 不向页面暴露握手 HTTP 状态码,因此 WebSocket Resource 没有 resource_status

文档评价

文档内容是否对您有帮助? ×