• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/awaitpromise/then异步任务中使用HiTraceChain
34
35async/awaitpromise/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 &gt; src &gt; main &gt; ets &gt; pages &gt; 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.startSyncTracehiTraceMeter.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/thenasync/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 &gt; src &gt; main &gt; ets &gt; pages &gt; 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