geographdb_core/
telemetry.rs1#[cfg(feature = "telemetry")]
10use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
11
12#[cfg(feature = "telemetry")]
14pub struct OpTracer {
15 call_counts: dashmap::DashMap<String, AtomicU64>,
16}
17
18#[cfg(feature = "telemetry")]
19impl OpTracer {
20 pub fn new() -> Self {
21 Self {
22 call_counts: dashmap::DashMap::new(),
23 }
24 }
25
26 pub fn trace(&self, op: &str, file: &str, line: u32) {
27 let key = format!("{}:{}:{}", file, line, op);
28 let count = self
29 .call_counts
30 .entry(key.clone())
31 .or_insert(AtomicU64::new(0));
32 let new_count = count.fetch_add(1, Ordering::SeqCst) + 1;
33
34 if new_count > 100 {
36 tracing::warn!(
37 "Operation {} called {} times - possible loop",
38 key,
39 new_count
40 );
41 }
42 }
43}
44
45#[cfg(feature = "telemetry")]
46impl Default for OpTracer {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52#[cfg(not(feature = "telemetry"))]
53impl Default for OpTracer {
54 fn default() -> Self {
55 Self::new()
56 }
57}
58
59#[cfg(feature = "telemetry")]
61pub struct LoopGuard {
62 name: &'static str,
63 max_iterations: usize,
64 counter: AtomicUsize,
65}
66
67#[cfg(feature = "telemetry")]
68impl LoopGuard {
69 pub fn new(name: &'static str, max_iterations: usize) -> Self {
70 Self {
71 name,
72 max_iterations,
73 counter: AtomicUsize::new(0),
74 }
75 }
76
77 pub fn check(&self) -> Result<(), String> {
78 let count = self.counter.fetch_add(1, Ordering::SeqCst);
79 if count >= self.max_iterations {
80 return Err(format!(
81 "LoopGuard '{}' exceeded max iterations: {}",
82 self.name, self.max_iterations
83 ));
84 }
85 Ok(())
86 }
87}
88
89#[cfg(feature = "telemetry")]
90impl Drop for LoopGuard {
91 fn drop(&mut self) {
92 let count = self.counter.load(Ordering::SeqCst);
93 if count > self.max_iterations / 2 {
94 tracing::info!("LoopGuard '{}' iterations: {}", self.name, count);
95 }
96 }
97}
98
99#[cfg(not(feature = "telemetry"))]
101pub struct OpTracer;
102
103#[cfg(not(feature = "telemetry"))]
104impl OpTracer {
105 pub fn new() -> Self {
106 Self
107 }
108 pub fn trace(&self, _op: &str, _file: &str, _line: u32) {}
109}
110
111#[cfg(not(feature = "telemetry"))]
112pub struct LoopGuard;
113
114#[cfg(not(feature = "telemetry"))]
115impl LoopGuard {
116 pub fn new(_name: &'static str, _max_iterations: usize) -> Self {
117 Self
118 }
119 pub fn check(&self) -> Result<(), String> {
120 Ok(())
121 }
122}