• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用HiTraceChain打点(C/C++)
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请参考[分布式跟踪C API](../reference/apis-performance-analysis-kit/capi-trace-h.md)。
13
14下表所示的接口提供基本的分布式跟踪功能,ArkTS中也有相应的接口。
15
16| 方法 | 接口描述 |
17| -------- | -------- |
18| HiTraceId OH_HiTrace_BeginChain(const char \*name, int flags) | 开始跟踪,并返回创建的HiTraceId。 |
19| void OH_HiTrace_EndChain() | 停止跟踪。 |
20| HiTraceId OH_HiTrace_GetId() | 从当前线程TLS中获取跟踪标识。 |
21| void OH_HiTrace_SetId(const HiTraceId \*id) | 将当前线程TLS中的跟踪标识设置为id。 |
22| void OH_HiTrace_ClearId(void) | 清除当前线程的跟踪标识。 |
23| HiTraceId OH_HiTrace_CreateSpan(void) | 创建跟踪分支。创建一个HiTraceId,使用当前线程TLS中的chainId、spanId初始化HiTraceId的chainId、parentSpanId,并为HiTraceId生成一个新的spanId,返回该HiTraceId。 |
24| bool OH_HiTrace_IsIdValid(const HiTraceId \*id) | 判断HiTraceId是否有效。<br/>true:HiTraceId有效;false:HiTraceId无效。 |
25| bool OH_HiTrace_IsFlagEnabled(const HiTraceId \*id, HiTrace_Flag flag) | 判断HiTraceId中指定的跟踪标志是否已启用。<br/>true:指定的跟踪标志已启用;false:指定的跟踪标志未启用。 |
26| void OH_HiTrace_EnableFlag(const HiTraceId \*id, HiTrace_Flag flag) | 启用HiTraceId中指定的跟踪标志。 |
27| void OH_HiTrace_Tracepoint(HiTrace_Communication_Mode mode, HiTrace_Tracepoint_Type type, const HiTraceId \*id, const char \*fmt, ...) | HiTraceMeter跟踪信息埋点。 |
28
29下表所示的接口提供对HiTraceId的一些拓展操作,这些接口仅在C/C++中提供。
30
31| 方法 | 接口描述 |
32| -------- | -------- |
33| void OH_HiTrace_InitId(HiTraceId \*id) | 初始化HiTraceId。 |
34| int OH_HiTrace_GetFlags(const HiTraceId \*id) | 获取HiTraceId中设置的跟踪标志位。 |
35| void OH_HiTrace_SetFlags(HiTraceId \*id, int flags) | 设置跟踪标志位到HiTraceId中。 |
36| uint64_t OH_HiTrace_GetChainId(const HiTraceId \*id) | 获取HiTraceId中的跟踪链ID。 |
37| void OH_HiTrace_SetChainId(HiTraceId \*id, uint64_t chainId) | 设置跟踪链ID到HiTraceId中。 |
38| uint64_t OH_HiTrace_GetSpanId(const HiTraceId \*id) | 获取HiTraceId中的分支ID。 |
39| void OH_HiTrace_SetSpanId(HiTraceId \*id, uint64_t spanId) | 设置分支ID到HiTraceId中。 |
40| uint64_t OH_HiTrace_GetParentSpanId(const HiTraceId \*id) | 获取HiTraceId中的父分支ID。 |
41| void OH_HiTrace_SetParentSpanId(HiTraceId \*id, uint64_t parentSpanId) | 设置父分支ID到HiTraceId中。 |
42| int OH_HiTrace_IdToBytes(const HiTraceId\* id, uint8_t\* pIdArray, int len) | 将HiTraceId转换为字节数组,用于缓存或通信传递。 |
43| void OH_HiTrace_IdFromBytes(HiTraceId \*id, const uint8_t \*pIdArray, int len) | 根据字节数组创建HiTraceId。 |
44
45
46## 开发步骤
47
48std::thread不支持自动传递HiTraceId,开发示例展示了该场景下分布式跟踪的使用方法。开发者可参考[约束与限制](hitracechain-intro.md#约束与限制),了解常见的支持与不支持HiTraceChain自动传递的机制。
49
501. 在DevEco Studio中新建工程,选择“Native C++”,工程的目录结构如下:
51
52   ```text
53   ├── entry
54   │   ├── src
55   │       ├── main
56   │       │   ├── cpp
57   │       │   │   ├── CMakeLists.txt
58   │       │   │   ├── napi_init.cpp
59   │       │   │   └── types
60   │       │   │       └── libentry
61   │       │   │           ├── Index.d.ts
62   │       │   │           └── oh-package.json5
63   │       │   ├── ets
64   │       │   │   ├── entryability
65   │       │   │   │   └── EntryAbility.ets
66   │       │   │   ├── entrybackupability
67   │       │   │   │   └── EntryBackupAbility.ets
68   │       │   │   └── pages
69   │       │   │       └── Index.ets
70   ```
71
722. 在“entry &gt; src &gt; main &gt; cpp &gt; CMakeLists.txt”文件中新增libhitrace_ndk.z.solibhilog_ndk.z.so动态链接库,完整的文件内容如下:
73
74   ```cmake
75   # the minimum version of CMake.
76   cmake_minimum_required(VERSION 3.5.0)
77   project(HiTraceChainTest03)
78
79   set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
80
81   if(DEFINED PACKAGE_FIND_FILE)
82       include(${PACKAGE_FIND_FILE})
83   endif()
84
85   include_directories(${NATIVERENDER_ROOT_PATH}
86                       ${NATIVERENDER_ROOT_PATH}/include)
87
88   add_library(entry SHARED napi_init.cpp)
89   target_link_libraries(entry PUBLIC libace_napi.z.so libhitrace_ndk.z.so libhilog_ndk.z.so)
90   ```
91
923. 编辑“entry &gt; src &gt; main &gt; cpp &gt; napi_init.cpp”文件,使用HiTraceChain跟踪多线程任务,完整的示例代码如下:
93
94   ```cpp
95   #include <thread>
96
97   #include "hilog/log.h"
98   #include "hitrace/trace.h"
99   #include "napi/native_api.h"
100
101   #undef LOG_TAG
102   #define LOG_TAG "testTag"
103
104   void Print2(HiTraceId id)
105   {
106       // 为当前线程设置HiTraceId
107       OH_HiTrace_SetId(&id);
108       // 生成分支标识spanId
109       id = OH_HiTrace_CreateSpan();
110       // 为当前线程设置带spanId的HiTraceId
111       OH_HiTrace_SetId(&id);
112       OH_LOG_INFO(LogType::LOG_APP, "Print2");
113       // 结束当前线程分布式跟踪,功能同OH_HiTrace_EndChain()
114       OH_HiTrace_ClearId();
115       OH_LOG_INFO(LogType::LOG_APP, "Print2, HiTraceChain end");
116   }
117
118   void Print1(HiTraceId id)
119   {
120       // 为当前线程设置HiTraceId
121       OH_HiTrace_SetId(&id);
122       // 生成分支标识spanId
123       id = OH_HiTrace_CreateSpan();
124       // 为当前线程设置带spanId的HiTraceId
125       OH_HiTrace_SetId(&id);
126       OH_LOG_INFO(LogType::LOG_APP, "Print1");
127       std::thread(Print2, OH_HiTrace_GetId()).detach();
128       // 结束当前线程分布式跟踪
129       OH_HiTrace_EndChain();
130       OH_LOG_INFO(LogType::LOG_APP, "Print1, HiTraceChain end");
131   }
132
133   static napi_value Add(napi_env env, napi_callback_info info)
134   {
135       // 任务开始,开启分布式跟踪
136       HiTraceId hiTraceId = OH_HiTrace_BeginChain("testTag: hiTraceChain begin", HiTrace_Flag::HITRACE_FLAG_DEFAULT);
137       // 判断生成的hiTraceId是否有效,有效则输出一行hilog日志
138       if (OH_HiTrace_IsIdValid(&hiTraceId)) {
139           OH_LOG_INFO(LogType::LOG_APP, "HiTraceId is valid");
140       }
141       // 使能HITRACE_FLAG_INCLUDE_ASYNC标志位,表示会在系统支持的异步机制里自动传递HiTraceId
142       OH_HiTrace_EnableFlag(&hiTraceId, HiTrace_Flag::HITRACE_FLAG_INCLUDE_ASYNC);
143       // 判断hitraceId的HITRACE_FLAG_INCLUDE_ASYNC标志位是否已经使能,使能则把hiTraceId设置到当前线程TLS中
144       if (OH_HiTrace_IsFlagEnabled(&hiTraceId, HiTrace_Flag::HITRACE_FLAG_INCLUDE_ASYNC)) {
145           OH_HiTrace_SetId(&hiTraceId);
146           OH_LOG_INFO(LogType::LOG_APP, "HITRACE_FLAG_INCLUDE_ASYNC is enabled");
147       }
148       size_t argc = 2;
149       napi_value args[2] = {nullptr};
150
151       napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
152
153       napi_valuetype valuetype0;
154       napi_typeof(env, args[0], &valuetype0);
155
156       napi_valuetype valuetype1;
157       napi_typeof(env, args[1], &valuetype1);
158
159       double value0;
160       napi_get_value_double(env, args[0], &value0);
161
162       double value1;
163       napi_get_value_double(env, args[1], &value1);
164
165       napi_value sum;
166       napi_create_double(env, value0 + value1, &sum);
167
168       // 创建线程执行打印任务,传递当前线程的HiTraceId
169       std::thread(Print1, OH_HiTrace_GetId()).detach();
170       // 任务结束,结束分布式跟踪
171       OH_HiTrace_EndChain();
172       OH_LOG_INFO(LogType::LOG_APP, "Add, HiTraceChain end");
173
174       return sum;
175   }
176
177   EXTERN_C_START
178   static napi_value Init(napi_env env, napi_value exports)
179   {
180       napi_property_descriptor desc[] = {
181           { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }
182       };
183       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
184       return exports;
185   }
186   EXTERN_C_END
187
188   static napi_module demoModule = {
189       .nm_version = 1,
190       .nm_flags = 0,
191       .nm_filename = nullptr,
192       .nm_register_func = Init,
193       .nm_modname = "entry",
194       .nm_priv = ((void*)0),
195       .reserved = { 0 },
196   };
197
198   extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
199   {
200       napi_module_register(&demoModule);
201   }
202   ```
203
204   编辑“entry &gt; src &gt; main &gt; ets &gt; pages &gt; Index.ets”文件,在按钮点击事件里调用Add方法,完整的示例代码如下:
205
206   ```ts
207   import { hilog } from '@kit.PerformanceAnalysisKit';
208   import testNapi from 'libentry.so';
209
210   const DOMAIN = 0x0000;
211
212   @Entry
213   @Component
214   struct Index {
215     @State message: string = "clickTime=0";
216     @State clickTime: number = 0;
217
218     build() {
219       Row() {
220         Column() {
221           Button(this.message)
222             .fontSize(20)
223             .margin(5)
224             .width(350)
225             .height(60)
226             .fontWeight(FontWeight.Bold)
227             .onClick(() => {
228               this.clickTime++;
229               this.message = "clickTime=" + this.clickTime;
230               hilog.info(DOMAIN, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.add(2, 3));
231             })
232         }
233         .width('100%')
234       }
235       .height('100%')
236     }
237   }
238   ```
239
2404. 点击DevEco Studio界面中的运行按钮,运行应用工程。然后点击设备上“clickTime=0”按钮,触发业务逻辑。
241
2425. 在DevEco Studio Log窗口查看分布式跟踪的相关信息。
243   - 设备屏幕上按钮显示“clickTime=1”,表示已点击了按钮一次并触发业务逻辑。
244   - 示例所有hilog打印均使用了“testTag”,因此可以使用“testTag”关键字过滤日志,查看该业务代码打印的hilog信息。
245
246      ```txt
247      06-05 21:26:01.006   9944-9944     C02D33/com.exa...tion/HiTraceC  com.examp...lication  I     [a92ab19ae90197d 0 0]HiTraceBegin name:testTag: hiTraceChain begin flags:0x00.
248      06-05 21:26:01.006   9944-9944     A00000/com.exa...ation/testTag  com.examp...lication  I     [a92ab19ae90197d 0 0]HiTraceId is valid
249      06-05 21:26:01.006   9944-9944     A00000/com.exa...ation/testTag  com.examp...lication  I     [a92ab19ae90197d 0 0]HITRACE_FLAG_INCLUDE_ASYNC is enabled
250      06-05 21:26:01.007   9944-9944     A00000/com.exa...ation/testTag  com.examp...lication  I     Add, HiTraceChain end
251      06-05 21:26:01.007   9944-9944     A00000/com.exa...ation/testTag  com.examp...lication  I     Test NAPI 2 + 3 = 5
252      06-05 21:26:01.007   9944-13961    A00000/com.exa...ation/testTag  com.examp...lication  I     [a92ab19ae90197d 2544fdb 0]Print1
253      06-05 21:26:01.007   9944-13961    A00000/com.exa...ation/testTag  com.examp...lication  I     Print1, HiTraceChain end
254      06-05 21:26:01.008   9944-13962    A00000/com.exa...ation/testTag  com.examp...lication  I     [a92ab19ae90197d 236699a 2544fdb]Print2
255      06-05 21:26:01.008   9944-13962    A00000/com.exa...ation/testTag  com.examp...lication  I     Print2, HiTraceChain end
256      ```
257
258   - hilog日志前附加的[chainId spanId parentSpanId]格式的信息即为HiTraceId信息,例如[a92ab19ae90197d 236699a 2544fdb]表示跟踪链标识chainId值为a92ab19ae90197d,分支标识spanId值为236699a,父分支标识parentSpanId值为2544fdb。
259   - 通过手动传递HiTraceId,创建spanId,并将其设置到std::thread创建的子线程中,子线程中运行的Print1和Print2业务的hilog日志也携带上同主线程一致的跟踪标识“a92ab19ae90197d”。
260   - 使用OH_HiTrace_EndChain()或OH_HiTrace_ClearId()结束分布式跟踪后,hilog打印信息不再携带HiTraceId信息。
261