Skip to content

RUM Configuration

This article covers the HarmonyOS RUM initialization configuration and manual collection capabilities.

RUM Initialization Configuration

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);
Method Type Required Description
setRumAppId string Yes RUM application ID, obtained from the [RUM] application
setSamplingRate number No RUM sampling rate, range [0.0, 1.0], default 1.0
setSessionErrorSampleRate number No Error sampling rate, range [0.0, 1.0], default 0.0
setEnableTraceUserAction boolean No Whether to enable automatic action tracing, default false
setEnableTraceUserView boolean No Whether to enable page tracing, default false
setEnableTraceUserResource boolean No Whether to enable resource tracing, default false
setEnableTrackAppUIBlock boolean No Whether to enable UI blocking detection, default false
setEnableTrackAppANR boolean No Whether to enable ANR monitoring, default false
setEnableTrackAppCrash boolean No Whether to enable APP crash monitoring, default false. For Native Crash, requires dependency on @guancecloud/ft_native
setEnableTraceWebView boolean No Whether to enable WebView data collection, default false. For complete integration, refer to WebView Data Monitoring
setRumCacheLimitCount number No RUM data cache limit count, default 100000, minimum 10000
setRumCacheDiscardStrategy RUMCacheDiscard No Sets the RUM data discard rule when the limit is reached, default is RUMCacheDiscard.DISCARD, DISCARD discards appended data, DISCARD_OLDEST discards oldest data

RUM Manual Collection

Configure setEnableTraceUserAction, setEnableTraceUserView, setEnableTraceUserResource, setEnableTrackAppUIBlock, setEnableTrackAppCrash, and setEnableTrackAppANR in FTRUMConfig to enable automatic collection of Action, View, Resource, LongTask, and Error. For custom collection, use FTRUMGlobalManager for manual reporting.

View

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

Automatic Tracing:

After enabling enableTraceUserView in the RUM configuration, the SDK automatically traces page navigation, including:

  • Route navigation (router.pushUrl, router.replaceUrl, etc.)
  • Navigation component switching
import { FTRUMGlobalManager } from '@guancecloud/ft_sdk/Index';

// Scenario 1
FTRUMGlobalManager.getInstance().startView('ProductPage');

// Scenario 2: Dynamic parameters
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);

// Scenario 1
FTRUMGlobalManager.getInstance().stopView();

// Scenario 2: Dynamic parameters
const stopViewProperty = new ViewProperty();
stopViewProperty.set('view_duration', 1000);
FTRUMGlobalManager.getInstance().stopView(stopViewProperty.toObject());

Notes:

  • Automatic tracing requires enabling enableTraceUserView(true) in the RUM configuration
  • Automatic tracing automatically calls startView and stopView during page transitions, no manual calls needed
  • For scenarios like conditional rendering, manual calls to startView and stopView are still possible
  • Page names are automatically extracted from route paths or Navigation component names

Action

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

// Scenario 1: Direct completion
FTRUMGlobalManager.getInstance().addAction('buy_button_click', 'click');

// Scenario 2: Dynamic parameters
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());

// Scenario 3: Start Action
FTRUMGlobalManager.getInstance().startAction('buy_button_click', 'click');

Automatic Tracing:

After enabling enableTraceUserAction in the RUM configuration, the SDK automatically traces click events on UI components. Adding customProperty to a Button component captures the button text:

Button('Buy Now')
  .id('buy-btn')
  .customProperty('buy-btn', 'Buy Now')
  .onClick(() => {
    // Click events are automatically traced
  })

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');

  // Scenario 1: Report custom Error
  FTRUMGlobalManager.getInstance().addCustomError(
    error.message,
    error.stack ?? '',
    errorProperty.toObject()
  );

  // Scenario 2: Specify Error type and application state
  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 unit is nanoseconds.

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

Automatic Tracing:

After enabling enableTraceUserResource in the RUM configuration, the SDK can automatically trace the following requests:

  • @guancecloud/ft_sdk: RCP and Axios compatibility mode
  • @guancecloud/ft_sdk_ext: Enhanced mode based on @kit.NetworkKit HttpInterceptorChain, supported since 0.1.14-alpha03, and requires 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 Automatic Tracing

