1#![doc = include_str!("../README.md")]
16#![deny(missing_docs)]
17#![warn(clippy::undocumented_unsafe_blocks)]
18#![cfg_attr(
19 feature = "intrinsics",
20 allow(internal_features),
21 feature(core_intrinsics)
22)]
23
24pub mod data_source;
26
27pub mod heap_buffer;
29
30pub mod pb_decoder;
32
33pub mod pb_msg;
35
36pub mod pb_utils;
38
39pub mod producer;
41
42pub mod protos;
44
45pub mod stream_writer;
47
48pub mod tracing_session;
50
51pub mod track_event;
53
54const FNV64_OFFSET: u64 = 0xcbf29ce484222325;
56const FNV64_PRIME: u64 = 0x00000100000001B3;
57
58pub const fn fnv1a(bytes: &[u8]) -> u64 {
60 let mut hash = FNV64_OFFSET;
61 let mut i = 0;
62 while i < bytes.len() {
63 hash ^= bytes[i] as u64;
64 hash = hash.wrapping_mul(FNV64_PRIME);
65 i += 1;
66 }
67 hash
68}
69
70#[cfg(feature = "intrinsics")]
72#[doc(hidden)]
73#[macro_export]
74macro_rules! __likely {
75 ($e:expr) => {{ std::intrinsics::likely($e) }};
76}
77
78#[cfg(not(feature = "intrinsics"))]
80#[doc(hidden)]
81#[macro_export]
82macro_rules! __likely {
83 ($e:expr) => {{ $e }};
84}
85
86#[cfg(feature = "intrinsics")]
88#[doc(hidden)]
89#[macro_export]
90macro_rules! __unlikely {
91 ($e:expr) => {{ std::intrinsics::unlikely($e) }};
92}
93
94#[cfg(not(feature = "intrinsics"))]
96#[doc(hidden)]
97#[macro_export]
98macro_rules! __unlikely {
99 ($e:expr) => {{ $e }};
100}
101
102#[doc(hidden)]
104pub fn __box_as_mut_ptr<T: ?Sized>(b: &mut Box<T>) -> *mut T {
105 &raw mut **b
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112 use crate::producer::{Backends, Producer, ProducerInitArgsBuilder};
113 use crate::tracing_session::*;
114 use std::sync::{Mutex, MutexGuard, Once};
115
116 static INIT_TEST_ENVIRONMENT: Once = Once::new();
117 static TEST_ENVIRONMENT_MUTEX: Mutex<()> = Mutex::new(());
118
119 pub(crate) const PRODUCER_SHMEM_SIZE_HINT_KB: u32 = 64;
120
121 pub(crate) fn acquire_test_environment() -> MutexGuard<'static, ()> {
124 INIT_TEST_ENVIRONMENT.call_once(|| {
125 let producer_args = ProducerInitArgsBuilder::new()
126 .backends(Backends::IN_PROCESS)
127 .shmem_size_hint_kb(PRODUCER_SHMEM_SIZE_HINT_KB);
128 Producer::init(producer_args.build());
129 });
130 TEST_ENVIRONMENT_MUTEX.lock().unwrap()
131 }
132
133 #[derive(Default)]
134 #[must_use = "This is a builder; remember to call `.build()` (or keep chaining)."]
135 pub(crate) struct TracingSessionBuilder {
136 data_source_name: String,
137 enabled_categories: Vec<String>,
138 disabled_categories: Vec<String>,
139 }
140
141 impl TracingSessionBuilder {
142 pub fn new() -> Self {
143 Self::default()
144 }
145
146 #[must_use = "Builder methods return an updated builder; use the returned value or keep chaining."]
147 pub fn set_data_source_name(mut self, name: impl Into<String>) -> Self {
148 self.data_source_name = name.into();
149 self
150 }
151
152 #[must_use = "Builder methods return an updated builder; use the returned value or keep chaining."]
153 pub fn add_enabled_category(mut self, category: impl Into<String>) -> Self {
154 self.enabled_categories.push(category.into());
155 self
156 }
157
158 #[must_use = "Builder methods return an updated builder; use the returned value or keep chaining."]
159 pub fn add_disabled_category(mut self, category: impl Into<String>) -> Self {
160 self.disabled_categories.push(category.into());
161 self
162 }
163
164 fn build_proto_config(&self) -> Vec<u8> {
165 use crate::{
166 heap_buffer::HeapBuffer,
167 pb_msg::{PbMsg, PbMsgWriter},
168 protos::config::{
169 data_source_config::DataSourceConfig,
170 trace_config::{TraceConfig, TraceConfigBufferConfig, TraceConfigDataSource},
171 track_event::track_event_config::TrackEventConfig,
172 },
173 };
174 let writer = PbMsgWriter::new();
175 let hb = HeapBuffer::new(&writer.writer);
176 let mut msg = PbMsg::new(&writer).unwrap();
177 {
178 let mut cfg = TraceConfig { msg: &mut msg };
179 cfg.set_buffers(|buf_cfg: &mut TraceConfigBufferConfig| {
180 buf_cfg.set_size_kb(1024);
181 });
182 cfg.set_data_sources(|data_sources: &mut TraceConfigDataSource| {
183 data_sources.set_config(|ds_cfg: &mut DataSourceConfig| {
184 ds_cfg.set_name(&self.data_source_name);
185 if !self.enabled_categories.is_empty()
186 || !self.disabled_categories.is_empty()
187 {
188 ds_cfg.set_track_event_config(|te_cfg: &mut TrackEventConfig| {
189 for enabled_catagory in &self.enabled_categories {
190 te_cfg.set_enabled_categories(enabled_catagory);
191 }
192 for disabled_catagory in &self.disabled_categories {
193 te_cfg.set_disabled_categories(disabled_catagory);
194 }
195 });
196 }
197 });
198 });
199 }
200 msg.finalize();
201 let cfg_size = writer.writer.get_written_size();
202 let mut cfg_buffer: Vec<u8> = vec![0u8; cfg_size];
203 hb.copy_into(&mut cfg_buffer);
204
205 cfg_buffer
206 }
207
208 pub fn build(&self) -> Result<TracingSession, TracingSessionError> {
209 let config = self.build_proto_config();
210 let mut ts = TracingSession::in_process()?;
211 ts.setup(&config);
212 Ok(ts)
213 }
214 }
215
216 #[test]
217 fn fnv1a_hash() {
218 assert_eq!(fnv1a("mytrack".as_bytes()), 9332035348890697650);
219 }
220
221 #[test]
222 fn unlikely_conditional() {
223 if __unlikely!(fnv1a("mystring".as_bytes()) == 0) {
224 unreachable!();
225 }
226 }
227}