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);
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, number |
否 | 是否开启 UI 卡顿检测,默认为 false。第二个参数 blockDurationMs 用于控制检测时间范围 [100,),单位毫秒,默认 1000ms |
setEnableTrackAppANR |
boolean |
否 | 是否开启 ANR 监控,默认 false |
setEnableTrackAppCrash |
boolean |
否 | 是否开启 APP 崩溃监控,默认 false。如需 Native Crash,需依赖 @guancecloud/ft_native |
setEnableTraceWebView |
boolean |
否 | 是否开启 WebView 数据采集,默认 false。如需完整接入,请参考 WebView 数据监测 |
setAllowWebViewHost |
Array<string> \| null |
否 | 设置允许 WebView JavaScript Bridge 使用的 Host 白名单。传入 null 或空数组时不限制 Host;如需限制,请参考 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¶
使用方法¶
/**
* 开始 View 生命周期。
*
* @param viewName View 名称。
* @param property 可选的扩展属性。
*/
startView(viewName: string, property?: Record<string, object>): Promise<void>
/**
* 结束当前 View 生命周期。
*
* @param property 可选的扩展属性。
*/
stopView(property?: Record<string, object>): Promise<void>
/**
* 更新当前 View 的加载耗时。
*
* @param loadTime 加载耗时,单位为纳秒。
*/
updateLoadTime(loadTime: number): void
代码示例¶
import { FTRUMGlobalManager } from '@guancecloud/ft_sdk/Index';
@Entry
@Component
struct ProductPage {
async aboutToAppear() {
// 场景 1:
await FTRUMGlobalManager.getInstance().startView('ProductPage');
// 场景 2:带扩展属性时
const viewProperty: Record<string, object> = { page_category: new String('product'), page_id: new String('12345') };
await FTRUMGlobalManager.getInstance().startView('ProductPage', viewProperty);
}
async aboutToDisappear() {
// 场景 1:
await FTRUMGlobalManager.getInstance().stopView();
// 场景 2:
const stopViewProperty: Record<string, object> = { view_duration: new Number(1000) };
await FTRUMGlobalManager.getInstance().stopView(stopViewProperty);
}
build() {
Column() {
Text('Product Page');
}
}
}
Action¶
使用方法¶
/**
* 添加已完成的 Action;该数据不会关联 Error、Resource、LongTask。
*
* @param actionName Action 名称。
* @param actionType Action 类型,例如 `click`。
* @param durationOrProperty 可选。传入 number 时表示持续时间(纳秒);传入 Record 时表示扩展属性。
* @param property 可选。仅当第三个参数为持续时间时传入扩展属性。
*/
addAction(
actionName: string,
actionType: string,
durationOrProperty?: number | Record<string, object>,
property?: Record<string, object>
): void
/**
* 开始 Action;SDK 会管理结束时机,并关联附近发生的 Resource、LongTask、Error 数据。
*
* @param actionName Action 名称。
* @param actionType Action 类型,例如 `click`。
* @param property 可选的扩展属性。
*/
startAction(
actionName: string,
actionType: string,
property?: Record<string, object>
): void
addAction(...) 用于直接完成的 Action,不能关联 Error、Resource、LongTask 等数据。duration 的单位为纳秒:第三个参数可直接传扩展属性;如需同时传入时长和扩展属性,则依次作为第三、第四个参数传入。
startAction(...) 会由 SDK 管理结束时机及关联数据,暂不提供 stopAction(...)、等待状态等手动控制接口。
代码示例¶
import { FTRUMGlobalManager } from '@guancecloud/ft_sdk/Index';
// 场景 1:
FTRUMGlobalManager.getInstance().addAction('buy_button_click', 'click');
// 场景 2: 带扩展属性
const actionProperty: Record<string, object> = {
product_id: new String('product_id'),
product_name: new String('product_name')
};
FTRUMGlobalManager.getInstance().addAction('buy_button_click', 'click', actionProperty);
// 场景 1:
FTRUMGlobalManager.getInstance().startAction('buy_button_click', 'click');
// 场景 2: 带扩展属性
const startActionProperty: Record<string, object> = {
product_id: new String('product_id'),
product_name: new String('product_name')
};
FTRUMGlobalManager.getInstance().startAction('buy_button_click', 'click', startActionProperty);
Error¶
使用方法¶
/**
* 上报 Error。
*
* @param log 错误日志或堆栈信息。
* @param message 消息。
* @param errorType 错误类型,可传入 `ErrorType` 枚举或字符串。
* @param state 错误发生时的应用运行状态。
* @param property 可选的扩展属性。
*/
addError(
log: string,
message: string,
errorType: string | ErrorType,
state: AppState,
property?: Record<string, object> | null
): void
/**
* 上报指定发生时间的 Error。
*
* @param log 错误日志或堆栈信息。
* @param message 消息。
* @param dateline 错误发生时间,单位为纳秒。
* @param errorType 错误类型,可传入 `ErrorType` 枚举或字符串。
* @param state 错误发生时的应用运行状态。
* @param property 可选的扩展属性。
*/
addError(
log: string,
message: string,
dateline: number,
errorType: string | ErrorType,
state: AppState,
property?: Record<string, object> | null
): void
自定义 Error 请使用 ErrorType.CUSTOM。dateline 为可选的发生时间,单位为纳秒;
代码示例¶
import { FTRUMGlobalManager, ErrorType, AppState } from '@guancecloud/ft_sdk/Index';
import { systemDateTime } from '@kit.BasicServicesKit';
// 场景 1:
FTRUMGlobalManager.getInstance().addError('error log', 'error message', ErrorType.CUSTOM, AppState.RUN);
// 场景 2:延迟上报时,传入错误实际发生的时间(单位:纳秒)。
const errorTimeNs = systemDateTime.getTime(true);
FTRUMGlobalManager.getInstance().addError('error log', 'error message', errorTimeNs, ErrorType.CUSTOM, AppState.RUN);
// 场景 3:带扩展属性。
const errorProperty: Record<string, object> = {
module: new String('checkout'),
action: new String('submit_order')
};
FTRUMGlobalManager.getInstance().addError('error log', 'error message', ErrorType.CUSTOM, AppState.RUN, errorProperty);
LongTask¶
使用方法¶
/**
* 上报 LongTask。
*
* @param log 卡顿时的日志或堆栈信息。
* @param duration 卡顿持续时间,单位为纳秒。
* @param property 可选的扩展属性。
*/
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';
// 场景 1:
FTRUMGlobalManager.getInstance().addLongTask(stack, durationNs);
// 场景 2:带扩展属性。
const longTaskProperty: Record<string, string | number | boolean> = {
module: 'checkout',
operation: 'render_order_list',
threshold_ms: 200
};
FTRUMGlobalManager.getInstance().addLongTask(stack, durationNs, longTaskProperty);
Resource¶
使用方法¶
/**
* 开始 Resource 生命周期。
*
* @param resourceId 资源唯一标识;需要与 `stopResource`、`addResource` 使用相同的值。
* @param property 可选的扩展属性。
*/
startResource(resourceId: string, property?: Record<string, object>): void
/**
* 结束 Resource 生命周期。
*
* @param resourceId 资源唯一标识;应与 `startResource` 使用相同的值。
* @param property 可选的扩展属性。
*/
stopResource(resourceId: string, property?: Record<string, object>): void
/**
* 补充 Resource 的请求、响应和网络性能数据。
*
* @param resourceId 资源唯一标识;应与 `startResource`、`stopResource` 使用相同的值。
* @param resourceParams 资源详情,如 URL、请求方式、响应状态、响应长度和扩展属性。
* @param netStatusBean 网络性能数据,如 DNS、TCP、TTFB 和响应耗时。
*/
addResource(resourceId: string, resourceParams: ResourceParams, netStatusBean: NetStatusBean): void
startResource(...)、stopResource(...) 传入的扩展属性会与 ResourceParams 中的属性按调用顺序合并。资源状态码和响应长度请通过 ResourceParams 设置,不再作为 stopResource(...) 的参数传入。
代码示例¶
import {
FTRUMGlobalManager,
ResourceParams,
NetStatusBean
} from '@guancecloud/ft_sdk/Index';
const resourceId = 'https://api.example.com/data';
// 场景 1:
// 请求开始
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);
// 场景 2:带扩展属性。以下为独立请求,使用时替换场景 1 的 startResource 和 stopResource 调用。
const startResourceProperty: Record<string, object> = {
request_source: new String('checkout')
};
FTRUMGlobalManager.getInstance().startResource(resourceId, startResourceProperty);
const stopResourceProperty: Record<string, object> = {
response_cache: new Boolean(false)
};
FTRUMGlobalManager.getInstance().stopResource(resourceId, stopResourceProperty);
NetStatusBean 属性说明¶
NetStatusBean 用于补充手动 Resource 采集的网络性能数据。所有时间参数单位均为纳秒,*StartTime 表示相对于 Resource 开始时刻的偏移;未设置的时间值默认为 -1,不会写入对应指标。
| 方法 | 说明 |
|---|---|
setDNSTime |
DNS 解析耗时 |
setDNSStartTime |
DNS 解析开始偏移 |
setTcpTime |
TCP 建连耗时 |
setConnectStartTime |
TCP 建连开始偏移 |
setSSLTime |
SSL/TLS 握手耗时 |
setSslStartTime |
SSL/TLS 握手开始偏移 |
setTTFB |
首字节到达前的等待耗时(TTFB) |
setResponseTime |
响应传输耗时 |
setFirstByteTime |
首字节阶段耗时 |
setFirstByteStartTime |
首字节阶段开始偏移 |
setDownloadTime |
响应下载耗时 |
setDownloadTimeStart |
响应下载开始偏移 |
setHoleRequestTime |
整个请求耗时(API 名称按 SDK 定义保留 Hole 拼写) |
setResourceHostIP |
资源服务端 IP 地址 |
Resource 自动追踪¶
开启 setEnableTraceUserResource(true) 后,SDK 会自动追踪通过 RCP、Axios 兼容模式或 @kit.NetworkKit HTTP 拦截器发送的请求。
业务接入 @guancecloud/ft_sdk_ext 时,建议统一从 @guancecloud/ft_sdk_ext/Index 导入公开 API,避免使用 src/main/... 深路径。
RCP 自动追踪接入¶
在 RUM 配置中开启 setEnableTraceUserResource 后,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 实现问题。