API
SDK配置选项
import common from '@ohos.app.ability.common'
export enum LogLevel {
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
NONE
}
export type RecordRule = {
// 需要采集此参数的域名/URL配置。目标URL包含于这项配置才会采集,如果不配置本条规则会对所有URL生效
url?: string
// 获取全部请求头, 默认空
reqHeaders?: string[]
// 请求体配置, 默认空
reqBody?: string[]
// 获取全部返回头, 默认空
resHeaders?: string[]
// 返回体配置, 默认空
resBody?: string[]
}
export type NetworkConfig = {
// 网络请求采集开关, 默认false
enabled?: boolean
// 跨应用追踪开关, 默认false
trackingEnabled?: boolean
// 采集header body开关, 默认false
recordEnabled?: boolean
// 采集数据白名单
recordConfig?: RecordRule[]
// 采集数据黑名单
recordBlockConfig?: RecordRule[]
// 采集的body截断长度, 单位KB
bodyMaxSize?: number
// 第 三方apm请求头支持
apms?: string[]
// trace propagators
propagators?: string[]
// mPaaS开关, 默认false
mPaaSEnabled?: boolean
// mPaaS配置, 默认从entry模块rawfile中的mpaas.config文件中读取, 用户也可以通过此字段手动配置, 传入数据格式同mpaas.config的JSON格式。注意: 一旦设置此字段,将不再读取mpaas.config文件,即使手动配置不合法也不会回退到读取文件的默认行为
mPaaSConfig?: Record<string, string>
}
export type CrashConfig = {
// 崩溃采集总开关, 默认true
enabled?: boolean
// js崩溃采集开关, 默认true
jsCrashEnabled?: boolean
// cpp崩溃采集开关, 默认true
cppCrashEnabled?: boolean
}
export type FreezeConfig = {
// 卡死监控开关, 默认false
enabled?: boolean
}
export type LaunchWaitingPolicy = {
cold?: {
// 启动耗时事件等待时间, 默认30000ms
launchEvent?: number
// ability生命周期等待时间, 默认10000ms
ability?: number
// page生命周期等待时间, 默认15000ms
page?: number
},
hot?: {
// 启动耗时事件等待时间, 默认15000ms
launchEvent?: number
// 启动耗时事件等待时间, 默认10000ms
ability?: number
}
}
export type UserExperienceConfig = {
// 总开关, 默认false
enabled?: boolean
// 启动监控开关, 默认true
launchEnabled?: boolean
// 页面监控开关, 默认true
pageEnabled?: boolean
// 操作监控开关, 默认true
userActionEnabled?: boolean
// 使用自定义冷启动耗时结束点, 默认false
customLaunchEnd?: boolean
// 全量trace采集开关, 默认false
traceEnabled?: boolean
// 慢操作阈值, 默认3000ms
slowUserActionThreshold?: number
// 慢启动阈值, 默认3000ms
slowLaunchThreshold?: number
// 热启动阈值, 默认30s
hotStartThreshold?: number
// 慢可交互阈值, 默认1000ms
slowPageLoadThreshold?: number
// 慢首屏阈值, 默认3000ms
slowPageDurationThreshold?: number
// 启动耗时计算等待策略
launchWaitingPolicy?: LaunchWaitingPolicy
// 判断为操作错误的错误请求占比, 默认100
actionFailureThreshold?: number
// 启动耗时上限, 超过则不上报, 设置为0则不过滤, 默认60000ms
maxLaunchDuration?: number
}
export type UserActionConfig = {
// 总开关, 默认false
enabled?: boolean
}
export type WebviewConfig = {
// 总开关, 默认false
enabled?: boolean
// web sdk注入开关, 默认true
webSdkEnabled?: boolean
// 注入jsProxy开关, 默认true
jsProxyEnabled?: boolean
// JS片段注入开关, 默认true
jsSnippetEnabled?: boolean
// web sdk数据压缩开关, 默认false
// 当平台支持压缩功能时,后端可以通过下发的配置开关控制是否启用压缩,如需手动配置压缩开关,必须确保后端平台实际支持该功能
webSdkCompressEnabled?: boolean
}
export const ViewRecordQualities = {
// 极低质量
ULTRA_LOW: 0,
// 低质量
LOW: 1,
// 高质量
HIGH: 2
} as const
export type RecordQuality = typeof ViewRecordQualities[keyof typeof ViewRecordQualities]
export const ViewRecordUploadTypes = {
// 仅WIFI
WIFI_ONLY: 0,
// WIFI和移动网络
WIFI_AND_MOBILE: 1
} as const
export type RecordUploadType = typeof ViewRecordUploadTypes[keyof typeof ViewRecordUploadTypes]
export type ViewRecordConfig = {
// 总开关, 默认false
enabled?: boolean
// 上传类型, 默认为仅WIFI
uploadType?: RecordUploadType
// 图像质量, 默认为极低质量
quality?: RecordQuality
// 上传失败视图采集数据缓存大小, 单位MB, 默认10MB
maxCacheSize?: number
// 页面遮罩配置
pageBlacklist?: string[]
// 组件id遮罩配置
viewIdBlacklist?: string[]
}
export type EventConfig = {
// 暴力点击监控开关, 默认false
rageClickEnabled?: boolean
}
export type CommonConfig = {
// 是否允许采集操作系统版本, 默认true
osVersionEnabled?: boolean
// 是否允许采集设备厂商, 默认true
manufacturerEnabled?: boolean
// 是否允许采集设备型号, 默认true
manufacturerModelEnabled?: boolean
// 是否允许采集运营商信息, 默认true
carrierEnabled?: boolean
// 是否允许屏幕分辨率采集, 默认true
displayResolutionEnabled?: boolean
}
/**
* 应用配置
*/
export type InitConfig = {
// redirect服务器地址
redirectHost: string
// 应用appKey
appKey: string
// 上下文
context: common.Context
// 日志级别, 默认LogLevel.INFO
logLevel?: LogLevel
// 数据是否使用http发送数据, 默认false, 使用https发送
httpEnabled?: boolean
// axios对象, 需要拦截axios时需要传入
axios?: any
// 最大获取的栈深度, 默认20
stackDepth?: number
// 是否使用历史数据协议上报(平台3.8.0.0和以下版本平台需要设置为true),默认false
legacyDataProtocol?: boolean
// 构建ID
buildId?: string
// init内部部分逻辑是否采用异步初始化, 默认false
asyncInit?: boolean
// 是否启用国密加密方式上传数据, 默认false
encEnabled?: boolean
// 是否开启数据压缩上传, 默认true
compressEnabled?: boolean
// SDK请求超时时间, 单位ms, 默认15000ms, 最小设置3000ms, 设置低于最小值将回退为默认值
timeout?: number
// 插件配置
plugins?: Plugin[]
// 公共配置
common?: CommonConfig
// 网络请求采集配置
network?: NetworkConfig
// Crash监控配置
crash?: CrashConfig
// AppFreeze监控配置
freeze?: FreezeConfig
// 用户 体验配置
ue?: UserExperienceConfig
// 用户行为分析配置
ua?: UserActionConfig
// webview配置
webview?: WebviewConfig
// 视图采集配置
viewRecord?: ViewRecordConfig
// 事件配置
event?: EventConfig
}
说明:
- init传入的配置为SDK初始配置,在SDK与服务端通信后会优先以服务端下发的配置为准
插件
| 插件名称 | 包名 |
|---|---|
| 视图采集插件 | @tingyun/sdk-plugin-record |
注:具体使用方式请参考对应插件的说明文档
SDK启动状态管理
SDK启动流程为异步,调用tingyun.init后SDK并未立即完成启动。部分API需要在SDK启动完成后才能调用。
SDK提供了三个API来管理启动状态:
isReady- 同步判断SDK是否已启动onReady- 注册启动完成回调waitForReady- 异步等待启动完成
isReady
同步判断SDK是否已启动完成。
API:
export type Tingyun = {
/**
* 判断SDK是否已经启动完成
* @returns SDK是否已启动
*/
isReady: () => boolean
}
使用方式:
import tingyun from '@tingyun/sdk-core'
if (tingyun.isReady()) {
// SDK已启动,可以调用需要依赖启动状态的API
}
onReady
注册SDK启动完成的回调函数。
API:
export type SDKReadyResult = {
// 启动流程结束后SDK是否是启用状态
enabled: boolean
// 是否超时
timeout?: boolean
// 启动流程结束后的提示信息
message?: string
}
export type SDKReadyOptions = {
// 等待超时时间, 单位毫秒, 0表示无超时时间, 默认为0
timeout?: number
}
export type SDKReadyCallback = (result: SDKReadyResult) => void
export type Tingyun = {
/**
* 注册SDK启动完成的回调函数
* @param callback SDK启动完成时执行的回调
* @param options 配置选项
*/
onReady: (callback: SDKReadyCallback, options?: SDKReadyOptions) => void
}
使用方式:
import tingyun from '@tingyun/sdk-core'
tingyun.onReady(() => {
// SDK已启动完成,调用需要依赖启动状态的API
})
说明:
- 如果调用
onReady时SDK已经启动完成,回调会立即执行 - 可以多次调用
onReady注册多个回调
waitForReady
异步等待SDK启动完成。
API:
export type Tingyun = {
/**
* 异步等待SDK启动完成
* @param options 配置选项
* @returns SDK启动结果
*/
waitForReady: (options?: SDKReadyOptions) => Promise<SDKReadyResult>
}
使用方式:
import tingyun from '@tingyun/sdk-core'
async function setupAfterInit() {
await tingyun.waitForReady()
// SDK已启动完成,调用需要依赖启动状态的API
}
API启动依赖说明
需要在启动后调用的API(有限制):
reportError- 自定义错误startAction/endAction- 自定义操作startSpan- 创建执行单元startRequest/endRequest/createRequest- 自定义请求
无启动限制的API(可随时调用):
建议在启动后调用:
getSessionId- 获取会话ID(启动前调用可能返回空字符串)setCustomLaunchTime- 设置自定义冷启动耗时结束点(启动前调用可能导致耗时计算不准确)reportEvent- 自定义事件(启动前最多缓存5条,超出将被丢弃)
建议在启动前调用:
setSessionIdleTime- 设置会话闲置时长(建议在init前调用,仅首次调用生效)
无调用时机要求:
setUserId- 设置用户IDsetCustomData- 设置自定义附加信息leaveBreadcrumb- 设置面包屑数据setLatLon- 设置经纬度startNextSession- 切换会话
说明:
- 需要在启动后调用的API如果在启动前调用,将被忽略且不会生效,建议使用
onReady或waitForReady确保SDK启动 完成后再调用
网络请求
Axios
SDK支持@ohos/axios库网络请求采集, 可以使用下面2种方式监控axios:
-
tingyun.init时传入axios实例import tingyun from '@tingyun/sdk-core'
import axios from '@ohos/axios'
tingyun.init({
// 传入axios实例对象
axios: axios
}) -
使用
tingyun.registerAxiosInstance注册axios实例, 可以注册多个实例API定义:
export type Tingyun = {
registerAxiosInstance: (axiosInstance: AxiosInstance, options?: AxiosRegisterOptions) => void
}
export type AxiosRegisterOptions = {
// 不等待网络开关初始化完成, 立即注册axios拦截器。默认情况下, 会等待网络开关初始化完成后再注册axios拦截器。
immediate?: boolean
}示例:
import tingyun from '@tingyun/sdk-core'
import { axiosInstance1, axiosInstance2 } from './utils/axios'
// 普通注册(等待网络开关初始化完成)
tingyun.registerAxiosInstance(axiosInstance1)
// 立即注册(不等待网络开关初始化完成)
// 使用场景:当用户需要控制拦截器注入时机,希望提前 注入听云拦截器以确保拦截器执行顺序时,可以使用此选项
tingyun.registerAxiosInstance(axiosInstance2, { immediate: true })
// ...
说明:
- 两种方式可以同时使用, 相同axios实例只会被注册一次
- 首次启动时, SDK默认关闭网络请求开关, 如果需要监控首次启动时的网络请求, 需要在
tingyun.init时配置网络请求开关默认为truetingyun.init({
network: {
enabled: true
}
}) - 使用
immediate: true选项可以立即插入拦截器,用于用户对拦截器顺序有要求的场景。当用户需要控制拦截器注入时机,希望提前注入听云拦截器以确保拦截器执行顺序时,可以使用此选项
RCP
SDK通过提供拦截器的方式支持对RCP(remote communication platform)的监控。用户需要在调用createSession时加入SDK提供的拦截器
import tingyun from '@tingyun/sdk-core'
const session = rcp.createSession({
// 其他配置...
// 加入拦截器
interceptors: [new tingyun.RCPInterceptor()]
})
SDK网络请求接口
SDK对系统@ohos.net.http包HttpRequest.request接口进行了封装,对外暴露了request接口。调用这个接口发送的网络请求会被SDK采集
API定义:
import http from '@ohos.net.http';
export type HttpRequestWrapperOptions = {
url: string
options?: http.HttpRequestOptions
// http.createHttp() 返回的request对象,如果不传SDK内部会创建。不传httpRequest时,SDK内部只会在用户传入callback时在用户callback执行完后同步调用httpRequest.destroy。传入httpRequest时, SDK除了调用httpRequest.request之外不会调用其他方法。如果需要调用httpRequest其他方法、自行控制destroy时机以及使用promise方式时,需要传入httpRequest
httpRequest?: http.HttpRequest
}
export interface HttpRequestWrapper {
(options: HttpRequestWrapperOptions, callback: AsyncCallback<http.HttpResponse>): void
(options: HttpRequestWrapperOptions): Promise<http.HttpResponse>
}
export type Tingyun = {
// ...
// http request封装
request: HttpRequestWrapper
}
使用示例:
示例1: 传递URL (promise)
tingyun.request({url: 'xxx'})
.then((res) => {
// ...
})
.catch((err) => {
// ...
})
示例2: 传递URL (callback)
tingyun.request({url: 'xxx'}, (err, res) => {
// ...
})
示例3: 传递URL和options (promise)
tingyun.request({url: 'xxx', options: {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json'
},
extraData: {
// ...
}
}})
.then((res) => {
// ...
})
.catch((err) => {
// ...
})
示例4: 传递URL和options (callback)
tingyun.request({url: 'xxx', options: {
method: http.RequestMethod.POST,
header: {
'Content-Type': 'application/json'
},
extraData: {
// ...
}
}}, (err, res) => {
// ...
})
示例5: 使用自定义请求对象
const httpRequest = http.createHttp()
tingyun.request({
url: 'xxx',
httpRequest: httpRequest
}, (err, res) => {
// ...
})
自定义请求
为了支持用户使用的一些自定义网络请求库,SDK对外提供一套可以收集用户自身采集的网络库信息的ArkTS层API。为了满足多种使用场景, 提供两种使用模式:
-
模式1:请求发起时和请求结束后分别调用SDK API,SDK在请求结束API被调用时,收集这条网络请求
第一种模式又分为2种使用方式:
- 请求开始前调用
tingyun.startRequest,结束后调用tingyun.endRequest, 两次调用都传递一个自行维护的请求ID关联同一个请求。这种方式调用比较灵活,但需要自行维护一个请求ID标识一个请求,如果现有的请求库本身提供了请求ID,或者请求开始和结束的代码结构比较分散时,适合用这种方式 - 请求开始前调用
tingyun.startRequest获取到SDK返回的请求实例,请求结束后调用请求实例的end方法结束请求。这种方式不需要自行维护请求ID,但代码结构较为复杂时,可能需要自行传递请求实例对象, 如果发送请求代码逻辑比较简单,在单一函数内完成时,适合用这种方式
- 请求开始前调用
-
模式2:请求结束后或任意时刻, 一次性调用
tingyun.createRequest, 上报一条完整的网络请求数据
模式1: startRequest / endRequest
API定义:
export type Tingyun = {
// 开始自定义请求
startRequest: (options: RequestStartOptions) => IRequestInstance
// 结束自定义请求
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 = {
// 请求URL
url: string
// 请求ID: 请求唯一标识, 不传SDK将自动生成一个UUID格式字符串
id?: string
// 请求开始时间: 13位毫秒时间戳, 如果不传SDK将接口调用时间点作为开始点
startTime?: number
// method: 默认为GET
method?: RequestMethod
// 网络库名称
libName?: LibName
// 请求头
reqHeaders?: KeyValueStore<string>
// 请求体: 仅支持传文本类型, 如果是JSON格式需要序列化为字符串传入
reqBody?: string
// 发送字节数
bytesSent?: number
// 请求对象超时清理时间, 单位毫秒: 开始请求一段时间后如果不调用endRequest, SDK内会自动清理当前请求释放资源, 默认为90000ms
timeout?: number
}
export type RequestEndOptions = {
// 请求ID: 请求唯一标识, 当使用Tingyun.endRequest时必传,当使用请求实例对象结束时不传
id?: string
// http状态码
statusCode?: number
// 错误码: 网络错误或其他错误的错误码, 请求成功或发生http错误(4xx, 5xx), 不需要传
errorCode?: number
// 请求结束时间: 13位毫秒时间戳, 如果不传SDK将接口调用的时间点作为结束点
endTime?: number
// 请求总耗时, 单位毫秒: 如果不传使用endTime - startTime计算
duration?: number
// dns耗时, 单位毫秒: dns结束时间 - dns开始时间
dns?: number
// 建立连接时间, 单位毫秒: 建立连接结束时间 - 建立连接开始时间
connect?: number
// ssl握手时间, 单位毫秒: ssl握手结束时间 - ssl握手开始时间
ssl?: number
// 首包, 单位毫秒: 首包结束时间 - 首包开始时间
firstPacket?: number
// 剩余包, 单位毫秒: 剩余包结束时间 - 剩余包开始时间
remainPacket?: number
// 本地排队时间, 单位毫秒
localQueue?: number
// 发送字节数: 会覆盖startRequest时传递的bytesSent
bytesSent?: number
// 接收字节数
bytesReceived?: number
// 请 求目标地址服务端IP
ip?: string
// 请求头: 会覆盖startRequest时传递的reqHeaders
reqHeaders?: KeyValueStore<string>
// 请求体: 仅支持传文本类型, 如果是JSON格式需要序列化为字符串传入. 会覆盖startRequest时传递的reqBody
reqBody?: string
// 返回头
resHeaders?: KeyValueStore<string>
// 返回体: 仅支持传文本类型的返回体, 如果是JSON格式需要序列化为字符串传入
resBody?: string
// 错误信息
errorMessage?: string
// 错误堆栈
errorStack?: string
// 链路追踪第三方apm请求头
apms?: KeyValueStore<string>
// 包含Tingyun APM的原始返回头和值
tyApm?: KeyValueStore<string>
}
示例1: 使用startRequest/endRequest,自定义请求ID
import tingyun from '@tingyun/sdk-core'
async function testRequest1() {
// 自定义请求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'
}
// 请求开始前, 调用startRequest开始请求
tingyun.startRequest({
id: reqId,
url: url,
method: method,
reqHeaders: reqHeaders,
reqBody: JSON.stringify(reqBody)
})
try {
// 调用自己的请求库
const response = await callCustomHttpLib(url, {
method: method,
reqBody: reqBody,
reqHeaders: reqHeaders
})
// 请求成功, 调用endRequest结束请求, 传递标识请求的请求ID
tingyun.endRequest({
id: reqId,
statusCode: response.statusCode,
resHeaders: response.headers,
resBody: response.body
})
} catch(e) {
// 请求失败, 调用endRequest结束请求, 传递标识请求的请求ID
tingyun.endRequest({
id: reqId,
errorCode: e.code
})
}
}
示例2: 使用startRequest返回的请求实例结束请求
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'
}
// 请求开始前, 调用startRequest开始请求, 并获取请求实例
const requestInstance = tingyun.startRequest({
url: url,
method: method,
reqHeaders: reqHeaders,
reqBody: JSON.stringify(reqBody)
})
try {
// 调用自己的请求库
const response = await callCustomHttpLib(url, {
method: method,
reqBody: reqBody,
reqHeaders: reqHeaders
})
// 请求成功, 使用请求实例的end方法结束请求
requestInstance.end({
statusCode: response.statusCode,
resHeaders: response.headers,
resBody: response.body
})
} catch(e) {
// 请求失败, 使用请求实例的end方法结束请求
requestInstance.end({
errorCode: e.code
})
}
}
模式2: createRequest
API定义:
export type Tingyun = {
createRequest: (options: RequestOptions) => void
}
// RequestStartOptions RequestEndOptions 见上方
export type RequestOptions = Omit<RequestStartOptions & RequestEndOptions, 'id' | 'timeout'>
示例:
async function testRequest3() {
const url = 'https://example.com'
const method = 'POST'
const reqBody = {
key1: 1
}
const reqHeaders = {
'Content-Type': 'application/json;charset=UTF-8'
}
// 设置开始时间
const startTime = Date.now()
let endTime
try {
// 调用自己的请求库
const response = await callCustomHttpLib(url, {
method: method,
reqBody: reqBody,
reqHeaders: reqHeaders
})
// 设置结束时间
endTime = Date.now()
// 请求成功, 调用createRequest创建自定义请求
tingyun.createRequest({
url: url,
startTime: startTime,
endTime: endTime,
statusCode: response.statusCode,
reqHeaders: reqHeaders,
resHeaders: response.headers,
resBody: response.body
})
} catch(e) {
// 设置结束时间
endTime = Date.now()
// 请求失败, 调用createRequest创建自定义请求
tingyun.createRequest({
url: url,
startTime: startTime,
endTime: endTime,
errorCode: e.code
})
}
}
mPaaS移动网关请求
SDK通过拦截器实现对mPaaS移动网关请求的监控,支持全局注册和按请求注册两种方式。
全局注册方式
适用于需要监控所有mPaaS请求的场景:
import { MPFramework } from '@mpaas/framework';
import { MPRpc } from "@mpaas/rpc";
import tingyun from '@tingyun/sdk-core'
export default class MyAbilityStage extends AbilityStage {
onCreate(): void {
// 初始化mPaaS框架 (下面仅为示例, 具体初始化方式以实际项目为准)
MPFramework.create(this.context);
// 全局注册tingyun拦截器
MPRpc.addGlobalInterceptor(new tingyun.MPaaSRPCInterceptor())
// 初始化tingyun SDK
tingyun.init({
// 其他配置...
network: {
// 其他配置...
// 开启mPaaS移动网关请求监 控
mPaaSEnabled: true
}
})
}
}
按请求注册方式
适用于仅监控特定请求的场景:
import tingyun from '@tingyun/sdk-core'
// 需要先在tingyun.init中开启mPaaS监控
tingyun.init({
// 其他配置...
network: {
// 其他配置...
// 开启mPaaS移动网关请求监控
mPaaSEnabled: true
}
})
// 在具体请求中注册拦截器
MPRpc.executeRpc<string>(this, {
// 其他配置...
// 注册拦截器
interceptor: new tingyun.MPaaSRPCInterceptor()
})
用户体验监控
registerUIContext (Deprecated)
注意:该接口已废弃。新版本 SDK 已支持自动采集,不再需要手动调用此接口。
API定义:
export Tingyun = {
/**
* @deprecated 请使用自动采集,不再需要手动注册
*/
registerUIContext(uiContext: UIContext)
}
操作监控
SDK支持采集用户点击事件
使用方式:
在需要采集的组件上设置id属性或添加自定义属性_ty_name来设置操作名称, 自定义属性的优先级高于id
示例:
Button('clickTest')
// 设置组件ID
.id('<自定义操作名称>')
// 自定义属性
.customProperty('_ty_name', '<自定义操作名称>')
.onClick(() => {
})
自定义操作
API定义:
export type ActionStartOptions = {
// 父级操作的key, 不传视为顶级操作
parent?: string
// 事件唯一标识, 不传则使用name作为唯一标识
key?: string
// 操作开始时间, 毫秒时间戳, 不传取调用时间
startTime?: number
}
export type ActionEndOptions = {
// 操作名称
name?: string
// 事件唯一标识, 不传则使用name作为唯一标识
key?: string
// 操作结束时间, 毫秒时间戳, 不传取调用时间
endTime?: number
// 自定义tag
tag?: string
// 自定义信息
metaData?: KeyValueStore<ValueType>
}
export interface IActionInstance {
end: (options?: ActionEndOptions) => void
readonly key: string
readonly name: string
}
export type Tingyun = {
// 开始用户操作
startAction: (name: string, options?: ActionStartOptions) => IActionInstance
// 结束用户操作
endAction: (options: ActionEndOptions) => void
}
使用方式:
示例1: 基本使用
// 开始操作
const action = tingyun.startAction('action1')
// ...
// 结束操作
action.end()
示例2: 传递自定义tag和附加信息
// 开始操作
const action = tingyun.startAction('action1')
// ...
// 结束操作
action.end({
// tag
tag: 'tag1',
// 附加信息
metaData: {
prop1: ''
}
})
示例3: 自定义开始时间和结束时间
// 开始操作
const action = tingyun.startAction('action1', {
startTime: <13位毫秒时间戳>
})
// ...
// 结束操作
action.end({
endTime: <13位毫秒时间戳>
})