跳转至

RUM 配置

本文用于承载 HarmonyOS RUM 初始化配置与手动采集能力。

RUM 初始化配置

import { FTSDK, FTRUMConfig } from '@guancecloud/ft_sdk/Index';

const rumConfig = new FTRUMConfig()
  .setRumAppId('your-app-id')
  .setSamplingRate(1.0)
  .setSessionErrorSampleRate(1.0)
  .setEnableTraceUserAction(true)
  .setEnableTraceUserView(true)
  .setEnableTraceUserResource(true)
  .setEnableTrackAppUIBlock(true)
  .setEnableTrackAppANR(true)
  .setEnableTrackAppCrash(true)
  .setEnableTraceWebView(true);

await FTSDK.installRUMConfig(rumConfig);
方法 类型 必须 说明
setRumAppId string RUM 应用 ID,从[用户访问监测]应用中获取
setSamplingRate number RUM 采样率,范围 [0.0, 1.0],默认 1.0
setSessionErrorSampleRate number 错误采样率,范围 [0.0, 1.0],默认 0.0
setEnableTraceUserAction boolean 是否开启自动动作追踪,默认 false
setEnableTraceUserView boolean 是否开启页面追踪,默认 false
setEnableTraceUserResource boolean 是否开启资源追踪,默认 false
setEnableTrackAppUIBlock boolean 是否开启 UI 卡顿检测,默认为 false
setEnableTrackAppANR boolean 是否开启 ANR 监控,默认 false
setEnableTrackAppCrash boolean 是否开启 APP 崩溃监控,默认 false。如需 Native Crash,需依赖 @guancecloud/ft_native
setEnableTraceWebView boolean 是否开启 WebView 数据采集,默认 false。如需完整接入,请参考 WebView 数据监测
setRumCacheLimitCount number RUM 数据缓存数量限制,默认 100000,最小值 10000
setRumCacheDiscardStrategy RUMCacheDiscard 设置RUM数据达到限制上限以后的RUM丢弃规则,默认为 RUMCacheDiscard.DISCARDDISCARD 为丢弃追加数据,DISCARD_OLDEST 丢弃老数据

RUM 手动采集

FTRUMConfig 配置 setEnableTraceUserActionsetEnableTraceUserViewsetEnableTraceUserResourcesetEnableTrackAppUIBlocksetEnableTrackAppCrashsetEnableTrackAppANR 来实现 ActionViewResourceLongTaskError 的自动采集。若需自定义采集,可通过 FTRUMGlobalManager 手动上报。

View

startView(viewName: string, property?: Record<string, object>): void
stopView(property?: Record<string, object>): void
updateLoadTime(loadTime: number): void

自动追踪:

在 RUM 配置中开启 enableTraceUserView 后,SDK 会自动追踪页面跳转,包括:

  • 路由导航(router.pushUrlrouter.replaceUrl 等)
  • Navigation 组件切换
import { FTRUMGlobalManager } from '@guancecloud/ft_sdk/Index';

// 场景 1
FTRUMGlobalManager.getInstance().startView('ProductPage');

// 场景 2: 动态参数
class PropertyWrapper {
  value: string | number | boolean;

  constructor(v: string | number | boolean) {
    this.value = v;
  }
}

class ViewProperty {
  private properties: Map<string, string | number | boolean> = new Map();

  set(key: string, value: string | number | boolean): void {
    this.properties.set(key, value);
  }

  toObject(): Record<string, object> {
    const result: Record<string, object> = {} as Record<string, object>;
    this.properties.forEach((value, key) => {
      result[key] = new PropertyWrapper(value) as object;
    });
    return result;
  }
}

const viewProperty = new ViewProperty();
viewProperty.set('page_category', 'product');
viewProperty.set('page_id', '12345');
FTRUMGlobalManager.getInstance().startView('ProductPage', viewProperty.toObject());

FTRUMGlobalManager.getInstance().updateLoadTime(100000000);

// 场景 1
FTRUMGlobalManager.getInstance().stopView();

// 场景 2: 动态参数
const stopViewProperty = new ViewProperty();
stopViewProperty.set('view_duration', 1000);
FTRUMGlobalManager.getInstance().stopView(stopViewProperty.toObject());

注意事项:

  • 自动追踪需要在 RUM 配置中开启 enableTraceUserView(true)
  • 自动追踪会在页面切换时自动调用 startViewstopView,无需手动调用
  • 如果使用条件渲染等场景,仍可手动调用 startViewstopView
  • 页面名称会自动从路由路径或 Navigation 组件名称中提取

