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 > src > main > cpp > CMakeLists.txt”文件中新增libhitrace_ndk.z.so和libhilog_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 > src > main > cpp > 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 > src > main > ets > pages > 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