Skip to main content

gwr_track/tracker/
capnp.rs

1// Copyright (c) 2020 Graphcore Ltd. All rights reserved.
2
3use std::cell::RefCell;
4use std::rc::Rc;
5
6use capnp::serialize_packed;
7
8use crate::entity::Capacity;
9use crate::gwr_track_capnp::event;
10use crate::gwr_track_capnp::log::LogLevel;
11use crate::tracker::aka::AlternativeNames;
12use crate::tracker::{EntityManager, Track};
13use crate::{Id, SharedWriter, Writer, gwr_track_capnp};
14
15/// A tracker that writes Cap'n Proto binary data
16pub struct CapnProtoTracker {
17    entity_manager: EntityManager,
18    writer: SharedWriter,
19}
20
21impl CapnProtoTracker {
22    /// Create a new [`CapnProtoTracker`] with an [`EntityManager`]
23    pub fn new(entity_manager: EntityManager, writer: Writer) -> Self {
24        Self {
25            entity_manager,
26            writer: Rc::new(RefCell::new(writer)),
27        }
28    }
29
30    /// Helper function to create a _trace_ event
31    ///
32    /// # Arguments
33    ///
34    /// * `event_loc` - A [EventLocation](struct.EventLocation.html) giving
35    ///   details of the location
36    /// * `lvl` - The logging level which is used to filter events
37    /// * `build` - The event builder function
38    fn write_event<F>(&self, id: Id, build: F)
39    where
40        F: FnOnce(gwr_track_capnp::event::Builder<'_>),
41    {
42        let mut builder = capnp::message::Builder::new_default();
43        {
44            let mut event = builder.init_root::<event::Builder>();
45            event.set_id(id.0);
46
47            // Call build method to populate the rest of the event
48            build(event);
49        }
50
51        // Write out the event to the file
52        let mut writer_ref = self.writer.borrow_mut();
53        serialize_packed::write_message(&mut *writer_ref, &builder).unwrap();
54    }
55}
56
57/// Implementation each [`Track`] event
58///
59/// There is a function to emit each Cap'n Proto event structure. These
60/// functions call the helper function
61/// [`write_event`](crate::tracker::capnp::CapnProtoTracker), passing in a
62/// function that is used to populate the event body.
63impl Track for CapnProtoTracker {
64    fn unique_id(&self) -> Id {
65        self.entity_manager.unique_id()
66    }
67
68    fn enabled_level(&self, id: Id) -> log::Level {
69        self.entity_manager.enabled_level(id)
70    }
71
72    fn monitoring_window_size_for(&self, id: Id) -> Option<u64> {
73        self.entity_manager.monitoring_window_size_for(id)
74    }
75
76    fn add_entity(
77        &self,
78        id: Id,
79        entity_name: &str,
80        alternative_names: AlternativeNames,
81    ) -> log::Level {
82        self.entity_manager
83            .add_entity(id, entity_name, alternative_names)
84    }
85
86    fn enter(&self, id: Id, object: Id) {
87        if self.is_entity_enabled(id, log::Level::Trace) {
88            self.write_event(id, |mut event| {
89                event.set_enter(object.0);
90            });
91        }
92    }
93
94    fn exit(&self, id: Id, object: Id) {
95        if self.is_entity_enabled(id, log::Level::Trace) {
96            self.write_event(id, |mut event| {
97                event.set_exit(object.0);
98            });
99        }
100    }
101
102    fn value(&self, id: Id, value: f64) {
103        if self.is_entity_enabled(id, log::Level::Trace) {
104            self.write_event(id, |mut event| {
105                event.set_value(value);
106            });
107        }
108    }
109
110    fn begin_activity(&self, activity: Id, lane: Id, name: &str) {
111        if self.is_entity_enabled(lane, log::Level::Trace) {
112            self.write_event(activity, |event| {
113                let mut begin_activity = event.init_begin_activity();
114                begin_activity.set_lane(lane.0);
115                begin_activity.set_name(name);
116            });
117        }
118    }
119
120    fn add_to_group(&self, activity: Id, group_id: Id) {
121        self.write_event(activity, |mut event| {
122            event.set_add_to_group(group_id.0);
123        });
124    }
125
126    fn remove_from_group(&self, activity: Id, group_id: Id) {
127        self.write_event(activity, |mut event| {
128            event.set_remove_from_group(group_id.0);
129        });
130    }
131
132    fn end_activity(&self, activity: Id) {
133        self.write_event(activity, |mut event| {
134            event.set_end_activity(());
135        });
136    }
137
138    fn create_entity(&self, created_by: Id, id: Id, name: &str) {
139        // Don't filter this event as it could be required by a GUI
140        self.write_event(created_by, |event| {
141            let mut create = event.init_create();
142            create.set_id(id.0);
143            create.init_entity().set_name(name);
144        });
145    }
146
147    fn create_monitor(&self, created_by: Id, id: Id, name: &str) {
148        // Don't filter this event as it could be required by a GUI
149        self.write_event(created_by, |event| {
150            let mut create = event.init_create();
151            create.set_id(id.0);
152            create.init_monitor().set_name(name);
153        });
154    }
155
156    fn create_lane(&self, created_by: Id, id: Id, name: &str) {
157        // Don't filter this event as it could be required by a GUI
158        self.write_event(created_by, |event| {
159            let mut create = event.init_create();
160            create.set_id(id.0);
161            create.init_lane().set_name(name);
162        });
163    }
164
165    fn create_group(&self, created_by: Id, id: Id, name: &str) {
166        // Don't filter this event as it could be required by a GUI
167        self.write_event(created_by, |event| {
168            let mut create = event.init_create();
169            create.set_id(id.0);
170            create.init_group().set_name(name);
171        });
172    }
173
174    fn create_object(
175        &self,
176        created_by: Id,
177        id: Id,
178        size: usize,
179        units: &str,
180        req_type: u8,
181        details: &str,
182    ) {
183        if self.is_entity_enabled(created_by, log::Level::Trace) {
184            self.write_event(created_by, |event| {
185                let mut create = event.init_create();
186                create.set_id(id.0);
187                let mut object = create.init_object();
188                object.set_size(size as u64);
189                object.set_units(units);
190                object.set_type(req_type);
191                object.set_details(details);
192            });
193        }
194    }
195
196    fn capacity(&self, id: Id, capacity: Capacity) {
197        // Don't filter this event as it could be required by a GUI
198        self.write_event(id, |event| {
199            let mut event_capacity = event.init_capacity();
200            event_capacity.set_value(capacity.value as u64);
201            event_capacity.set_units(&capacity.units);
202        });
203    }
204
205    fn destroy(&self, destroyed_by: Id, id: Id) {
206        if self.is_entity_enabled(id, log::Level::Trace) {
207            self.write_event(destroyed_by, |mut event| {
208                event.set_destroy(id.0);
209            });
210        }
211    }
212
213    fn connect(&self, connect_from: Id, connect_to: Id) {
214        if self.is_entity_enabled(connect_from, log::Level::Trace)
215            || self.is_entity_enabled(connect_to, log::Level::Trace)
216        {
217            self.write_event(connect_from, |mut event| {
218                event.set_connect(connect_to.0);
219            });
220        }
221    }
222
223    fn log(&self, id: Id, level: log::Level, msg: std::fmt::Arguments) {
224        if self.is_entity_enabled(id, level) {
225            self.write_event(id, |event| {
226                let mut log = event.init_log();
227                let txt = format!("{msg}");
228                log.set_message(&txt);
229                log.set_level(to_capnp_log_level(level));
230            });
231        }
232    }
233
234    fn time(&self, set_by: Id, time_ns: f64) {
235        self.write_event(set_by, |mut event| {
236            event.set_time(time_ns);
237        });
238    }
239
240    fn shutdown(&self) {
241        self.writer.borrow_mut().flush().unwrap();
242    }
243}
244
245fn to_capnp_log_level(level: log::Level) -> LogLevel {
246    match level {
247        log::Level::Error => LogLevel::Error,
248        log::Level::Warn => LogLevel::Warn,
249        log::Level::Info => LogLevel::Info,
250        log::Level::Debug => LogLevel::Debug,
251        log::Level::Trace => LogLevel::Trace,
252    }
253}