Action

addAction(actionName: string, actionType: string, duration: number, startTime: number, property?: Record<string, object>): void
import { FTRUMGlobalManager } from '@guancecloud/ft_sdk/Index';

// 场景 1: 直接完成
FTRUMGlobalManager.getInstance().addAction('buy_button_click', 'click');

// 场景 2: 动态参数
class PropertyWrapper {
  value: string | number | boolean;

  constructor(v: string | number | boolean) {
    this.value = v;
  }
}

class ActionProperty {
  private properties: Map<string, string | number | boolean> = new Map();

  set(key: string, value: string | number | boolean): void {
    this.properties.set(key, value);
  }

  toObject(): Record<string, object> {
    const result: Record<string, object> = {} as Record<string, object>;
    this.properties.forEach((value, key) => {
      result[key] = new PropertyWrapper(value) as object;
    });
    return result;
  }
}

const actionProperty = new ActionProperty();
actionProperty.set('product_id', '12345');
actionProperty.set('product_name', 'iPhone 15');
FTRUMGlobalManager.getInstance().addActionWithProperty('buy_button_click', 'click', actionProperty.toObject());

// 场景 3: 开始 Action
FTRUMGlobalManager.getInstance().startAction('buy_button_click', 'click');

自动追踪:

在 RUM 配置中开启 enableTraceUserAction 后,SDK 会自动追踪 UI 组件的点击事件。为 Button 组件添加 customProperty 可获取按钮文本:

Button('Buy Now')
  .id('buy-btn')
  .customProperty('buy-btn', 'Buy Now')
  .onClick(() => {
    // 点击事件会自动被追踪
  })

Error

addError(
  log: string,
  message: string,
  errorType: string | ErrorType,
  state: AppState,
  property?: Record<string, object> | null,
  dateline?: number,
  callBack?: RunnerCompleteCallBack | null
): void

addCustomError(errorMessage: string, errorStack?: string, property?: Record<string, object>): void
import { FTRUMGlobalManager, ErrorType, AppState } from '@guancecloud/ft_sdk/Index';

class PropertyWrapper {
  value: string | number | boolean;

  constructor(v: string | number | boolean) {
    this.value = v;
  }
}

class ErrorProperty {
  private properties: Map<string, string | number | boolean> = new Map();

  set(key: string, value: string | number | boolean): void {
    this.properties.set(key, value);
  }

  toObject(): Record<string, object> {
    const result: Record<string, object> = {} as Record<string, object>;
    this.properties.forEach((value, key) => {
      result[key] = new PropertyWrapper(value) as object;
    });
    return result;
  }
}

try {
  throw new Error('checkout failed');
} catch (err) {
  const error = err instanceof Error ? err : new Error(String(err));

  const errorProperty = new ErrorProperty();
  errorProperty.set('module', 'checkout');
  errorProperty.set('action', 'submit_order');

  // 场景 1: 上报自定义 Error
  FTRUMGlobalManager.getInstance().addCustomError(
    error.message,
    error.stack ?? '',
    errorProperty.toObject()
  );

  // 场景 2: 指定 Error 类型与应用状态
  FTRUMGlobalManager.getInstance().addError(
    error.stack ?? '',
    error.message,
    ErrorType.CUSTOM,
    AppState.RUN,
    errorProperty.toObject()
  );
}

LongTask

addLongTask(log: string, duration: number, property?: Record<string, string | number | boolean>): void

duration 单位为纳秒。

import { FTRUMGlobalManager } from '@guancecloud/ft_sdk/Index';

const durationMs = 350;
const durationNs = durationMs * 1000000;
const stack = new Error('checkout render long task').stack ?? 'Stack trace not available';

FTRUMGlobalManager.getInstance().addLongTask(
  stack,
  durationNs,
  {
    module: 'checkout',
    operation: 'render_order_list',
    threshold_ms: 200
  }
);

Resource

startResource(resourceId: string, property?: Record<string, object>): void
stopResource(resourceId: string): void
addResource(resourceId: string, resourceParams: ResourceParams, netStatusBean?: NetStatusBean): void

自动追踪:

在 RUM 配置中开启 enableTraceUserResource 后,SDK 可自动追踪以下请求:

  • @guancecloud/ft_sdk:RCP 与 Axios 兼容模式
  • @guancecloud/ft_sdk_ext:基于 @kit.NetworkKit HttpInterceptorChain 的增强模式,自 0.1.14-alpha03 起支持,且要求 HarmonyOS API 22+
