Skip to main content

gwr_track/tracker/
multi_tracker.rs

1// Copyright (c) 2023 Graphcore Ltd. All rights reserved.
2
3use crate::Id;
4use crate::entity::Capacity;
5use crate::tracker::aka::AlternativeNames;
6use crate::tracker::{EntityManager, Track, Tracker};
7
8/// Container for multiple [`Tracker`]s
9pub struct MultiTracker {
10    entity_manager: EntityManager,
11    trackers: Vec<Tracker>,
12}
13
14impl MultiTracker {
15    /// Basic constructor
16    /// Add a new tracker
17    pub fn add_tracker(&mut self, tracker: Tracker) {
18        self.trackers.push(tracker);
19    }
20}
21
22impl Default for MultiTracker {
23    fn default() -> Self {
24        Self {
25            // Create a local entity_manager that will just be used for handling IDs
26            entity_manager: EntityManager::new(log::Level::Error),
27            trackers: Vec::new(),
28        }
29    }
30}
31
32impl Track for MultiTracker {
33    fn unique_id(&self) -> Id {
34        self.entity_manager.unique_id()
35    }
36
37    fn enabled_level(&self, id: Id) -> log::Level {
38        self.trackers
39            .iter()
40            .map(|tracker| tracker.enabled_level(id))
41            .max()
42            .unwrap_or(log::Level::Error)
43    }
44
45    fn monitoring_window_size_for(&self, id: Id) -> Option<u64> {
46        for tracker in &self.trackers {
47            if let Some(window_size_ticks) = tracker.monitoring_window_size_for(id) {
48                return Some(window_size_ticks);
49            }
50        }
51        None
52    }
53
54    fn add_entity(
55        &self,
56        id: Id,
57        entity_name: &str,
58        alternative_names: AlternativeNames,
59    ) -> log::Level {
60        self.trackers
61            .iter()
62            .map(|tracker| tracker.add_entity(id, entity_name, alternative_names))
63            .max()
64            .unwrap_or(log::Level::Error)
65    }
66
67    fn enter(&self, id: Id, object: Id) {
68        for tracker in &self.trackers {
69            tracker.enter(id, object);
70        }
71    }
72
73    fn exit(&self, id: Id, object: Id) {
74        for tracker in &self.trackers {
75            tracker.exit(id, object);
76        }
77    }
78
79    fn value(&self, id: Id, value: f64) {
80        for tracker in &self.trackers {
81            tracker.value(id, value);
82        }
83    }
84
85    fn begin_activity(&self, activity: Id, lane: Id, name: &str) {
86        for tracker in &self.trackers {
87            tracker.begin_activity(activity, lane, name);
88        }
89    }
90
91    fn add_to_group(&self, activity: Id, group_id: Id) {
92        for tracker in &self.trackers {
93            tracker.add_to_group(activity, group_id);
94        }
95    }
96
97    fn remove_from_group(&self, activity: Id, group_id: Id) {
98        for tracker in &self.trackers {
99            tracker.remove_from_group(activity, group_id);
100        }
101    }
102
103    fn end_activity(&self, activity: Id) {
104        for tracker in &self.trackers {
105            tracker.end_activity(activity);
106        }
107    }
108
109    fn create_entity(&self, created_by: Id, id: Id, name: &str) {
110        for tracker in &self.trackers {
111            tracker.create_entity(created_by, id, name);
112        }
113    }
114
115    fn create_monitor(&self, created_by: Id, id: Id, name: &str) {
116        for tracker in &self.trackers {
117            tracker.create_monitor(created_by, id, name);
118        }
119    }
120
121    fn create_lane(&self, created_by: Id, id: Id, name: &str) {
122        for tracker in &self.trackers {
123            tracker.create_lane(created_by, id, name);
124        }
125    }
126
127    fn create_group(&self, created_by: Id, id: Id, name: &str) {
128        for tracker in &self.trackers {
129            tracker.create_group(created_by, id, name);
130        }
131    }
132
133    fn create_object(
134        &self,
135        created_by: Id,
136        id: Id,
137        size: usize,
138        units: &str,
139        req_type: u8,
140        details: &str,
141    ) {
142        for tracker in &self.trackers {
143            tracker.create_object(created_by, id, size, units, req_type, details);
144        }
145    }
146
147    fn capacity(&self, id: Id, capacity: Capacity) {
148        for tracker in &self.trackers {
149            tracker.capacity(id, capacity.clone());
150        }
151    }
152
153    fn destroy(&self, destroyed_by: Id, id: Id) {
154        for tracker in &self.trackers {
155            tracker.destroy(destroyed_by, id);
156        }
157    }
158
159    fn connect(&self, connect_from: Id, connect_to: Id) {
160        for tracker in &self.trackers {
161            tracker.connect(connect_from, connect_to);
162        }
163    }
164
165    fn log(&self, id: Id, level: log::Level, msg: std::fmt::Arguments) {
166        for tracker in &self.trackers {
167            tracker.log(id, level, msg);
168        }
169    }
170
171    fn time(&self, set_by: Id, time_ns: f64) {
172        for tracker in &self.trackers {
173            tracker.time(set_by, time_ns);
174        }
175    }
176
177    fn shutdown(&self) {
178        for tracker in &self.trackers {
179            tracker.shutdown();
180        }
181    }
182}
183
184#[cfg(test)]
185mod tests {
186    use std::rc::Rc;
187
188    use log::Level;
189
190    use super::MultiTracker;
191    use crate::Id;
192    use crate::test_helpers::{TestTracker, check_and_clear};
193    use crate::tracker::{Track, Tracker};
194
195    #[test]
196    fn log_events_are_delivered_to_all_sub_trackers_even_if_only_one_enables_the_level() {
197        let trace_tracker = Rc::new(TestTracker::new(100, Level::Trace));
198        let error_tracker = Rc::new(TestTracker::new(200, Level::Error));
199
200        let mut multi_tracker = MultiTracker::default();
201        let trace_tracker_dyn: Tracker = trace_tracker.clone();
202        let error_tracker_dyn: Tracker = error_tracker.clone();
203        multi_tracker.add_tracker(trace_tracker_dyn);
204        multi_tracker.add_tracker(error_tracker_dyn);
205
206        let entity_id = Id(42);
207        assert!(multi_tracker.is_entity_enabled(entity_id, Level::Trace));
208
209        multi_tracker.log(entity_id, Level::Trace, format_args!("fanout"));
210
211        check_and_clear(&trace_tracker, &["42:TRACE: fanout"]);
212        check_and_clear(&error_tracker, &["42:TRACE: fanout"]);
213    }
214}