• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Using hiTraceChain (C/C++)
2
3<!--Kit: Performance Analysis Kit-->
4<!--Subsystem: HiviewDFX-->
5<!--Owner: @qq_437963121-->
6<!--Designer: @MontSaintMichel-->
7<!--Tester: @gcw_KuLfPSbe-->
8<!--Adviser: @foryourself-->
9
10## Available APIs
11
12The APIs for distributed call chain tracing are provided by the HiTraceChain module. For details, see [trace.h](../reference/apis-performance-analysis-kit/capi-trace-h.md).
13
14The following table lists the APIs provided by HiTraceChain for implementing the basic distributed tracing functionality. The corresponding APIs are also available in ArkTS.
15
16| API| Description|
17| -------- | -------- |
18| HiTraceId OH_HiTrace_BeginChain(const char \*name, int flags) | Starts call chain tracing and returns the created **HiTraceId**.|
19| void OH_HiTrace_EndChain() | Stops call chain tracing.|
20| HiTraceId OH_HiTrace_GetId() | Obtains the trace ID in TLS of the calling thread.|
21| void OH_HiTrace_SetId(const HiTraceId \*id) | Sets the trace ID in TLS of the calling thread to **id**.|
22| void OH_HiTrace_ClearId(void) | Clears the trace ID of the current thread.|
23| HiTraceId OH_HiTrace_CreateSpan(void) | Creates a trace span. Specifically, create a **HiTraceId**, use the **chainId** and **spanId** in the Thread-Local Storage (TLS) of the current thread to initialize the **chainId** and **parentSpanId** of the **HiTraceId**, generate a new **spanId** for the **HiTraceId**, and return the **HiTraceId**.|
24| bool OH_HiTrace_IsIdValid(const HiTraceId \*id) | Checks whether the **HiTraceId** is valid.<br>The value **true** indicates that **HiTraceId** is valid, and **false** indicates the opposite.|
25| bool OH_HiTrace_IsFlagEnabled(const HiTraceId \*id, HiTrace_Flag flag) | Checks whether the trace flag specified by **HiTraceId** is enabled.<br>The value **true** indicates that the specified trace flag is enabled, and **false** indicates the opposite.|
26| void OH_HiTrace_EnableFlag(const HiTraceId \*id, HiTrace_Flag flag) | Enables the trace flag specified in **HiTraceId**.|
27| void OH_HiTrace_Tracepoint(HiTrace_Communication_Mode mode, HiTrace_Tracepoint_Type type, const HiTraceId \*id, const char \*fmt, ...) | Adds a trace point for the HiTraceMeter logging.|
28
29The following table describes the APIs provided to extend **HiTraceId**. These APIs are available only in C/C++.
30
31| API| Description|
32| -------- | -------- |
33| void OH_HiTrace_InitId(HiTraceId \*id) | Initializes a **HiTraceId**.|
34| int OH_HiTrace_GetFlags(const HiTraceId \*id) | Obtains the trace flag set in **HiTraceId**.|
35| void OH_HiTrace_SetFlags(HiTraceId \*id, int flags) | Sets the trace flag in **HiTraceId**.|
36| uint64_t OH_HiTrace_GetChainId(const HiTraceId \*id) | Obtains the trace chain ID in **HiTraceId**.|
37| void OH_HiTrace_SetChainId(HiTraceId \*id, uint64_t chainId) | Sets the trace chain ID in **HiTraceId**.|
38| uint64_t OH_HiTrace_GetSpanId(const HiTraceId \*id) | Obtains the span ID in **HiTraceId**.|
39| void OH_HiTrace_SetSpanId(HiTraceId \*id, uint64_t spanId) | Sets the span ID in **HiTraceId**.|
40| uint64_t OH_HiTrace_GetParentSpanId(const HiTraceId \*id) | Obtains the parent span ID in **HiTraceId**.|
41| void OH_HiTrace_SetParentSpanId(HiTraceId \*id, uint64_t parentSpanId) | Sets the parent span ID in **HiTraceId**.|
42| int OH_HiTrace_IdToBytes(const HiTraceId\* id, uint8_t\* pIdArray, int len) | Converts **HiTraceId** into a byte array for cache or communication.|
43| void OH_HiTrace_IdFromBytes(HiTraceId \*id, const uint8_t \*pIdArray, int len) | Creates a **HiTraceId** based on a byte array.|
44
45
46## How to Develop
47
48**std::thread** does not support automatic transfer of **HiTraceId**. The following example shows how to use distributed tracing in this scenario. For details about the common mechanisms that support and do not support HiTraceChain automatic transfer, see [Constraints](hitracechain-intro.md#constraints).
49
501. Create a project in DevEco Studio and select **Native C++**. The project directory structure is as follows:
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. In the **entry > src > main > cpp > CMakeLists.tx** file, add **libhitrace_ndk.z.so** and **libhilog_ndk.z.so**. The complete file content is as follows:
73
74   ```cmake
75   # 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. In the **entry > src > main > cpp > napi_init.cpp** file, use HiTraceChain to trace multi-thread tasks. The sample code is as follows:
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       // Set a HiTraceId for the thread.
107       OH_HiTrace_SetId(&id);
108       // Generate a spanId.
109       id = OH_HiTrace_CreateSpan();
110       // Set a HiTraceId with the spanId for the thread.
111       OH_HiTrace_SetId(&id);
112       OH_LOG_INFO(LogType::LOG_APP, "Print2");
113       // End the distributed tracing of the thread. This functionality is the same as that of 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       // Set a HiTraceId for the thread.
121       OH_HiTrace_SetId(&id);
122       // Generate a spanId.
123       id = OH_HiTrace_CreateSpan();
124       // Set a HiTraceId with the spanId for the thread.
125       OH_HiTrace_SetId(&id);
126       OH_LOG_INFO(LogType::LOG_APP, "Print1");
127       std::thread(Print2, OH_HiTrace_GetId()).detach();
128       // End the distributed tracing of the thread.
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       // Start distributed tracing when the task starts.
136       HiTraceId hiTraceId = OH_HiTrace_BeginChain("testTag: hiTraceChain begin", HiTrace_Flag::HITRACE_FLAG_DEFAULT);
137       // Check whether the generated hiTraceId is valid. If yes, a HiLog log is generated.
138       if (OH_HiTrace_IsIdValid(&hiTraceId)) {
139           OH_LOG_INFO(LogType::LOG_APP, "HiTraceId is valid");
140       }
141       // Enable the HITRACE_FLAG_INCLUDE_ASYNC flag, indicating that HiTraceId is automatically transferred in the asynchronous mechanism supported by the system.
142       OH_HiTrace_EnableFlag(&hiTraceId, HiTrace_Flag::HITRACE_FLAG_INCLUDE_ASYNC);
143       // Check whether the HITRACE_FLAG_INCLUDE_ASYNC flag of HiTraceId is enabled. If yes, set the HiTraceId to the thread 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       // Create a thread to execute the print task and transfer the HiTraceId of the thread.
169       std::thread(Print1, OH_HiTrace_GetId()).detach();
170       // Stop the distributed tracing when the task is complete.
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   In the **entry > src > main > ets > pages > Index.ets** file, call the **Add** method in the button click event. The sample code is as follows:
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. Click the **Run** button in DevEco Studio to run the project. Then, click **clickTime=0** on the device to trigger the service logic.
241
2425. In the **Log** window of DevEco Studio, view the distributed tracing information.
243   - If **clickTime=1** is displayed on the device screen, the button is clicked once and the service logic is triggered.
244   - All HiLog logs in this example use **testTag**. You can filter logs by the keyword **testTag** to view the HiLog logs printed by the service code.
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   - The **[chainId spanId parentSpanId]** information added before the HiLog log is **HiTraceId** information. For example, **[a92ab19ae90197d 236699a 2544fdb]** indicates that the trace chain ID (**chainId**) is **a92ab19ae90197d**, the span ID (**spanId**) is **236699a**, and the parent span ID (**parentSpanId**) is **2544fdb**.
259   - Transfer the **HiTraceId**, create a **spanId**, and set it to the child thread created by **std::thread**. The HiLog logs of the Print1 and Print2 services running in the child thread also carry the same trace ID **a92ab19ae90197d** as that of the main thread.
260   - After the distributed tracing is ended using **OH_HiTrace_EndChain** or **OH_HiTrace_ClearId**, the HiLog print information does not carry the **HiTraceId** information.
261