import {
  FTRUMGlobalManager,
  ResourceParams,
  NetStatusBean
} from '@guancecloud/ft_sdk/Index';

const resourceId = 'https://api.example.com/data';

FTRUMGlobalManager.getInstance().startResource(resourceId);

const resourceParams = new ResourceParams();
resourceParams.setUrl(resourceId);
resourceParams.setResourceStatus(200);
resourceParams.setResponseContentLength(1024);
resourceParams.resourceType = 'xhr';

const netStatusBean = new NetStatusBean();
netStatusBean.setResourceHostIP('192.168.1.1');
netStatusBean.setDNSTime(10000000);
netStatusBean.setTcpTime(20000000);
netStatusBean.setTTFB(50000000);
netStatusBean.setResponseTime(100000000);

FTRUMGlobalManager.getInstance().stopResource(resourceId);
FTRUMGlobalManager.getInstance().addResource(resourceId, resourceParams, netStatusBean);

Resource 自动追踪

开启 enableTraceUserResource(true) 后,SDK 会自动追踪通过 RCP、Axios 兼容模式或 @kit.NetworkKit HTTP 拦截器发送的请求。

业务接入 @guancecloud/ft_sdk_ext 时,建议统一从 @guancecloud/ft_sdk_ext/Index 导入公开 API,避免使用 src/main/... 深路径。

RCP 自动追踪接入

在 RUM 配置中开启 enableTraceUserResource 后,SDK 会为通过 RCP 发送的 HTTP 请求自动采集 Resource 数据。

从当前版本开始,SDK 不再自动创建或持有全局 RCP Session,而是提供以下能力供业务自行装配:

  • RCPTraceInterceptor:自动注入 Trace Headers
  • RCPResourceInterceptor:自动采集 Resource 数据与性能指标
  • createFTRCPInterceptors():返回默认 RCP 拦截器列表,便于与自定义 SessionConfiguration 合并
  • createFTRCPTrackConfig():快速生成带默认拦截器和 TracingConfigurationSessionConfiguration

推荐接入方式:使用默认 SessionConfiguration 工厂函数

import { rcp } from '@kit.RemoteCommunicationKit';
import { createFTRCPTrackConfig } from '@guancecloud/ft_sdk/Index';

const session = rcp.createSession(
  createFTRCPTrackConfig({
    baseAddress: 'https://api.example.com'
  })
);

// GET 请求
const request = new rcp.Request('/data', 'GET');
const response = await session.fetch(request);

// POST 请求
const headers: rcp.RequestHeaders = { 'Content-Type': 'application/json' };
const postRequest = new rcp.Request('/data', 'POST', headers, { name: 'test' });
const postResponse = await session.fetch(postRequest);

如果项目通过 SDK 根入口导入,也可以使用:

import { createFTRCPTrackConfig } from '@guancecloud/ft_sdk/Index';

手动装配拦截器

如果需要完全控制 Session 配置,也可以直接使用 SDK 提供的拦截器:

import { rcp } from '@kit.RemoteCommunicationKit';
import { RCPTraceInterceptor, RCPResourceInterceptor } from '@guancecloud/ft_sdk/Index';

const session = rcp.createSession({
  baseAddress: 'https://api.example.com',
  interceptors: [
    new RCPTraceInterceptor(),
    new RCPResourceInterceptor()
  ],
  requestConfiguration: {
    tracing: {
      collectTimeInfo: true
    }
  }
});

TracingConfiguration 说明:

  • collectTimeInfo: true:建议开启。SDK 依赖 response.timeInfo 计算 DNS、TCP、SSL、TTFB、下载时间等性能指标
  • incomingHeader / outgoingHeader:可选,默认开启
  • incomingData / outgoingData:默认关闭,以减少额外开销

HTTP 拦截器接入

如果业务使用 @kit.NetworkKithttp.createHttp() 发起请求,可以通过 @guancecloud/ft_sdk_ext 提供的 HTTP 拦截器完成自动 Trace Header 注入和 Resource 采集。该接入方式自 0.1.14-alpha03 起支持,并要求 HarmonyOS API 22 及以上版本。

请先确保项目已安装:

  • ft_sdk.har,并在 oh-package.json5 中声明为 @guancecloud/ft_sdk
  • ft_sdk_ext.har,并在 oh-package.json5 中声明为 @guancecloud/ft_sdk_ext
  • 如果通过本地 HAR 安装 ft_sdk_ext.har,还需要在工程根目录的 oh-package.json5 中增加 overrides["@guancecloud/ft_sdk"] = "file:./libs/ft_sdk.har",将其内部依赖改写到本地 HAR

