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.DISCARD,DISCARD 为丢弃追加数据,DISCARD_OLDEST 丢弃老数据 |
RUM 手动采集¶
在 FTRUMConfig 配置 setEnableTraceUserAction、setEnableTraceUserView、setEnableTraceUserResource、setEnableTrackAppUIBlock、setEnableTrackAppCrash 和 setEnableTrackAppANR 来实现 Action、View、Resource、LongTask、Error 的自动采集。若需自定义采集,可通过 FTRUMGlobalManager 手动上报。
View¶
startView(viewName: string, property?: Record<string, object>): void
stopView(property?: Record<string, object>): void
updateLoadTime(loadTime: number): void
自动追踪:
在 RUM 配置中开启 enableTraceUserView 后,SDK 会自动追踪页面跳转,包括:
- 路由导航(
router.pushUrl、router.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) - 自动追踪会在页面切换时自动调用
startView和stopView,无需手动调用 - 如果使用条件渲染等场景,仍可手动调用
startView和stopView - 页面名称会自动从路由路径或
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.NetworkKitHttpInterceptorChain的增强模式,自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 HeadersRCPResourceInterceptor:自动采集Resource数据与性能指标createFTRCPInterceptors():返回默认 RCP 拦截器列表,便于与自定义SessionConfiguration合并createFTRCPTrackConfig():快速生成带默认拦截器和TracingConfiguration的SessionConfiguration
推荐接入方式:使用默认 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 根入口导入,也可以使用:
手动装配拦截器
如果需要完全控制 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.NetworkKit 的 http.createHttp() 发起请求,可以通过 @guancecloud/ft_sdk_ext 提供的 HTTP 拦截器完成自动 Trace Header 注入和 Resource 采集。该接入方式自 0.1.14-alpha03 起支持,并要求 HarmonyOS API 22 及以上版本。
请先确保项目已安装:
ft_sdk.har,并在oh-package.json5中声明为@guancecloud/ft_sdkft_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,并启动ResourceHttpFinalResponseInterceptor:在响应结束阶段补充Resource数据并结束采集createFTHttpInterceptorChain():创建可复用的http.HttpInterceptorChainapplyFTHttpTrack():将默认拦截器链直接挂载到单个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/axios的interceptorChain模式,建议额外挂载applyFTAxiosChainMethodBridge(),用于桥接 axios 的真实 method、url 和 headers @kit.NetworkKit的拦截器回调暂不暴露 RCPtimeInfo级别的明细耗时,因此当前只会补充resourceLoad
Axios 接入¶
如果业务使用 @ohos/axios,可按以下方式接入自动追踪:
@guancecloud/ft_sdk:基于 Axiosrequest/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/axioscompat 模式下,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_ext 的 interceptorChain 接入 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 拦截器接入 中的内容,按需自行组合 HttpInitialRequestInterceptor 和 HttpFinalResponseInterceptor。
如果按单次请求传入,也可以这样写:
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 导致Resourcemethod 记录不准确。 interceptorChain模式依赖@guancecloud/ft_sdk_ext(本地 HAR 文件名仍为ft_sdk_ext.har),并要求 HarmonyOS API 22+- 如需自动注入 Trace Headers,除了创建拦截器链外,还需要在 Trace 配置中开启
setEnableAutoTrace(true) - 如需自动采集
Resource,仍需在 RUM 配置中开启setEnableTraceUserResource(true) - 如果调用方已有自定义 HTTP/Axios 拦截器,推荐直接使用
HttpInitialRequestInterceptor、HttpFinalResponseInterceptor手动装配顺序,避免在 FT 自动追踪之后再次改写url、method或headers - SDK 只提供拦截器和默认配置工厂函数,RCP Session 的创建和生命周期由业务自己管理
- 如果业务直接使用
rcp.createSession()创建 Session,需要自行添加 SDK 提供的拦截器,否则请求不会被自动追踪 - 如果业务直接使用
http.createHttp()或@ohos/axios,需要显式挂载applyFTHttpTrack()、applyFTAxiosTrack()、createFTHttpInterceptorChain();AxiosinterceptorChain模式还需要调用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 实现问题。