Skip to main content

ai_agent/analytics/
mod.rs

1use std::sync::Arc;
2use std::sync::atomic::{AtomicU64, Ordering};
3
4#[derive(Debug, Clone)]
5pub enum AnalyticsEvent {
6    PageView {
7        path: String,
8    },
9    Action {
10        name: String,
11        metadata: Vec<(String, String)>,
12    },
13    Error {
14        message: String,
15        stack: Option<String>,
16    },
17    Performance {
18        metric: String,
19        value: f64,
20    },
21}
22
23#[derive(Debug, Default)]
24pub struct GleanTracker {
25    event_count: AtomicU64,
26    enabled: Arc<AtomicU64>,
27}
28
29impl GleanTracker {
30    pub fn new() -> Self {
31        Self::default()
32    }
33
34    pub fn track(&self, event: AnalyticsEvent) {
35        if self.is_enabled() {
36            self.event_count.fetch_add(1, Ordering::Relaxed);
37            self.send_event(event);
38        }
39    }
40
41    pub fn is_enabled(&self) -> bool {
42        self.enabled.load(Ordering::Relaxed) == 1
43    }
44
45    pub fn set_enabled(&self, enabled: bool) {
46        self.enabled
47            .store(if enabled { 1 } else { 0 }, Ordering::Relaxed);
48    }
49
50    pub fn event_count(&self) -> u64 {
51        self.event_count.load(Ordering::Relaxed)
52    }
53
54    fn send_event(&self, _event: AnalyticsEvent) {}
55}
56
57pub fn track_page_view(tracker: &GleanTracker, path: &str) {
58    tracker.track(AnalyticsEvent::PageView {
59        path: path.to_string(),
60    });
61}
62
63pub fn track_action(tracker: &GleanTracker, name: &str, metadata: Vec<(String, String)>) {
64    tracker.track(AnalyticsEvent::Action {
65        name: name.to_string(),
66        metadata,
67    });
68}
69
70pub fn track_error(tracker: &GleanTracker, message: &str, stack: Option<String>) {
71    tracker.track(AnalyticsEvent::Error {
72        message: message.to_string(),
73        stack,
74    });
75}
76
77pub fn track_performance(tracker: &GleanTracker, metric: &str, value: f64) {
78    tracker.track(AnalyticsEvent::Performance {
79        metric: metric.to_string(),
80        value,
81    });
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_tracker_disabled() {
90        let tracker = GleanTracker::new();
91        tracker.set_enabled(false);
92        tracker.track(AnalyticsEvent::PageView {
93            path: "/test".to_string(),
94        });
95        assert_eq!(tracker.event_count(), 0);
96    }
97
98    #[test]
99    fn test_tracker_enabled() {
100        let tracker = GleanTracker::new();
101        tracker.set_enabled(true);
102        track_page_view(&tracker, "/test");
103        assert_eq!(tracker.event_count(), 1);
104    }
105}