SDK 提供以下能力:

  • HttpInitialRequestInterceptor:在请求开始阶段注入 Trace Header,并启动 Resource
  • HttpFinalResponseInterceptor:在响应结束阶段补充 Resource 数据并结束采集
  • createFTHttpInterceptorChain():创建可复用的 http.HttpInterceptorChain
  • applyFTHttpTrack():将默认拦截器链直接挂载到单个 http.HttpRequest

提供两种接入方式。

方式一:使用 SDK 提供的默认工厂

import { http } from '@kit.NetworkKit';
import { createFTHttpInterceptorChain } from '@guancecloud/ft_sdk_ext/Index';

const request = http.createHttp();
const interceptorChain = createFTHttpInterceptorChain();
interceptorChain.apply(request);

try {
  const response = await request.request('https://httpbin.org/get', {
    method: http.RequestMethod.GET,
    header: {
      'Accept': 'application/json'
    }
  });
} finally {
  request.destroy();
}

如果希望继续追加业务自己的拦截器,也可以这样写:

import { http } from '@kit.NetworkKit';
import { createFTHttpInterceptorChain } from '@guancecloud/ft_sdk_ext/Index';

const request = http.createHttp();
const interceptorChain = createFTHttpInterceptorChain({
  interceptors: [
    new CustomAfterInterceptor()//追加自定义
  ]
});
interceptorChain.apply(request);

此时执行顺序为:

[
  new HttpInitialRequestInterceptor(),
  new HttpFinalResponseInterceptor(),
  new CustomAfterInterceptor()
]

方式二:手动装配 HttpInterceptorChain

如果业务本身已经有自定义拦截器,或者需要自由决定拦截器顺序,推荐直接手动创建 http.HttpInterceptorChain

import { http } from '@kit.NetworkKit';
import {
  HttpInitialRequestInterceptor,
  HttpFinalResponseInterceptor
} from '@guancecloud/ft_sdk_ext/Index';

const request = http.createHttp();
const interceptorChain = new http.HttpInterceptorChain();
interceptorChain.addChain([
  new CustomBeforeInterceptor(),
  new HttpInitialRequestInterceptor(),
  new HttpFinalResponseInterceptor()
]);
interceptorChain.apply(request);

注意事项:

  • HTTP 拦截器依赖 @kit.NetworkKit 在 API 22+ 提供的拦截器能力,低于 API 22 时请改用 RCP 或 Axios 兼容模式
  • 直接使用 http.createHttp() 的 HTTP 拦截器模式下,HttpRequestContext 当前无法稳定拿到真实请求方法,因此 Resource 中的 method 可能记录为 UNKNOWN
  • 如果业务使用 @ohos/axiosinterceptorChain 模式,建议额外挂载 applyFTAxiosChainMethodBridge(),用于桥接 axios 的真实 method、url 和 headers
  • @kit.NetworkKit 的拦截器回调暂不暴露 RCP timeInfo 级别的明细耗时,因此当前只会补充 resourceLoad

Axios 接入

如果业务使用 @ohos/axios,可按以下方式接入自动追踪:

  • @guancecloud/ft_sdk:基于 Axios request/response interceptors 的兼容模式
  • @guancecloud/ft_sdk_ext:自 0.1.14-alpha03 起提供基于 interceptorChain 的增强模式

@ohos/axios 2.2.4 及以上版本

该接入方式基于 Axios 的 request/response interceptors

import axios from '@ohos/axios';
import { applyFTAxiosTrack } from '@guancecloud/ft_sdk/Index';

const client = axios.create({
  timeout: 10000
});

applyFTAxiosTrack(client);

该接入方式可以与业务自己的拦截器共存使用:

import axios from '@ohos/axios';
import { applyFTAxiosTrack } from '@guancecloud/ft_sdk/Index';

const client = axios.create({
  timeout: 10000
});

applyFTAxiosTrack(client);

client.interceptors.request.use((config) => {
  config.headers = {
    ...(config.headers || {}),
    Authorization: 'Bearer <token>',
    'X-Signature': 'signed-value'
  };
  return config;
});

client.interceptors.response.use((response) => {
  return response;
});

