veecle_telemetry/collector/
global.rs1use core::sync::atomic::{AtomicUsize, Ordering};
4
5use core::{error, fmt};
6
7use super::{Collector, Export, InstanceMessage, ProcessId};
8
9#[derive(Debug)]
11struct NopExporter;
12
13impl Export for NopExporter {
14 fn export(&self, _: InstanceMessage) {}
15}
16
17static NO_EXPORTER: NopExporter = NopExporter;
18
19static NO_COLLECTOR: Collector = Collector::new(
20 ProcessId::from_raw(0),
21 &NO_EXPORTER,
22 nop_timestamp,
23 nop_thread_id,
24);
25
26static mut GLOBAL_COLLECTOR: Collector = Collector::new(
29 ProcessId::from_raw(0),
30 &NO_EXPORTER,
31 nop_timestamp,
32 nop_thread_id,
33);
34
35fn nop_timestamp() -> u64 {
36 0
37}
38
39fn nop_thread_id() -> core::num::NonZeroU64 {
40 core::num::NonZeroU64::new(1).unwrap()
41}
42
43static GLOBAL_INIT: AtomicUsize = AtomicUsize::new(0);
44
45const UNINITIALIZED: usize = 0;
50const INITIALIZING: usize = 1;
51const INITIALIZED: usize = 2;
52
53pub(super) fn set_collector(collector: Collector) -> Result<(), SetGlobalError> {
55 if GLOBAL_INIT
56 .compare_exchange(
57 UNINITIALIZED,
58 INITIALIZING,
59 Ordering::Acquire,
60 Ordering::Relaxed,
61 )
62 .is_ok()
63 {
64 unsafe { GLOBAL_COLLECTOR = collector }
66 GLOBAL_INIT.store(INITIALIZED, Ordering::Release);
67 Ok(())
68 } else {
69 Err(SetGlobalError(()))
70 }
71}
72
73pub fn get_collector() -> &'static Collector {
77 #[cfg(not(feature = "enable"))]
78 {
79 &NO_COLLECTOR
80 }
81
82 #[cfg(feature = "enable")]
83 if GLOBAL_INIT.load(Ordering::Acquire) != INITIALIZED {
92 &NO_COLLECTOR
93 } else {
94 unsafe {
96 #[expect(clippy::deref_addrof, reason = "false positive")]
97 &*&raw const GLOBAL_COLLECTOR
98 }
99 }
100}
101
102#[derive(Debug)]
104pub struct SetGlobalError(());
105
106impl SetGlobalError {
107 const MESSAGE: &'static str = "a global exporter has already been set";
108}
109
110impl fmt::Display for SetGlobalError {
111 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
112 fmt.write_str(Self::MESSAGE)
113 }
114}
115
116impl error::Error for SetGlobalError {}