After enabling enableTraceUserResource(true), the SDK automatically traces requests sent via RCP, Axios compatibility mode, or @kit.NetworkKit HTTP interceptors.

When integrating @guancecloud/ft_sdk_ext, it is recommended to uniformly import public APIs from @guancecloud/ft_sdk_ext/Index, avoiding deep paths like src/main/....

RCP Automatic Tracing Integration

After enabling enableTraceUserResource in the RUM configuration, the SDK automatically collects Resource data for HTTP requests sent via RCP.

Starting from the current version, the SDK no longer automatically creates or holds a global RCP Session. Instead, it provides the following capabilities for business to assemble themselves:

  • RCPTraceInterceptor: Automatically injects Trace Headers
  • RCPResourceInterceptor: Automatically collects Resource data and performance metrics
  • createFTRCPInterceptors(): Returns a default list of RCP interceptors, facilitating merging with custom SessionConfiguration
  • createFTRCPTrackConfig(): Quickly generates a SessionConfiguration with default interceptors and TracingConfiguration

Recommended Integration Method: Using the default SessionConfiguration factory function

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

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

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

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

If the project imports via the SDK root entry, you can also use:

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

Manual Assembly of Interceptors

If complete control over Session configuration is needed, you can also directly use the interceptors provided by the 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 Explanation:

  • collectTimeInfo: true: Recommended to enable. The SDK relies on response.timeInfo to calculate performance metrics such as DNS, TCP, SSL, TTFB, download time, etc.
  • incomingHeader / outgoingHeader: Optional, enabled by default
  • incomingData / outgoingData: Disabled by default to reduce additional overhead

HTTP Interceptor Integration

If the business uses @kit.NetworkKit's http.createHttp() to initiate requests, automatic Trace Header injection and Resource collection can be completed via the HTTP interceptor provided by @guancecloud/ft_sdk_ext. This integration method is supported since 0.1.14-alpha03 and requires HarmonyOS API 22 or higher.

First, ensure the project has installed:

  • ft_sdk.har, and declared as @guancecloud/ft_sdk in oh-package.json5
  • ft_sdk_ext.har, and declared as @guancecloud/ft_sdk_ext in oh-package.json5
  • If installing ft_sdk_ext.har via local HAR, also add overrides["@guancecloud/ft_sdk"] = "file:./libs/ft_sdk.har" to the project root's oh-package.json5 to rewrite its internal dependency to the local HAR

The SDK provides the following capabilities:

  • HttpInitialRequestInterceptor: Injects Trace Header at the request start stage and starts Resource
  • HttpFinalResponseInterceptor: Completes Resource data and ends collection at the response end stage
  • createFTHttpInterceptorChain(): Creates a reusable http.HttpInterceptorChain
  • applyFTHttpTrack(): Directly mounts the default interceptor chain to a single http.HttpRequest

Two integration methods are provided.

Method 1: Using the SDK-provided default factory

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();
}

If you wish to continue adding your own business interceptors, you can also write it like this:

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

const request = http.createHttp();
const interceptorChain = createFTHttpInterceptorChain({
  interceptors: [
    new CustomAfterInterceptor()//Add custom
  ]
});
interceptorChain.apply(request);

The execution order in this case is:

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

Method 2: Manually assembling HttpInterceptorChain

If the business already has custom interceptors or needs to freely decide the interceptor order, it is recommended to directly create http.HttpInterceptorChain manually:

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);

Notes:

  • HTTP interceptor relies on the interceptor capability provided by @kit.NetworkKit at API 22+. For versions below API 22, please switch to RCP or Axios compatibility mode.
  • In the HTTP interceptor mode using http.createHttp() directly, HttpRequestContext currently cannot stably obtain the real request method, so the method in Resource may be recorded as UNKNOWN.
  • If the business uses @ohos/axios's interceptorChain mode, it is recommended to additionally mount applyFTAxiosChainMethodBridge() to bridge axios's real method, url, and headers.
  • The interceptor callbacks of @kit.NetworkKit do not currently expose detailed timing like RCP timeInfo, so currently only resourceLoad will be supplemented.

Axios Integration