执行次序说明:

  • @ohos/axios compat 模式下,request 拦截器表现为:后注册先执行
  • 这意味着多个 request interceptors 可以共存,但注册顺序会影响 FT 看到的是“修改前”还是“修改后”的请求头
  • 如果希望 FT 采集到业务补齐鉴权、签名等字段之后的最终请求头,推荐顺序是:applyFTAxiosTrack(client),再注册业务 request interceptor
  • 按上述顺序时,业务 request interceptor 会先执行,FT 随后执行并读取到最终的 headers
  • 如果希望调整次序,只需调整注册顺序;例如先注册业务、再调用 applyFTAxiosTrack(client) 时,FT 会先执行,业务拦截器后执行

@ohos/axios 2.2.8 及以上

对于 @ohos/axios 2.2.8 及以上版本,推荐优先通过 @guancecloud/ft_sdk_extinterceptorChain 接入 FT 自动追踪:

import axios from '@ohos/axios';
import {
  createFTHttpInterceptorChain,
  applyFTAxiosChainMethodBridge
} from '@guancecloud/ft_sdk_ext/Index';

const client = axios.create({
  timeout: 10000,
  interceptorChain: createFTHttpInterceptorChain()
});

applyFTAxiosChainMethodBridge(client);

const response = await client.post('https://api.example.com/data', {
  source: 'axios',
  message: 'ft auto track'
});

如果存在多个 interceptor 共存、需要手动调整执行次序,或者需要与业务自定义拦截器统一装配的场景,可以参考 HTTP 拦截器接入 中的内容,按需自行组合 HttpInitialRequestInterceptorHttpFinalResponseInterceptor

如果按单次请求传入,也可以这样写:

import axios from '@ohos/axios';
import { createFTHttpInterceptorChain } from '@guancecloud/ft_sdk_ext/Index';

const response = await axios.request({
  url: 'https://httpbin.org/post',
  method: 'post',
  data: {
    source: 'axios',
    message: 'ft auto track'
  },
  responseType: 'string',
  interceptorChain: createFTHttpInterceptorChain()
});

注意事项:

  • 推荐在创建 Axios 实例时统一注入 interceptorChain,并调用 applyFTAxiosChainMethodBridge(client),避免遗漏 bridge 导致 Resource method 记录不准确。
  • interceptorChain 模式依赖 @guancecloud/ft_sdk_ext(本地 HAR 文件名仍为 ft_sdk_ext.har),并要求 HarmonyOS API 22+
  • 如需自动注入 Trace Headers,除了创建拦截器链外,还需要在 Trace 配置中开启 setEnableAutoTrace(true)
  • 如需自动采集 Resource,仍需在 RUM 配置中开启 setEnableTraceUserResource(true)
  • 如果调用方已有自定义 HTTP/Axios 拦截器,推荐直接使用 HttpInitialRequestInterceptorHttpFinalResponseInterceptor 手动装配顺序,避免在 FT 自动追踪之后再次改写 urlmethodheaders
  • SDK 只提供拦截器和默认配置工厂函数,RCP Session 的创建和生命周期由业务自己管理
  • 如果业务直接使用 rcp.createSession() 创建 Session,需要自行添加 SDK 提供的拦截器,否则请求不会被自动追踪
  • 如果业务直接使用 http.createHttp()@ohos/axios,需要显式挂载 applyFTHttpTrack()applyFTAxiosTrack()createFTHttpInterceptorChain();Axios interceptorChain 模式还需要调用 applyFTAxiosChainMethodBridge(client)

Resource 性能指标说明

HarmonyOS SDK 通过 RCP(Remote Call Protocol)的 TimeInfo 接口获取网络请求的性能指标,包括 DNS、TCP、SSL、TTFB(Time To First Byte)等。

TTFB 计算说明:

  • HarmonyOS TTFB:使用 startTransferTimeMs - preTransferTimeMs 计算,包含服务器处理时间、网络传输时间和响应头接收时间
  • Android TTFB:仅表示响应头接收时间,通常很短

  • DNS 时间:nameLookupTimeMs

  • TCP 时间:connectTimeMs - nameLookupTimeMs
  • SSL 时间:tlsHandshakeTimeMs - connectTimeMs
  • TTFB:startTransferTimeMs - preTransferTimeMs
  • 下载时间:totalTimeMs - startTransferTimeMs

由于 HarmonyOS RCP API 的限制,preTransferTimeMs 几乎等于 SSL 完成时间,因此 HarmonyOS 的 TTFB 会包含服务器处理时间,导致其值通常比 Android 更大。这是预期的平台行为差异,并非 SDK 实现问题。

文档评价

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