1# 使用HiTraceChain打点(ArkTS) 2 3<!--Kit: Performance Analysis Kit--> 4<!--Subsystem: HiviewDFX--> 5<!--Owner: @qq_437963121--> 6<!--Designer: @kutcherzhou1; @MontSaintMichel--> 7<!--Tester: @gcw_KuLfPSbe--> 8<!--Adviser: @foryourself--> 9 10## 接口说明 11 12分布式跟踪接口由HiTraceChain模块提供,详细API请参考[分布式跟踪ArkTS API](../reference/apis-performance-analysis-kit/js-apis-hitracechain.md)。 13 14| 接口名 | 描述 | 15| -------- | -------- | 16| hiTraceChain.begin(name: string, flags?: number = HiTraceFlag.DEFAULT): HiTraceId | 开始跟踪,并返回创建的HiTraceId。 | 17| hiTraceChain.end(id: HiTraceId): void | 结束跟踪。 | 18| hiTraceChain.getId(): HiTraceId | 获取跟踪标识。 | 19| hiTraceChain.setId(id: HiTraceId): void | 设置跟踪标识。 | 20| hiTraceChain.clearId(): void | 清除跟踪标识。 | 21| hiTraceChain.createSpan(): HiTraceId | 创建跟踪分支。创建一个HiTraceId,使用当前线程TLS中的chainId、spanId初始化HiTraceId的chainId、parentSpanId,并为HiTraceId生成一个新的spanId,返回该HiTraceId。 | 22| hiTraceChain.isValid(id: HiTraceId): boolean | 判断HiTraceId是否有效。<br/>true:HiTraceId有效;false:HiTraceId无效。 | 23| hiTraceChain.isFlagEnabled(id: HiTraceId, flag: HiTraceFlag): boolean | 判断HiTraceId中指定的跟踪标志是否已启用。<br/>true:指定的跟踪标志已启用;false:指定的跟踪标志未启用。 | 24| hiTraceChain.enableFlag(id: HiTraceId, flag: HiTraceFlag): void | 启用HiTraceId中指定的跟踪标志。 | 25| hiTraceChain.tracepoint(mode: HiTraceCommunicationMode, type: HiTraceTracepointType, id: HiTraceId, msg?: string): void | HiTraceMeter跟踪信息埋点。 | 26 27 28## 开发步骤 29 30HiTraceChain在ArkTS中的使用方法参考以下示例,开发者可参考[约束与限制](hitracechain-intro.md#约束与限制),了解常见的支持与不支持HiTraceChain自动传递的机制。 31 32 33### async/await和promise/then异步任务中使用HiTraceChain 34 35async/await和promise/then异步任务支持HiTraceChain自动传递,示例结合[应用事件订阅](hiappevent-watcher-app-events-arkts.md)和[HiTraceMeter性能跟踪](hitracemeter-guidelines-arkts.md),说明分布式跟踪在ArkTS中的使用方法。 36 371. 在DevEco Studio中新建工程,选择“Empty Ability”,SDK版本选择19及以上(示例工程使用的HiTraceMeter接口从API version 19开始支持),工程的目录结构如下: 38 ```txt 39 ├── entry 40 │ ├── src 41 │ ├── main 42 │ │ ├── ets 43 │ │ │ ├── entryability 44 │ │ │ │ └── EntryAbility.ets 45 │ │ │ ├── entrybackupability 46 │ │ │ │ └── EntryBackupAbility.ets 47 │ │ │ └── pages 48 │ │ │ └── Index.ets 49 ``` 50 512. 编辑“entry > src > main > ets > pages > Index.ets”文件,使用HiTraceChain跟踪异步任务,完整的示例代码如下: 52 53 ```ts 54 import { BusinessError } from '@kit.BasicServicesKit'; 55 import { hiAppEvent, hilog, hiTraceChain, hiTraceMeter } from '@kit.PerformanceAnalysisKit'; 56 57 async function test3() { 58 hilog.info(0x0000, "testTag", "test3"); 59 } 60 61 async function test2() { 62 hilog.info(0x0000, "testTag", "test2"); 63 } 64 65 async function test1() { 66 hilog.info(0x0000, 'testTag', "test1_1"); 67 await test2(); 68 hilog.info(0x0000, 'testTag', "test1_2"); 69 await test3(); 70 hilog.info(0x0000, 'testTag', "test1_3"); 71 } 72 73 @Entry 74 @Component 75 struct Index { 76 @State message: string = "clickTime=0"; 77 @State clickTime: number = 0; 78 79 build() { 80 Row() { 81 Column() { 82 Button(this.message) 83 .fontSize(20) 84 .margin(5) 85 .width(350) 86 .height(60) 87 .fontWeight(FontWeight.Bold) 88 .onClick(() => { 89 this.clickTime++; 90 this.message = "clickTime=" + this.clickTime; 91 // 业务开始前,开启分布式跟踪 92 // INCLUDE_ASYNC表示会在系统支持的异步机制里自动传递HiTraceId 93 let traceId = hiTraceChain.begin("testTag: hiTraceChain begin", hiTraceChain.HiTraceFlag.INCLUDE_ASYNC); 94 // 开始HiTraceMeter同步打点,该接口API version 19开始支持 95 hiTraceMeter.startSyncTrace(hiTraceMeter.HiTraceOutputLevel.COMMERCIAL, "onClick", this.message); 96 97 // 在按钮点击函数中进行事件打点,以记录按钮点击事件 98 let eventParams: Record<string, number> = { 'click_time': 100 }; 99 let eventInfo: hiAppEvent.AppEventInfo = { 100 // 事件领域定义 101 domain: "button", 102 // 事件名称定义 103 name: "click", 104 // 事件类型定义 105 eventType: hiAppEvent.EventType.BEHAVIOR, 106 // 事件参数定义 107 params: eventParams 108 }; 109 hiAppEvent.write(eventInfo).then(() => { 110 hilog.info(0x0000, "testTag", "Succeeded in writing an app event"); 111 // 按钮点击事件处理结束,关闭异步处理分支的分布式跟踪 112 hiTraceChain.end(traceId); 113 hilog.info(0x0000, "testTag", "hiTraceChain end in hiAppEvent"); 114 }).catch((err: BusinessError) => { 115 hilog.error(0x0000, "testTag", `HiAppEvent err.code: ${err.code}, err.message: ${err.message}`); 116 // 异常处理结束,关闭异步处理分支的分布式跟踪 117 hiTraceChain.end(traceId); 118 hilog.info(0x0000, "testTag", "hiTraceChain end in hiAppEvent"); 119 }); 120 121 // 创建Promise对象执行随机数生成任务,若随机数大于0.5,则正常返回结果,反之则返回异常信息 122 const promise: Promise<number> = new Promise((resolve: Function, reject: Function) => { 123 hilog.info(0x0000, "testTag", "promise task"); 124 const randomNumber: number = Math.random(); 125 if (randomNumber > 0.5) { 126 resolve(randomNumber); 127 } else { 128 reject(new Error('Random number is too small')); 129 } 130 }); 131 132 // then方法的回调函数处理Promise对象的执行结果 133 promise.then((result: number) => { 134 // 成功时执行 135 hilog.info(0x0000, "testTag", "Random number is %{public}d", result); 136 // 回调函数处理结束,关闭异步处理分支的分布式跟踪 137 hiTraceChain.end(traceId); 138 hilog.info(0x0000, "testTag", "hiTraceChain end in promise/then"); 139 }).catch((error: BusinessError) => { 140 // 失败时执行 141 hilog.error(0x0000, "testTag", error.message); 142 // 异常处理结束,关闭异步处理分支的分布式跟踪 143 hiTraceChain.end(traceId); 144 hilog.info(0x0000, "testTag", "hiTraceChain end in promise/then"); 145 }); 146 147 // 执行async/await异步任务 148 let res = test1(); 149 // then方法的回调函数处理异步任务的执行结果 150 res.then(() => { 151 hilog.info(0x0000, "testTag", "then task"); 152 // 功能同hiTraceChain.end,关闭异步处理分支的分布式跟踪 153 hiTraceChain.clearId(); 154 hilog.info(0x0000, "testTag", "hiTraceChain end in async/await"); 155 }); 156 157 // 结束HiTraceMeter同步打点,该接口API version 19开始支持 158 hiTraceMeter.finishSyncTrace(hiTraceMeter.HiTraceOutputLevel.COMMERCIAL); 159 // 业务结束后,关闭分布式跟踪 160 hiTraceChain.end(traceId); 161 hilog.info(0x0000, "testTag", "hiTraceChain end in main thread"); 162 }) 163 } 164 .width('100%') 165 } 166 .height('100%') 167 } 168 } 169 ``` 170 1713. 点击DevEco Studio界面中的运行按钮,运行应用工程。在DevEco Studio Terminal窗口中执行以下命令,捕获10秒内的应用trace,并使用关键字“onClick”过滤示例代码中hiTraceMeter.startSyncTrace和hiTraceMeter.finishSyncTrace生成的trace日志。 172 173 ```shell 174 PS D:\xxx\xxx> hdc shell 175 $ hitrace -t 10 app | grep onClick 176 ``` 177 1784. 点击设备上的“clickTime=0”按钮(需在10秒内完成,否则步骤3捕获不到trace数据),触发业务逻辑。 179 1805. 查看运行结果。 181 - 设备屏幕上按钮显示“clickTime=1”,表示点击了按钮一次,已触发业务逻辑。 182 - 在DevEco Studio Log窗口查看分布式跟踪的相关信息。 183 - 示例所有hilog打印均使用了“testTag”,因此可以使用关键字“testTag”过滤日志,查看该业务代码打印的hilog日志。 184 185 ```txt 186 06-04 17:46:45.156 55451-55451 C02D33/com.exa...tion/HiTraceC com.examp...lication I [a92ab116052648e 0 0]HiTraceBegin name:testTag: hiTraceChain begin flags:0x01. 187 06-04 17:46:45.157 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I [a92ab116052648e 0 0]promise task 188 06-04 17:46:45.158 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I [a92ab116052648e 0 0]test1_1 189 06-04 17:46:45.158 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I [a92ab116052648e 0 0]test2 190 06-04 17:46:45.158 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I hiTraceChain end in main thread 191 06-04 17:46:45.158 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I [a92ab116052648e 3457eff 0]test1_2 192 06-04 17:46:45.158 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I [a92ab116052648e 3457eff 0]test3 193 06-04 17:46:45.158 55451-55451 A00000/com.exa...ation/testTag com.examp...lication E [a92ab116052648e 1bb5a1b 35d9c46]Random number is too small 194 06-04 17:46:45.158 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I hiTraceChain end in promise/then 195 06-04 17:46:45.158 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I [a92ab116052648e 2ddfb70 3457eff]test1_3 196 06-04 17:46:45.158 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I [a92ab116052648e 225a1d9 2ddfb70]then task 197 06-04 17:46:45.158 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I hiTraceChain end in async/await 198 06-04 17:46:45.163 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I [a92ab116052648e 3a75cb2 520a92]Succeeded in writing an app event 199 06-04 17:46:45.163 55451-55451 A00000/com.exa...ation/testTag com.examp...lication I hiTraceChain end in hiAppEvent 200 ``` 201 202 - hilog日志前附加的[chainId spanId parentSpanId]格式的信息即为HiTraceId信息,例如[a92ab116052648e 2ddfb70 3457eff]表示跟踪链标识chainId值为a92ab116052648e,分支标识spanId值为2ddfb70,父分支标识parentSpanId值为3457eff。 203 - 示例得到的跟踪链标识chainId值为a92ab116052648e,可使用chainId值过滤日志,查看业务完整的调用链hilog日志。 204 - promise/then和async/await异步机制都会自动传递HiTraceId,并生成分支标识,例如示例hilog日志中的3457eff、2ddfb70、225a1d9等,均为异步任务自动生成的分支标识。 205 - hiTraceChain.end()和hiTraceChain.clear()都可以结束跟踪,跟踪结束后,hilog日志不再携带HiTraceId信息。 206 207 - 在DevEco Studio Terminal窗口查看trace数据,HiTraceChain跟踪开启期间,HiTraceMeter打点得到的trace日志会自动携带HiTraceId信息。 208 209 ```txt 210 e.myapplication-55451 ( 55451) [010] .... 27164.174417: tracing_mark_write: B|55451|H:[a92ab116052648e,0,0]#onClick|M62|clickTime=1 211 ``` 212 213 214### 异步宏任务setInterval和setTimeout中使用HiTraceChain 215 216异步宏任务setInterval和setTimeout不支持HiTraceChain自动传递,以下示例说明如何使用hiTraceChain.getId()、hiTraceChain.setId()接口传递HiTraceId,如何使用hiTraceChain.createSpan()接口创建分支标识,进行分布式跟踪。 217 2181. 在DevEco Studio中新建工程,选择“Empty Ability”,工程的目录结构如下: 219 220 ```txt 221 ├── entry 222 │ ├── src 223 │ ├── main 224 │ │ ├── ets 225 │ │ │ ├── entryability 226 │ │ │ │ └── EntryAbility.ets 227 │ │ │ ├── entrybackupability 228 │ │ │ │ └── EntryBackupAbility.ets 229 │ │ │ └── pages 230 │ │ │ └── Index.ets 231 ``` 232 2332. 编辑工程中的“entry > src > main > ets > pages > Index.ets”文件,使用HiTraceChain跟踪异步任务,完整的示例代码如下: 234 235 ```ts 236 import { BusinessError } from '@kit.BasicServicesKit'; 237 import { hilog, hiTraceChain } from '@kit.PerformanceAnalysisKit'; 238 239 @Entry 240 @Component 241 struct Index { 242 @State message: string = "clickTime=0"; 243 @State clickTime: number = 0; 244 245 build() { 246 Row() { 247 Column() { 248 Button(this.message) 249 .fontSize(20) 250 .margin(5) 251 .width(350) 252 .height(60) 253 .fontWeight(FontWeight.Bold) 254 .onClick(() => { 255 this.clickTime++; 256 this.message = "clickTime=" + this.clickTime; 257 // 获取当前线程的HiTraceId 258 let traceId = hiTraceChain.getId(); 259 // 如果traceId无效,为当前线程开启分布式跟踪 260 if (!hiTraceChain.isValid(traceId)) { 261 hilog.info(0x0000, "testTag", "HiTraceId is invalid, begin hiTraceChain"); 262 traceId = hiTraceChain.begin("testTag: hiTraceChain begin"); 263 // 使能traceId的INCLUDE_ASYNC,INCLUDE_ASYNC表示会在系统支持的异步机制里自动传递HiTraceId 264 hiTraceChain.enableFlag(traceId, hiTraceChain.HiTraceFlag.INCLUDE_ASYNC); 265 // 将使能INCLUDE_ASYNC的HiTraceId设置到当前线程 266 hiTraceChain.setId(traceId); 267 // 查询INCLUDE_ASYNC是否设置成功 268 if (hiTraceChain.isFlagEnabled(hiTraceChain.getId(), hiTraceChain.HiTraceFlag.INCLUDE_ASYNC)) { 269 hilog.info(0x0000, "testTag", "HiTraceFlag INCLUDE_ASYNC is enabled"); 270 } 271 } 272 273 const promise: Promise<number> = new Promise((resolve: Function, reject: Function) => { 274 // 创建异步重复定时任务,每1s执行一次 275 let intervalID = setInterval(() => { 276 // 为当前异步重复定时任务设置HiTraceId 277 hiTraceChain.setId(traceId); 278 const randomNumber: number = Math.random(); 279 hilog.info(0x0000, "testTag", "Interval 1s: randomNumber is %{public}d", randomNumber); 280 // 关闭当前异步重复定时任务的分布式跟踪 281 hiTraceChain.end(traceId); 282 }, 1000) 283 284 // 创建异步定时任务,2.5s后执行,结束异步重复定时任务 285 setTimeout(() => { 286 // 为异步定时任务设置HiTraceId 287 hiTraceChain.setId(traceId); 288 // 为异步定时任务生成分支标识spanId 289 let traceIdTimeout = hiTraceChain.createSpan(); 290 // 为异步定时任务设置带spanId的HiTraceId 291 hiTraceChain.setId(traceIdTimeout); 292 hilog.info(0x0000, 'testTag', "setTimeout 2.5s"); 293 // 结束异步重复定时任务 294 clearInterval(intervalID); 295 const randomNumber: number = Math.random(); 296 if (randomNumber > 0.5) { 297 resolve(randomNumber); 298 } else { 299 reject(new Error('Random number is too small')); 300 } 301 // 关闭异步定时任务的分布式跟踪 302 hiTraceChain.end(traceId); 303 }, 2500) 304 }) 305 306 promise.then((result: number) => { 307 // 成功时执行 308 hilog.info(0x0000, 'testTag', "Random number is %{public}d", result); 309 // 回调函数处理结束,关闭异步处理分支的分布式跟踪 310 hiTraceChain.end(traceId); 311 }).catch((error: BusinessError) => { 312 // 失败时执行 313 hilog.error(0x0000, 'testTag', error.message); 314 // 异常处理结束,关闭异步处理分支的分布式跟踪 315 hiTraceChain.end(traceId); 316 }); 317 318 // 业务结束后,关闭分布式跟踪 319 hiTraceChain.end(traceId); 320 hilog.info(0x0000, "testTag", "hiTraceChain end in main thread"); 321 }) 322 } 323 .width('100%') 324 } 325 .height('100%') 326 } 327 } 328 ``` 329 3303. 点击DevEco Studio界面中的运行按钮,运行应用工程,点击设备上“clickTime=0”按钮,触发业务逻辑。 331 3324. 查看运行结果。 333 - 设备屏幕上按钮显示“clickTime=1”,表示点击了按钮一次,已触发业务逻辑。 334 - 在DevEco Studio Log窗口查看分布式跟踪的相关信息。 335 - 示例所有hilog打印均使用了“testTag”,因此可以使用关键字“testTag”过滤日志,查看该业务代码打印的hilog日志。 336 337 ```txt 338 06-05 15:46:04.544 49568-49568 A00000/com.exa...ation/testTag com.examp...lication I HiTraceId is invalid, begin hiTraceChain 339 06-05 15:46:04.544 49568-49568 C02D33/com.exa...tion/HiTraceC com.examp...lication I [a92ab34b3c84ea7 0 0]HiTraceBegin name:testTag: hiTraceChain begin flags:0x00. 340 06-05 15:46:04.544 49568-49568 A00000/com.exa...ation/testTag com.examp...lication I [a92ab34b3c84ea7 0 0]HiTraceFlag INCLUDE_ASYNC is enabled 341 06-05 15:46:04.544 49568-49568 A00000/com.exa...ation/testTag com.examp...lication I hiTraceChain end in main thread 342 06-05 15:46:05.547 49568-49568 A00000/com.exa...ation/testTag com.examp...lication I [a92ab34b3c84ea7 0 0]Interval 1s: randomNumber is 0.863610 343 06-05 15:46:06.548 49568-49568 A00000/com.exa...ation/testTag com.examp...lication I [a92ab34b3c84ea7 0 0]Interval 1s: randomNumber is 0.365460 344 06-05 15:46:07.047 49568-49568 A00000/com.exa...ation/testTag com.examp...lication I [a92ab34b3c84ea7 3cafdfd 0]setTimeout 2.5s 345 06-05 15:46:07.048 49568-49568 A00000/com.exa...ation/testTag com.examp...lication I [a92ab34b3c84ea7 dc842f 3cafdfd]Random number is 0.524236 346 ``` 347 348 - hilog日志前附加的[chainId spanId parentSpanId]格式的信息即为HiTraceId信息,例如[a92ab34b3c84ea7 dc842f 3cafdfd]表示跟踪链标识chainId值为a92ab34b3c84ea7,分支标识spanId值为dc842f,父分支标识parentSpanId值为3cafdfd。 349 - 示例得到的chainId值为a92ab34b3c84ea7,可使用chainId值过滤日志,查看业务完整的调用链hilog日志。 350