1/*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16//! Interface definition for rust APIs of hitracechain.
17
18#[macro_use]
19pub mod macros;
20
21use std::ffi::{CString, c_char, c_int, c_ulonglong};
22use std::ops::BitOr;
23
24/// Enumerate trace flag
25#[non_exhaustive]
26pub enum HiTraceFlag {
27    /// DEFAULT: default value.
28    Default = 0,
29
30    /// trace sync and async call. default: trace sync call only.
31    IncludeAsync = 1 << 0,
32
33    /// do not create child span. default: create child span.
34    DoNotCreateSpan = 1 << 1,
35
36    /// output tracepoint info in span. default: do not output tracepoint info.
37    TpInfo = 1 << 2,
38
39    /// do not output begin and end info. default: output begin and end info.
40    NoBeInfo = 1 << 3,
41
42    /// do not add id to log. default: add id to log.
43    DoNotEnableLog = 1 << 4,
44
45    /// the trace is triggered by fault.
46    FaultTigger = 1 << 5,
47
48    /// output device-to-device tracepoint info in span only. default: do not output device-to-device tracepoint info.
49    D2dTpInfo = 1 << 6,
50}
51
52/// Add support for bitor operating for HiTraceFlag
53impl BitOr for HiTraceFlag {
54    type Output = i32;
55
56    fn bitor(self, rhs: Self) -> Self::Output {
57        (self as i32) | (rhs as i32)
58    }
59}
60
61/// Enumerate trace point type
62#[non_exhaustive]
63pub enum HiTraceTracepointType {
64
65    /// client send
66    Cs = 0,
67
68    /// client receive
69    Cr = 1,
70
71    /// server send
72    Ss = 2,
73
74    /// server receive
75    Sr = 3,
76
77    /// general info
78    General = 4,
79}
80
81/// Enumerate trace communication mode
82#[non_exhaustive]
83pub enum HiTraceCommunicationMode {
84    /// unspecified communication mode
85    Default = 0,
86
87    /// thread-to-thread communication mode
88    Thread = 1,
89
90    /// process-to-process communication mode
91    Process = 2,
92
93    /// device-to-device communication mode
94    Device = 3,
95}
96
97/// This type represent to HiTraceIdStruct defined in C.
98#[repr(C)]
99pub struct HiTraceIdStruct {
100    trace_details: [u64;2],
101}
102
103/// Alias for HiTraceIdStruct
104pub type HiTraceId = HiTraceIdStruct;
105
106impl HiTraceId {
107    /// Judge whether the trace id is valid or not.
108    pub fn is_valid(&self) -> bool {
109        // Safty: call C ffi border function, all risks are under control.
110        unsafe {
111            HiTraceChainIsValidWrapper(self as *const HiTraceId)
112        }
113    }
114
115    /// Judge whether the trace id has enabled a trace flag or not.
116    pub fn is_flag_enabled(&self, flag: HiTraceFlag) -> bool {
117        // Safty: call C ffi border function, all risks are under control.
118        unsafe {
119            HiTraceChainIsFlagEnabledWrapper(self as *const HiTraceId, flag as i32)
120        }
121    }
122
123    /// Enable the designative trace flag for the trace id.
124    pub fn enable_flag(&mut self, flag: HiTraceFlag) {
125        // Safty: call C ffi border function, all risks are under control.
126        unsafe {
127            HiTraceChainEnableFlagWrapper(self as *mut HiTraceId, flag as i32);
128        }
129    }
130
131    /// Set trace flags for the trace id.
132    pub fn set_flags(&mut self, flags: i32) {
133        // Safty: call C ffi border function, all risks are under control.
134        unsafe {
135            HiTraceChainSetFlagsWrapper(self as *mut HiTraceId, flags);
136        }
137    }
138
139    /// Get trace flags of the trace id.
140    pub fn get_flags(&self) -> i32 {
141        // Safty: call C ffi border function, all risks are under control.
142        unsafe {
143            HiTraceChainGetFlagsWrapper(self as *const HiTraceId)
144        }
145    }
146
147    /// Set chain id of the trace id.
148    pub fn set_chain_id(&mut self, chain_id: u64) {
149        // Safty: call C ffi border function, all risks are under control.
150        unsafe {
151            HiTraceChainSetChainIdWrapper(self as *mut HiTraceId, chain_id);
152        }
153    }
154
155    /// Get chain id of the trace id.
156    pub fn get_chain_id(&self) -> u64 {
157        // Safty: call C ffi border function, all risks are under control.
158        unsafe {
159            HiTraceChainGetChainIdWrapper(self as *const HiTraceId)
160        }
161    }
162
163    /// Set span id of the trace id.
164    pub fn set_span_id(&mut self, span_id: u64) {
165        // Safty: call C ffi border function, all risks are under control.
166        unsafe {
167            HiTraceChainSetSpanIdWrapper(self as *mut HiTraceId, span_id);
168        }
169    }
170
171    /// Get span id of the trace id.
172    pub fn get_span_id(&self)-> u64 {
173        // Safty: call C ffi border function, all risks are under control.
174        unsafe {
175            HiTraceChainGetSpanIdWrapper(self as *const HiTraceId)
176        }
177    }
178
179     /// Set parent span id of the trace id.
180    pub fn set_parent_span_id(&mut self, parent_span_id: u64) {
181        // Safty: call C ffi border function, all risks are under control.
182        unsafe {
183            HiTraceChainSetParentSpanIdWrapper(self as *mut HiTraceId, parent_span_id);
184        }
185    }
186
187    /// Get parent span id of the trace id.
188    pub fn get_parent_span_id(&self) -> u64 {
189        // Safty: call C ffi border function, all risks are under control.
190        unsafe {
191            HiTraceChainGetParentSpanIdWrapper(self as *const HiTraceId)
192        }
193    }
194}
195
196/// Start tracing a process impl.
197pub fn begin(name: &str, flags: i32) -> HiTraceId {
198    // Safty: call C ffi border function, all risks are under control.
199    unsafe {
200        let name = CString::new(name).unwrap();
201        HiTraceChainBegin(name.as_ptr() as *const c_char, flags)
202    }
203}
204
205/// Stop process tracing and clear trace id of current thread if the given trace
206/// id is valid, otherwise do nothing.
207pub fn end(id: &HiTraceId) {
208    // Safty: call C ffi border function, all risks are under control.
209    unsafe {
210        HiTraceChainEnd(id as *const HiTraceId);
211    }
212}
213
214/// Get trace id of current thread, and return a invalid trace id if no
215/// trace id belong to current thread
216pub fn get_id() -> HiTraceId {
217    // Safty: call C ffi border function, all risks are under control.
218    unsafe {
219        HiTraceChainGetId()
220    }
221}
222
223/// Set id as trace id of current thread. Do nothing if id is invalid.
224pub fn set_id(id: &HiTraceId) {
225    // Safty: call C ffi border function, all risks are under control.
226    unsafe {
227        HiTraceChainSetId(id as *const HiTraceId);
228    }
229}
230
231/// Clear trace id of current thread and set it invalid.
232pub fn clear_id() {
233    // Safty: call C ffi border function, all risks are under control.
234    unsafe {
235        HiTraceChainClearId();
236    }
237}
238
239/// Create a new span id according to the trace id of current thread.
240pub fn create_span() -> HiTraceId {
241    // Safty: call C ffi border function, all risks are under control.
242    unsafe {
243        HiTraceChainCreateSpan()
244    }
245}
246
247/// Persist a trace id into a uint8_t array
248pub fn id_to_bytes(p_id: &HiTraceId, p_id_array: &mut [u8]) -> i32 {
249    let arr_len = p_id_array.len();
250    let mut id_array_wrapper: Vec<u8> = vec![];
251    for &item in p_id_array.iter().take(arr_len) {
252        id_array_wrapper.push(item);
253    }
254    // Safty: call C ffi border function, all risks are under control.
255    unsafe {
256        let ret = HiTraceChainIdToBytesWrapper(p_id as *const HiTraceId,
257            id_array_wrapper.as_mut_ptr(),
258            arr_len as c_int);
259        p_id_array[..arr_len].copy_from_slice(&id_array_wrapper[..arr_len]);
260        ret
261    }
262}
263
264/// Build a trace id form a uint8_t array
265pub fn bytes_to_id(p_id_array: &[u8]) -> HiTraceId {
266    let mut id_array_wrapper: Vec<u8> = vec![];
267    for &item in p_id_array {
268        id_array_wrapper.push(item);
269    }
270    // Safty: call C ffi border function, all risks are under control.
271    unsafe {
272        HiTraceChainBytesToIdWrapper(id_array_wrapper.as_mut_ptr(), p_id_array.len() as c_int)
273    }
274}
275
276extern "C" {
277    /// ffi border function
278    fn HiTraceChainBegin(name: *const c_char, _flags: c_int) -> HiTraceId;
279
280    /// ffi border function
281    fn HiTraceChainEnd(id: *const HiTraceId);
282
283    /// ffi border function
284    fn HiTraceChainGetId() -> HiTraceId;
285
286    /// ffi border function
287    fn HiTraceChainSetId(id: *const HiTraceId);
288
289    /// ffi border function
290    fn HiTraceChainClearId();
291
292    /// ffi border function
293    fn HiTraceChainCreateSpan() -> HiTraceId;
294
295    /// ffi border function
296    fn HiTraceChainIdToBytesWrapper(id: *const HiTraceId, p_id_array: *const u8, len: c_int) -> c_int;
297
298    /// ffi border function
299    fn HiTraceChainBytesToIdWrapper(p_id_array: *const u8, len: c_int) -> HiTraceId;
300
301    /// ffi border function
302    #[allow(dead_code)]
303    pub fn HiTraceChainTracepointExWrapper(communication_mode: c_int, trace_type: c_int,
304        p_id: *const HiTraceId, fmt: *const c_char, ...);
305
306    /// ffi border function
307    fn HiTraceChainIsValidWrapper(p_id: *const HiTraceId) -> bool;
308
309    /// ffi border function
310    fn HiTraceChainIsFlagEnabledWrapper(p_id: *const HiTraceId, flag: c_int) -> bool;
311
312    /// ffi border function
313    fn HiTraceChainEnableFlagWrapper(p_id: *mut HiTraceId, flag: c_int);
314
315    /// ffi border function
316    fn HiTraceChainSetFlagsWrapper(p_id: *mut HiTraceId, flags: c_int);
317
318    /// ffi border function
319    fn HiTraceChainGetFlagsWrapper(p_id: *const HiTraceId) -> c_int;
320
321    /// ffi border function
322    fn HiTraceChainSetChainIdWrapper(p_id: *mut HiTraceId, chain_id: c_ulonglong);
323
324    /// ffi border function
325    fn HiTraceChainGetChainIdWrapper(p_id: *const HiTraceId) -> c_ulonglong;
326
327    /// ffi border function
328    fn HiTraceChainSetSpanIdWrapper(p_id: *mut HiTraceId, span_id: c_ulonglong);
329
330    /// ffi border function
331    fn HiTraceChainGetSpanIdWrapper(p_id: *const HiTraceId) -> c_ulonglong;
332
333    /// ffi border function
334    fn HiTraceChainSetParentSpanIdWrapper(p_id: *mut HiTraceId,
335        parent_span_id: c_ulonglong);
336
337    /// ffi border function
338    fn HiTraceChainGetParentSpanIdWrapper(p_id: *const HiTraceId) -> c_ulonglong;
339}
340