If the business uses @ohos/axios, automatic tracing can be integrated as follows:

  • @guancecloud/ft_sdk: Compatibility mode based on Axios request/response interceptors
  • @guancecloud/ft_sdk_ext: Enhanced mode based on interceptorChain provided since 0.1.14-alpha03

@ohos/axios version 2.2.4 and above

This integration method is based on Axios's request/response interceptors.

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

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

applyFTAxiosTrack(client);

This integration method can coexist with the business's own interceptors:

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;
});

Execution Order Explanation:

  • In @ohos/axios compat mode, request interceptors behave as: last registered, first executed
  • This means multiple request interceptors can coexist, but the registration order affects whether FT sees the "before modification" or "after modification" request headers
  • If you want FT to collect the final request headers after business supplements authentication, signature, and other fields, the recommended order is: first applyFTAxiosTrack(client), then register business request interceptor
  • With the above order, the business request interceptor executes first, FT executes subsequently and reads the final headers
  • If you want to adjust the order, simply adjust the registration order; for example, when registering business first and then calling applyFTAxiosTrack(client), FT executes first, and the business interceptor executes later

@ohos/axios 2.2.8 and above

For @ohos/axios 2.2.8 and above, it is recommended to prioritize integrating FT automatic tracing via interceptorChain from @guancecloud/ft_sdk_ext:

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'
});

If multiple interceptors coexist, requiring manual adjustment of execution order, or scenarios requiring unified assembly with business custom interceptors, refer to the content in HTTP Interceptor Integration and combine HttpInitialRequestInterceptor and HttpFinalResponseInterceptor as needed.

If passing per request, you can also write:

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()
});

Notes:

  • It is recommended to uniformly inject interceptorChain when creating the Axios instance and call applyFTAxiosChainMethodBridge(client) to avoid missing the bridge causing inaccurate Resource method recording.
  • The interceptorChain mode relies on @guancecloud/ft_sdk_ext (local HAR file name is still ft_sdk_ext.har) and requires HarmonyOS API 22+.
  • For automatic injection of Trace Headers, besides creating the interceptor chain, setEnableAutoTrace(true) must also be enabled in the Trace configuration.
  • For automatic collection of Resource, setEnableTraceUserResource(true) must still be enabled in the RUM configuration.
  • If the caller already has custom HTTP/Axios interceptors, it is recommended to directly use HttpInitialRequestInterceptor, HttpFinalResponseInterceptor to manually assemble the order, avoiding rewriting url, method, or headers again after FT automatic tracing.
  • The SDK only provides interceptors and default configuration factory functions; the creation and lifecycle of the RCP Session are managed by the business itself.
  • If the business directly uses rcp.createSession() to create a Session, it needs to add the interceptors provided by the SDK itself; otherwise, requests will not be automatically traced.
  • If the business directly uses http.createHttp() or @ohos/axios, it needs to explicitly mount applyFTHttpTrack(), applyFTAxiosTrack(), createFTHttpInterceptorChain(); Axios interceptorChain mode also requires calling applyFTAxiosChainMethodBridge(client).

Resource Performance Metrics Explanation

The HarmonyOS SDK obtains network request performance metrics, including DNS, TCP, SSL, TTFB (Time To First Byte), etc., through RCP's (Remote Call Protocol) TimeInfo interface.

TTFB Calculation Explanation:

  • HarmonyOS TTFB: Calculated using startTransferTimeMs - preTransferTimeMs, includes server processing time, network transmission time, and response header reception time
  • Android TTFB: Only represents response header reception time, usually very short

  • DNS time: nameLookupTimeMs

  • TCP time: connectTimeMs - nameLookupTimeMs
  • SSL time: tlsHandshakeTimeMs - connectTimeMs
  • TTFB: startTransferTimeMs - preTransferTimeMs
  • Download time: totalTimeMs - startTransferTimeMs

Due to limitations of the HarmonyOS RCP API, preTransferTimeMs is almost equal to the SSL completion time. Therefore, HarmonyOS's TTFB includes server processing time, causing its value to typically be larger than Android's. This is an expected platform behavior difference, not an SDK implementation issue.

Feedback

Is this page helpful? ×