API
SDK Configuration Options
import common from '@ohos.app.ability.common'
export enum LogLevel {
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
NONE
}
export type RecordRule = {
// Domain name/URL configuration required for this parameter. Only the target URL included in this configuration will be crawled. If this rule is not configured, it will apply to all URLs
url?: string
// Get all request headers, empty by default
reqHeaders?: string[]
// Request body configuration, empty by default
reqBody?: string[]
// Get all return headers, empty by default
resHeaders?: string[]
// Return body configuration, empty by default
resBody?: string[]
}
export type NetworkConfig = {
// Network request collection switch, default is false
enabled?: boolean
// Cross-application tracking switch, default is false
trackingEnabled?: boolean
// Collect header body switch, default is false
recordEnabled?: boolean
// Collect data whitelist
recordConfig?: RecordRule[]
// Data collection blacklist
recordBlockConfig?: RecordRule[]
// The truncated length of the collected body, in kilobytes (KB)
bodyMaxSize?: number
// Third-party apm request header support
apms?: string[]
// trace propagators
propagators?: string[]
// mPaaS switch, default is false
mPaaSEnabled?: boolean
// mPaaS configuration, by default, it is read from the mpaas.config file in the entry module's rawfile. Users can also manually configure it through this field, and the format of the input data is the same as the JSON format of mpaas.config. Note: Once this field is set, the mpaas.config file will no longer be read, and even if the manual configuration is invalid, it will not revert to the default behavior of reading the file
mPaaSConfig?: Record<string, string>
}
export type CrashConfig = {
// Crash collection master switch, default is true
enabled?: boolean
// JavaScript crash collection switch, default is true
jsCrashEnabled?: boolean
// cpp crash collection switch, default is true
cppCrashEnabled?: boolean
}
export type FreezeConfig = {
// Freeze monitoring switch, default is false
enabled?: boolean
}
export type LaunchWaitingPolicy = {
cold? : {
// Start the waiting time for time-consuming events, default is 30000ms
launchEvent?: number
// Ability lifecycle waiting time, default 10000ms
ability?: number
// Page lifecycle waiting time, default 15000ms
page?: number
},
hot? : {
// Startup time-consuming event waiting time, default 15000ms
launchEvent?: number
// Start the waiting time for time-consuming events, default is 10000ms
ability?: number
}
}
export type UserExperienceConfig = {
// Master switch, default is false
enabled?: boolean
// Enable monitoring switch, default to true
launchEnabled?: boolean
// Page monitoring switch, default is true
pageEnabled?: boolean
// Operate the monitoring switch, default is true
userActionEnabled?: boolean
// Use custom cold start time consumption end point, default is false
customLaunchEnd?: boolean
// Full trace collection switch, default is false
traceEnabled?: boolean
// Slow operation threshold, default 3000ms
slowUserActionThreshold?: number
// Slow start threshold, default 3000ms
slowLaunchThreshold?: number
// Hot start threshold, default 30s
hotStartThreshold?: number
// Slow interactive threshold, default 1000ms
slowPageLoadThreshold?: number
// Slow first screen threshold, default 3000ms
slowPageDurationThreshold?: number
// Initiate the waiting strategy for calculating startup time
launchWaitingPolicy?: LaunchWaitingPolicy
// The proportion of error requests identified as operational errors, defaulted to 100
actionFailureThreshold?: number
// Maximum startup time limit. If exceeded, do not report. Set to 0 to disable filtering. Default is 60000ms
maxLaunchDuration?: number
}
export type UserActionConfig = {
// Master switch, default is false
enabled?: boolean
}
export type WebviewConfig = {
// Master switch, default is false
enabled?: boolean
// Web SDK injection switch, default is true
webSdkEnabled?: boolean
// Inject jsProxy switch, default is true
jsProxyEnabled?: boolean
// JS fragment injection switch, default is true
jsSnippetEnabled?: boolean
// Web SDK data compression switch, default is false
// When the platform supports compression functionality, the backend can control whether to enable compression through the issued configuration switch. If manual configuration of the compression switch is required, it must be ensured that the backend platform actually supports this functionality
webSdkCompressEnabled?: boolean
}
export const ViewRecordQualities = {
// Extremely low quality
ULTRA_LOW: 0,
// Low quality
LOW: 1,
// High quality
HIGH: 2
} as const
export type RecordQuality = typeof ViewRecordQualities[keyof typeof ViewRecordQualities]
export const ViewRecordUploadTypes = {
// WIFI only
WIFI_ONLY: 0,
// WIFI and mobile network
WIFI_AND_MOBILE: 1
} as const
export type RecordUploadType = typeof ViewRecordUploadTypes[keyof typeof ViewRecordUploadTypes]
export type ViewRecordConfig = {
// Master switch, default to false
enabled?: boolean
// Upload type, default to WIFI only
uploadType?: RecordUploadType
// Image quality, default to very low quality
quality?: RecordQuality
// View collection data cache size for upload failure, in MB, default 10MB
maxCacheSize?: number
// Page mask configuration
pageBlacklist?: string[]
// Component id masking configuration
viewIdBlacklist?: string[]
}
export type EventConfig = {
// Violent click monitoring switch, default false
rageClickEnabled?: boolean
}
export type CommonConfig = {
// Whether to allow collecting the operating system version, default is true
osVersionEnabled?: boolean
// Whether to allow device manufacturers to be collected, default is true
manufacturerEnabled?: boolean
// Whether to allow collecting device model, default is true
manufacturerModelEnabled?: boolean
// Whether to allow the collection of operator information, default is true
carrierEnabled?: boolean
// Whether to allow screen resolution collection, default is true
displayResolutionEnabled?: boolean
}
/**
* Application configuration
*/
export type InitConfig = {
// Redirect server address
redirectHost: string
// Apply appKey
appKey: string
// Context
context: common.Context
// Log level, default to LogLevel.INFO
logLevel?: LogLevel
// Whether to use HTTP or HTTPS to send data. The default is false, indicating the use of HTTPS for sending
httpEnabled?: boolean
// axios object, it needs to be passed in when axios interception is required
axios?: any
// Maximum stack depth obtained, default 20
stackDepth?: number
// Whether to use historical data protocol for reporting (platforms 3.8.0.0 and below need to be set to true), default is false
legacyDataProtocol?: boolean
// Build ID
buildId?: string
// Whether to use asynchronous initialization for the internal logic of init, default is false
asyncInit?: boolean
// Whether to enable the national cryptographic encryption method for data uploading, default is false
encEnabled?: boolean
// Whether to enable data compression upload, default is true
compressEnabled?: boolean
// SDK request timeout, in ms, default 15000ms, minimum setting 3000ms, setting below minimum will fallback to default value
timeout?: number
// Plugin configuration
plugins?: Plugin[]
// Public configuration
common?: CommonConfig
// Network request collection configuration
network?: NetworkConfig
// Crash monitoring configuration
crash?: CrashConfig
// AppFreeze monitoring configuration
freeze?: FreezeConfig
// User experience configuration
ue?: UserExperienceConfig
// User behavior analysis configuration
ua?: UserActionConfig
// WebView configuration
webview?: WebviewConfig
// View collection configuration
viewRecord?: ViewRecordConfig
// Event configuration
event?: EventConfig
}
Instructions:
- The configuration passed in by init is the initial configuration of the SDK. After communication between the SDK and the server, the configuration issued by the server will take precedence
Plugins
| Plugin Name | Package Name |
|---|---|
| View Collection Plugin | @tingyun/sdk-plugin-record |
Note: For specific usage, please refer to the instruction manual of the corresponding plugin
SDK Startup Status Management
The SDK startup process is asynchronous, meaning that the SDK does not complete its startup immediately after calling tingyun.init. Some APIs can only be called after the SDK has finished starting up.
The SDK provides three APIs to manage the startup status:
isReady- Synchronously determines whether the SDK has been startedonReady- Register the callback for startup completionwaitForReady- asynchronously waits for startup to complete
isReady
Synchronously determine whether the SDK has been fully launched.
API:
export type Tingyun = {
/**
* Determine whether the SDK has been fully initialized
* @returns Whether the SDK has been started
*/
isReady: () => boolean
}
Usage:
import tingyun from '@tingyun/sdk-core'
if (tingyun.isReady()) {
// SDK has been initiated, and APIs that require a dependent startup status can be called
}
onReady
Callback function for the completion of SDK registration startup.
API:
export type SDKReadyResult = {
// Whether the SDK is in an enabled state after the startup process is completed
enabled: boolean
// Whether it is overdue
timeout?: boolean
// Prompt message after the startup process is completed
message?: string
}
export type SDKReadyOptions = {
// Wait timeout, in milliseconds, 0 indicates no timeout, default is 0
timeout?: number
}
export type SDKReadyCallback = (result: SDKReadyResult) => void
export type Tingyun = {
/**
* Callback function for the completion of SDK registration startup
* @param callback The callback to be executed when the SDK is fully initialized
* @param options Configuration options
*/
onReady: (callback: SDKReadyCallback, options?: SDKReadyOptions) => void
}
Usage:
import tingyun from '@tingyun/sdk-core'
tingyun.onReady(() => {
// SDK has been successfully launched, calling APIs that require a startup state
})
Instructions:
- If the SDK has already been initiated when
onReadyis called, the callback will be executed immediately - You can call
onReadymultiple times to register multiple callbacks
waitForReady
Asynchronously wait for the SDK to finish starting.
API:
export type Tingyun = {
/**
* Asynchronously wait for the SDK to finish starting
* @param options Configuration options
* @returns SDK startup result
*/
waitForReady: (options?: SDKReadyOptions) => Promise<SDKReadyResult>
}
Usage:
import tingyun from '@tingyun/sdk-core'
async function setupAfterInit() {
await tingyun.waitForReady()
// SDK has been fully initialized, calling APIs that rely on the initialization status
}
API Startup Dependency Instructions
APIs to be called after startup (with restrictions):
reportError- Custom errorstartAction/endAction- Custom actionstartSpan- Create an execution unitstartRequest/endRequest/createRequest- Custom requests
API without startup restrictions (can be called at any time):
It is recommended to call after startup:
getSessionId- Gets the session ID (calling before startup may return an empty string)setCustomLaunchTime- Set the custom end point for cold start time consumption (calling before startup may lead to inaccurate time consumption calculation)reportEvent- Custom event (up to 5 events can be cached before startup, exceeding events will be discarded)
It is recommended to call before starting:
setSessionIdleTime- Sets the session idle duration (recommended to call before init, and only takes effect on the first call)
No timing requirement for invocation:
setUserId- Set user IDsetCustomData- Set custom additional informationleaveBreadcrumb- Set breadcrumb datasetLatLon- Set latitude and longitudestartNextSession- Switch session
Instructions:
- If an API that needs to be called after startup is invoked before startup, it will be ignored and will not take effect. It is recommended to use
onReadyorwaitForReadyto ensure that the SDK has fully started before making the call
Network Request
Axios
The SDK supports network request collection using the @ohos/axios library. You can monitor axios using the following two methods:
- Pass in the axios instance when calling
tingyun.init
import tingyun from '@tingyun/sdk-core'
import axios from '@ohos/axios'
tingyun.init({
// Pass in the axios instance object
axios: axios
})
- Use
tingyun.registerAxiosInstanceto register an axios instance, and multiple instances can be registered
API definition:
export type Tingyun = {
registerAxiosInstance: (axiosInstance: AxiosInstance, options?: AxiosRegisterOptions) => void
}
export type AxiosRegisterOptions = {
// Do not wait for the network switch initialization to complete, immediately register the axios interceptor. By default, the axios interceptor will be registered after the network switch initialization is complete.
immediate?: boolean
}
Example:
import tingyun from '@tingyun/sdk-core'
import { axiosInstance1, axiosInstance2 } from './utils/axios'
// Regular registration (waiting for network switch initialization to complete)
tingyun.registerAxiosInstance(axiosInstance1)
// Register immediately (without waiting for network switch initialization to complete)
// Usage scenario: When users need to control the timing of interceptor injection and wish to inject the Tingyun interceptor in advance to ensure the execution order of interceptors, this option can be used
tingyun.registerAxiosInstance(axiosInstance2, { immediate: true })
// . ..
Instructions:
- Both methods can be used simultaneously, and the same axios instance will only be registered once
- Upon initial launch, the SDK turns off the network request switch by default. If you need to monitor network requests during the initial launch, you need to configure the network request switch to be true by default in
tingyun.init
tingyun.init({
network: {
enabled: true
}
})
- The
immediate: trueoption can be used to immediately insert interceptors, which is suitable for scenarios where users have specific requirements for the order of interceptors. When users need to control the timing of interceptor injection and wish to inject the Tingyun interceptor ahead of time to ensure the execution order of interceptors, this option can be used
RCP
The SDK supports monitoring of the RCP (remote communication platform) by providing interceptors. Users need to incorporate the interceptor provided by the SDK when calling createSession
import tingyun from '@tingyun/sdk-core'
const session = rcp.createSession({
// Other configurations ..
// Add interceptor
interceptors: [new tingyun.RCPInterceptor()]
})
SDK network request interface
The SDK encapsulates the HttpRequest.request interface of the system @ohos.net.http package, exposing the request interface to the outside world. Network requests sent by calling this interface will be collected by the SDK
API definition:
import http from '@ohos.net.http';
export type HttpRequestWrapperOptions = {
url: string
options?: http.HttpRequestOptions
// The request object returned by http.createHttp() will be created internally by the SDK if not passed. When no httpRequest is passed, the SDK will only synchronously call httpRequest.destroy after the user's callback is executed if the user has passed in a callback. When httpRequest is passed, the SDK will not call any other methods besides httpRequest.request. If you need to call other methods of httpRequest, control the destroy timing yourself, or use the promise method, you need to pass in httpRequest
httpRequest?: http.HttpRequest
}
export interface HttpRequestWrapper {
(options: HttpRequestWrapperOptions, callback: AsyncCallback<http.HttpResponse>): void
(options: HttpRequestWrapperOptions): Promise<http.HttpResponse>
}
export type Tingyun = {
// . ..
// HTTP request encapsulation
request: HttpRequestWrapper
}
Usage example: Example 1: Passing a URL (promise)
tingyun.request({url: 'xxx'})
.then((res) => {
// . ..
})
.catch((err) => {
// . ..
})
Example 2: Passing URL (callback)
tingyun.request({url: 'xxx'}, (err, res) => {
// . ..
})
Example 3: Passing URL and options (promise)
tingyun.request({url: 'xxx', options: {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json'
},
extraData: {
// . ..
}
}})
.then((res) => {
// . ..
})
.catch((err) => {
// . ..
})
Example 4: Passing URL and options (callback)
tingyun.request({url: 'xxx', options: {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json'
},
extraData: {
// . ..
}
}}, (err, res) => {
// . ..
})
Example 5: Using a custom request object
const httpRequest = http.createHttp()
tingyun.request({
url: 'xxx',
httpRequest: httpRequest
}, (err, res) => {
// . ..
})
Custom Request
To support some custom network request libraries used by users, the SDK provides a set of ArkTS layer APIs that can collect information about the network libraries collected by users themselves. To cater to various usage scenarios, two usage modes are provided:
-
Mode 1: The SDK API is called respectively at the time of request initiation and after the request ends. When the SDK API is called at the end of the request, it collects this network request
The first mode is further divided into two usage options:
- Before initiating a request, call
tingyun.startRequest, and after it ends, calltingyun.endRequest. Both calls pass a self-maintained request ID to associate with the same request. This method of invocation is flexible, but it requires manually maintaining a request ID to identify a request. If the existing request library provides a request ID or the code structure for initiating and ending requests is relatively decentralized, this method is suitable - Before initiating a request, call
tingyun.startRequestto obtain the request instance returned by the SDK. After the request is completed, call theendmethod of the request instance to terminate the request. This approach eliminates the need to manually maintain the request ID. However, when the code structure is complex, it may be necessary to manually pass the request instance object. If the logic for sending the request is relatively simple and can be completed within a single function, this approach is suitable
- Before initiating a request, call
-
Mode 2: After the request ends or at any time, call
tingyun.createRequestonce to report a complete set of network request data
Mode 1: startRequest / endRequest
API definition:
export type Tingyun = {
// Start custom request
startRequest: (options: RequestStartOptions) => IRequestInstance
// End custom request
endRequest: (options: RequestEndOptions) => void
}
export interface IRequestInstance {
end: (options?: RequestEndOptions) => void
clear: () => void
readonly id: string
}
export type RequestMethod = 'OPTIONS' | 'GET' | 'HEAD' | 'POST' | 'PUT' | 'DELETE' | 'TRACE' | 'CONNECT'
export type KeyValueStore<T> = Record<string, T> | Map<string, T>
export const LibNames = {
Flutter: 10,
OhosHttp: 13,
OhosAxios: 14,
OhosRCP: 15
} as const
export type LibName = typeof LibNames[keyof typeof LibNames]
export type RequestStartOptions = {
// Request URL
url: string
// Request ID: A unique identifier for the request. If not passed to the SDK, a UUID-formatted string will be automatically generated
id?: string
// Request start time: 13-digit millisecond timestamp. If not passed through the SDK, the interface call time point will be used as the starting point
startTime?: number
// method: GET by default
method?: RequestMethod
// Network library name
libName?: LibName
// Request header
reqHeaders?: KeyValueStore<string>
// Request body: Only text types are supported. If it is in JSON format, it needs to be serialized into a string before being passed in
reqBody?: string
// Number of bytes sent
bytesSent?: number
// Request object timeout cleanup time, in milliseconds: If endRequest is not called after a certain period of time since the request was initiated, the SDK will automatically cleanup the current request to free up resources. The default is 90000ms
timeout?: number
}
export type RequestEndOptions = {
// Request ID: Unique identifier for the request. It must be passed when using Tingyun.endRequest, but not when using the request instance object to end the request
id?: string
// HTTP status code
statusCode?: number
// Error code: The error code for network errors or other types of errors. It is not required to be transmitted when the request is successful or when an HTTP error (4xx, 5xx) occurs
errorCode?: number
// Request end time: 13-digit millisecond timestamp. If not passed through the SDK, the time point of the interface call will be used as the end point
endTime?: number
// Total request duration, in milliseconds: calculated using endTime - startTime if not provided
duration?: number
// DNS duration, in milliseconds: DNS end time - DNS start time
dns?: number
// Connection establishment time, in milliseconds: Connection establishment end time - Connection establishment start time
connect?: number
// SSL handshake time, in milliseconds: SSL handshake end time - SSL handshake start time
ssl?: number
// First packet, in milliseconds: End time of first packet - Start time of first packet
firstPacket?: number
// Remaining packets, in milliseconds: End time of remaining packets - Start time of remaining packets
remainPacket?: number
// Local queuing time, in milliseconds
localQueue?: number
// Number of bytes sent: This will overwrite the bytesSent passed in during startRequest
bytesSent?: number
// Number of received bytes
bytesReceived?: number
// Request the server IP of the target address
ip?: string
// Request headers: Will overwrite the reqHeaders passed in during startRequest
reqHeaders?: KeyValueStore<string>
// Request body: Only text types are supported. If it is in JSON format, it needs to be serialized into a string before being passed in. It will overwrite the reqBody passed in during startRequest
reqBody?: string
// Return header
resHeaders?: KeyValueStore<string>
// Return body: Only text-type return bodies are supported. If it is in JSON format, it needs to be serialized into a string before being passed in
resBody?: string
// Error message
errorMessage?: string
// Error stack
errorStack?: string
// Link tracing third-party APM request header
apms?: KeyValueStore<string>
// Contains the original return headers and values of Tingyun APM
tyApm?: KeyValueStore<string>
}
Example 1: Using startRequest/endRequest to customize the request ID
import tingyun from '@tingyun/sdk-core'
async function testRequest1() {
// Custom request ID
const reqId = genRequestId()
const url = 'https://example.com'
const method = 'POST'
const reqBody = {
key1: 1
}
const reqHeaders = {
'Content-Type': 'application/json;charset=UTF-8'
}
// Before starting the request, call startRequest to initiate the request
tingyun.startRequest({
id: reqId,
url: url,
method: method,
reqHeaders: reqHeaders,
reqBody: JSON.stringify(reqBody)
})
try {
// Call your own request library
const response = await callCustomHttpLib(url, {
method: method,
reqBody: reqBody,
reqHeaders: reqHeaders
})
// Request successful, call endRequest to end the request, passing the request ID that identifies the request
tingyun.endRequest({
id: reqId,
statusCode: response.statusCode,
resHeaders: response.headers,
resBody: response.body
})
} catch(e) {
// Request failed, call endRequest to end the request, passing the request ID that identifies the request
tingyun.endRequest({
id: reqId,
errorCode: e.code
})
}
}
Example 2: Using the request instance returned by startRequest to terminate the request
import tingyun from '@tingyun/sdk-core'
async function testRequest2() {
const url = 'https://example.com'
const method = 'POST'
const reqBody = {
key1: 1
}
const reqHeaders = {
'Content-Type': 'application/json;charset=UTF-8'
}
// Before starting the request, call startRequest to initiate the request and obtain the request instance
const requestInstance = tingyun.startRequest({
url: url,
method: method,
reqHeaders: reqHeaders,
reqBody: JSON.stringify(reqBody)
})
try {
// Call your own request library
const response = await callCustomHttpLib(url, {
method: method,
reqBody: reqBody,
reqHeaders: reqHeaders
})
// Request successful, use the end method of the request instance to terminate the request
requestInstance.end({
statusCode: response.statusCode,
resHeaders: response.headers,
resBody: response.body
})
} catch(e) {
// Request failed, use the end method of the request instance to terminate the request
requestInstance.end({
errorCode: e.code
})
}
}
Mode 2: createRequest
API definition:
export type Tingyun = {
createRequest: (options: RequestOptions) => void
}
// RequestStartOptions RequestEndOptions see above
export type RequestOptions = Omit<RequestStartOptions & RequestEndOptions, 'id' | 'timeout'>
Example:
async function testRequest3() {
const url = 'https://example.com'
const method = 'POST'
const reqBody = {
key1: 1
}
const reqHeaders = {
'Content-Type': 'application/json;charset=UTF-8'
}
// Set the start time
const startTime = Date.now()
let endTime
try {
// Call your own request library
const response = await callCustomHttpLib(url, {
method: method,
reqBody: reqBody,
reqHeaders: reqHeaders
})
// Set the end time
endTime = Date.now()
// Request successful, call createRequest to create a custom request
tingyun.createRequest({
url: url,
startTime: startTime,
endTime: endTime,
statusCode: response.statusCode,
reqHeaders: reqHeaders,
resHeaders: response.headers,
resBody: response.body
})
} catch(e) {
// Set the end time
endTime = Date.now()
// Request failed, call createRequest to create a custom request
tingyun.createRequest({
url: url,
startTime: startTime,
endTime: endTime,
errorCode: e.code
})
}
}
mPaaS Mobile Gateway Request
The SDK monitors mPaaS mobile gateway requests through interceptors, supporting both global registration and request-specific registration methods.
Global registration method
Applicable to scenarios where monitoring of all mPaaS requests is required:
import { MPFramework } from '@mpaas/framework';
import { MPRpc } from "@mpaas/rpc";
import tingyun from '@tingyun/sdk-core'
export default class MyAbilityStage extends AbilityStage {
onCreate(): void {
// Initialize the mPaaS framework (the following is just an example, the specific initialization method should be based on the actual project)
MPFramework.create(this.context);
// Globally register the tingyun interceptor
MPRpc.addGlobalInterceptor(new tingyun.MPaaSRPCInterceptor())
// Initialize the tingyun SDK
tingyun.init({
// Other configurations ..
network: {
// Other configurations ..
// Enable mPaaS mobile gateway request monitoring
mPaaSEnabled: true
}
})
}
}
Registration by request
Suitable for scenarios where only specific requests are monitored:
import tingyun from '@tingyun/sdk-core'
// You need to enable mPaaS monitoring in tingyun.init first
tingyun.init({
// Other configurations ..
network: {
// Other configurations ..
// Enable mPaaS mobile gateway request monitoring
mPaaSEnabled: true
}
})
// Register an interceptor in a specific request
MPRpc.executeRpc<string>(this, {
// Other configurations ..
// Register interceptor
interceptor: new tingyun.MPaaSRPCInterceptor()
})
User experience monitoring
registerUIContext (Deprecated)
Note: This interface has been deprecated. The new version of the SDK already supports automatic collection, eliminating the need to manually call this interface.
API definition:
export Tingyun = {
/**
* @deprecated Please use automatic collection; manual registration is no longer necessary
*/
registerUIContext(uiContext: UIContext)
}
Operation monitoring
The SDK supports collecting user click events
Usage:
Set the id attribute or add a custom attribute _ty_name on the component to be collected to set the operation name. The priority of the custom attribute is higher than that of the id
Example:
Button('clickTest')
// Set component ID
.id('<custom action name>')
// Custom attributes
.customProperty("_ty_name", "<Custom Action Name>")
.onClick(() => {
})
Custom Operation
API definition:
export type ActionStartOptions = {
// The key of the parent operation. If not passed, it is considered as the top-level operation
parent?: string
// Unique identifier for the event. If not provided, the name will be used as the unique identifier
key?: string
// Operation start time, timestamp in milliseconds, do not pass the call time
startTime?: number
}
export type ActionEndOptions = {
// Operation name
name?: string
// Unique identifier for the event. If not provided, the name will be used as the unique identifier
key?: string
// Operation end time, in milliseconds, not passing the call time
endTime?: number
// Custom tag
tag?: string
// Custom information
metaData?: KeyValueStore<ValueType>
}
export interface IActionInstance {
end: (options?: ActionEndOptions) => void
readonly key: string
readonly name: string
}
export type Tingyun = {
// Start user operation
startAction: (name: string, options?: ActionStartOptions) => IActionInstance
// End user operation
endAction: (options: ActionEndOptions) => void
}
Usage:
Example 1: Basic usage
// Start operation
const action = tingyun.startAction('action1')
// . ..
// End operation
action.end()
Example 2: Passing custom tags and additional information
// Start operation
const action = tingyun.startAction('action1')
// . ..
// End operation
action.end({
// tag
tag: 'tag1',
// Additional information
metaData: {
prop1: ''
}
})
Example 3: Customizing the start time and end time
// Start operation
const action = tingyun.startAction('action1', {
startTime: <13-digit millisecond timestamp>
})
// . ..
// End operation
action.end({
endTime: <13-digit millisecond timestamp>
})
Customize the end point of cold start duration
API definition:
export type CustomLaunchOptions = {
className?: string
}
export type Tingyun = {
// Set the custom cold start duration end point
setCustomLaunchTime: (options?: CustomLaunchOptions) => void
}
Usage:
- Set
customLaunchEndto true when the SDK starts
import tingyun from '@tingyun/sdk-core'
tingyun.init({
// . ..
ue: {
customLaunchEnd: true
}
})
- Call
tingyun.setCustomLaunchTimeat the end of cold start
import tingyun from '@tingyun/sdk-core'
tingyun.setCustomLaunchTime()
Webview data collection
The SDK provides the following APIs for Webview data collection:
export type Tingyun = {
// Register WebviewController
registerWebviewController: (controller: webview.WebviewController) => void
// Obtain the JS script to be injected
getWebScriptItem: (scriptRules?: string[]) => any
}
Native Webview
import tingyun from '@tingyun/sdk-core'
Web({ src: 'https://example.com', controller: this.controller })
// Ensure that both javaScriptAccess and domStorageAccess are in an enabled state
.javaScriptAccess(true)
.domStorageAccess(true)
.onControllerAttached(() => {
// Call tingyun.registerWebviewController in the onControllerAttached callback
tingyun.registerWebviewController(this.controller)
})
// Inject the JS code required for webview monitoring
.javaScriptOnDocumentStart([tingyun.getWebScriptItem()])
mPaaS Webview
mPaaS Webview integrates monitoring capabilities through customizing H5WebClientProvider.
- Implement a custom Provider
Example
import { H5WebClientProvider, Page } from '@mpaas/hriver'
import tingyun from '@tingyun/sdk-core'
export class H5WebClientProviderImpl extends H5WebClientProvider {
onPageBegin(page: Page | undefined, url: string | undefined): void {
const controller = page?.webcontroller
if (controller) {
try {
// Inject the tingyun web SDK and the JS code for collecting webview network requests
controller.runJavaScript(tingyun.getWebScriptItem().script)
} catch (e) {
console.error('Failed to inject Tingyun script:', e)
}
}
}
onControllerAttached(page: Page | undefined): void {
const controller = page?.webcontroller
if (controller) {
// Register jsBridge
tingyun.registerWebviewController(controller)
}
}
}
- Register Provider
HRiver.setProvider(H5WebClientProvider.name, new H5WebClientProviderImpl())
Custom Error
API:
export const ErrorTypes = {
// Custom error
CUSTOM: 1,
// Errors captured by SDK
CAPTURED: 2
} as const
export type ErrorType = typeof ErrorTypes[keyof typeof ErrorTypes]
export type ErrorInfo = {
// Stack
stack?: string
// Thread ID
threadId?: number
// Thread name
threadName?: string
}
export type KeyValueStore<T> = Record<string, T> | Map<string, T>
export type ValueType = string | number | boolean | object
export type ErrorOptions = {
// Error type, default to custom error
type?: ErrorType
// Error supplementary information
error?: ErrorInfo
// Additional information
metaData?: KeyValueStore<ValueType>
}
export type Tingyun = {
// Custom error
reportError: (message: string, options?: ErrorOptions) => void
}
Usage:
import tingyun from '@tingyun/sdk-core'
tingyun.reportError('<customError>')
Custom User Additional Information
API:
export type Tingyun = {
setCustomData: (key: string, message: string) => void
}
Usage:
import tingyun from '@tingyun/sdk-core'
tingyun.setCustomData('<key>', '<value>')
Custom breadcrumbs
API:
export type Tingyun = {
leaveBreadcrumb: (breadcrumb: string) => void
}
Usage:
import tingyun from '@tingyun/sdk-core'
tingyun.leaveBreadcrumb('<message>')
User ID
API:
export type Tingyun = {
setUserId: (userId: string) => void
}
Usage:
import tingyun from '@tingyun/sdk-core'
tingyun.setUserId('<userId>')
Instructions:
- If the user ID is set multiple times before the SDK initialization is complete, only the value set last time will be used
Conversation
Switch Session
API:
export type Tingyun = {
startNextSession: (sessionId?: string) => void
}
Usage:
import tingyun from '@tingyun/sdk-core'
tingyun.startNextSession()
Set session idle duration
API:
export type Tingyun = {
/**
* Set the session idle time. It is recommended to call before SDK initialization, and it will only take effect on the first call
* @param idleTime: Session idle time, measured in seconds. The minimum setting is 60. It can be set to a special value of 0, indicating that session idle duration will not be evaluated, and sessions will only be switched when the application exits or when startNextSession is called
*/
setSessionIdleTime: (idleTime: number) => void
}
Usage:
import tingyun from '@tingyun/sdk-core'
tingyun.setSessionIdleTime(<idle duration>)
Obtain session ID
API:
export type Tingyun = {
/**
* Obtain the session ID. If the session has not been initialized, return an empty string
* @returns
*/
getSessionId: () => string
}
Usage:
import tingyun from '@tingyun/sdk-core'
tingyun.getSessionId()
Latitude and longitude
API:
export type Tingyun = {
setLatLon: (latitude: number, longitude: number) => void
}
Usage:
import tingyun from '@tingyun/sdk-core'
tingyun.setLatLon(<latitude>, <longitude>)
Instructions:
- The valid values for latitude are [-90, 90]
- The valid range for longitude is [-180, 180]
- If one of the latitude and longitude values is invalid, the API call will be invalid
Protocol Extension
API:
export type Tingyun = {
/**
* Create an execution unit
* @param name: The name, which cannot be empty and has a length limit of 1024 characters. If it exceeds this limit, only the first 1024 characters will be retained
* @param operation: Data type, cannot be empty, length limited to 128 characters, exceeding will be truncated to the first 128 characters
* @returns
*/
startSpan: (name: string, operation: string) => ISpan
}
export interface ISpan {
/**
* Complete the execution unit
* @param status Execution status, defaults to SpanStatuses.OK
*/
finish: (status?: SpanStatus) => void
/**
* Create a sub-execution unit
* @param name Name, cannot be empty, length limit is 1024 characters, if exceeding, the first 1024 characters will be used
* @param operation: Data type, cannot be empty, length limited to 128 characters, exceeding will be truncated to the first 128 characters
* @param description Description information, with a length limit of 1024 characters. If it exceeds this limit, only the first 1024 characters will be retained
* @returns
*/
startChild: (name: string, operation: string, description?: string) => ISpan
/**
* Set Data
* @param key: The key of the data
* @param value: The value of the data
*/
setData: (key: string, value: Object) => void
/**
* Remove Data based on key
* @param key: The key of the data
*/
removeData: (key: string) => void
/**
* Set Tag data
* @param key: The key of the tag
* @param value: The value of the tag
*/
setTag: (key: string, value: string) => void
/**
* Remove Tag based on key
* @param key: The key of the tag
*/
removeTag: (key: string) => void
/**
* Set Metric data
* @param key: The key of the metric
* @param value: the value of the metric
* @param unit: The unit of the metric
*/
setMetric: (key: string, value: number, unit?: string) => void
/**
* Remove Metric based on key
* @param key: The key of the Metric
*/
removeMetric: (key: string) => void
/**
* Set execution status
* @param status
*/
setStatus: (status: SpanStatus) => void
/**
* Set the execution unit time consumption, in milliseconds
* @param duration
*/
setDuration: (duration: number) => void
/**
* Set status code
* @param code: Status code, defaults to "0"
*/
setStatusCode: (code: string) => void
}
export const SpanStatuses = {
UNKNOWN: 0,
OK: 1,
ERROR: -1
} as const
export type SpanStatus = typeof SpanStatuses[keyof typeof SpanStatuses]
// Predefined units
export const SpanMetricUnits = {
Bit: "b",
Byte: "B",
Kilobytes: "KB",
Megabytes: "MB",
Millisecond: "ms",
Second: "s",
Minute: "m",
Hour: "h",
Day: "d",
Bitps: "b/s",
Byteps: "B/s",
KBps: "KB/s",
MBps: "MB/s",
} as const
Usage:
import tingyun, {SpanStatuses} from '@tingyun/sdk-core'
const span = tingyun.startSpan('span_name', 'span_operation')
span.setData('dataKey', 'dataValue')
span.setTag('tagKey', 'tagValue')
span.setMetric('time', 50, SpanMetricUnits.Millisecond)
span.setDuration(100)
span.setStatus(SpanStatuses.OK)
span.setStatusCode('200')
const childSpan = span.startChild('child_span_name', 'child_span_operation')
childSpan.finish()
span.finish()
Custom Events
API:
export type EventAttributeValue = string | number | boolean | { [key: string]: EventAttributeValue } | EventAttributeValue[]
export type EventAttributes = Record<string, EventAttributeValue>
export type Tingyun = {
/**
* Report custom events
* @param name: Event name, with a maximum length of 1024. If it exceeds the maximum length, it will be truncated
* @param attributes: Event attributes, with a maximum total length of 128KB
*/
reportEvent: (name: string, attributes?: EventAttributes) => void
}
Usage:
import tingyun from '@tingyun/sdk-core'
tingyun.reportEvent('<eventName>', <attributes>)