trellis_runner/watchers/
tracing.rs1use num_traits::float::FloatCore;
2use tracing::Level;
3
4use crate::engine::{EngineSignal, Termination};
5use crate::progress::Progress;
6use crate::state::{StateView, UserState};
7use crate::watchers::Observe;
8
9macro_rules! log_at_level {
10 ($level:expr, $($arg:tt)*) => {{
11 match $level {
12 tracing::Level::ERROR => tracing::error!($($arg)*),
13 tracing::Level::WARN => tracing::warn!($($arg)*),
14 tracing::Level::INFO => tracing::info!($($arg)*),
15 tracing::Level::DEBUG => tracing::debug!($($arg)*),
16 tracing::Level::TRACE => tracing::trace!($($arg)*),
17 }
18 }};
19}
20
21#[derive(Clone)]
27pub struct Tracer {
28 level: Level,
29}
30
31impl Tracer {
32 pub fn new(level: Level) -> Self {
37 if matches!(level, Level::ERROR | Level::WARN) {
38 panic!("Tracer only supports INFO, DEBUG, TRACE levels");
39 }
40
41 Self { level }
42 }
43
44 fn lifecycle(&self, ident: &str, event_name: &str) {
45 log_at_level!(
46 self.level,
47 target: "engine.lifecycle",
48 ident = ident,
49 event = event_name,
50 );
51 }
52
53 fn termination(&self, ident: &str, termination: Termination) {
54 log_at_level!(
55 self.level,
56 target: "engine.termination",
57 ident = ident,
58 ?termination
59 );
60 }
61
62 fn progress<S>(&self, state: StateView<'_, S>, progress: &Progress<S::Float>)
63 where
64 S: UserState,
65 S::Float: FloatCore + tracing::Value,
66 {
67 match progress {
68 Progress::Measure(value) => {
69 log_at_level!(
70 self.level,
71 target: "engine.progress",
72 kind = "metric",
73 iteration = state.iteration(),
74 value = *value
75 );
76 }
77
78 Progress::Report {
79 measure,
80 diagnostics,
81 } => {
82 log_at_level!(
83 self.level,
84 target: "engine.progress",
85 kind = "report",
86 iteration = state.iteration(),
87 measure = *measure,
88 ?diagnostics
89 );
90 }
91
92 Progress::Complete => {
93 log_at_level!(
94 self.level,
95 target: "engine.progress",
96 kind = "complete",
97 iteration = state.iteration()
98 );
99 }
100 }
101 }
102}
103
104impl<S> Observe<S> for Tracer
105where
106 S: UserState,
107 S::Float: FloatCore + tracing::Value,
108{
109 fn observe(
110 &self,
111 ident: &'static str,
112 state: StateView<'_, S>,
113 event: &EngineSignal<S::Float>,
114 ) {
115 match event {
116 EngineSignal::Initialised => {
117 self.lifecycle(ident, "initialised");
118 }
119
120 EngineSignal::CheckpointSaved => {
121 self.lifecycle(ident, "checkpoint_saved");
122 }
123
124 EngineSignal::CheckpointRequested(_) => {
125 self.lifecycle(ident, "checkpoint_requested");
126 }
127
128 EngineSignal::Termination(reason) => {
129 self.termination(ident, *reason);
130 }
131
132 EngineSignal::Progress(progress) => {
133 self.progress(state, progress);
134 }
135 }
136 }
137}