mithril_aggregator/runtime/
error.rs1use slog::{crit, error, Logger};
2use thiserror::Error;
3
4use mithril_common::StdError;
5
6#[derive(Error, Debug)]
10pub enum RuntimeError {
11 #[error("An error occurred, runtime state kept. message = '{message}'")]
13 KeepState {
14 message: String,
16
17 #[source]
19 nested_error: Option<StdError>,
20 },
21 #[error("A critical error occurred, aborting runtime. message = '{message}'")]
24 Critical {
25 message: String,
27
28 #[source]
30 nested_error: Option<StdError>,
31 },
32 #[error("An error occurred, runtime will be re-initialized. message = '{message}'")]
34 ReInit {
35 message: String,
37
38 #[source]
40 nested_error: Option<StdError>,
41 },
42}
43
44impl RuntimeError {
45 pub fn is_critical(&self) -> bool {
47 matches!(self, RuntimeError::Critical { .. })
48 }
49
50 pub fn keep_state(message: &str, error: Option<StdError>) -> Self {
52 Self::KeepState {
53 message: message.to_string(),
54 nested_error: error,
55 }
56 }
57
58 pub fn critical(message: &str, error: Option<StdError>) -> Self {
60 Self::Critical {
61 message: message.to_string(),
62 nested_error: error,
63 }
64 }
65
66 pub fn write_to_log(&self, logger: &Logger) {
68 match self {
69 Self::KeepState { nested_error, .. } | Self::ReInit { nested_error, .. } => {
70 match nested_error {
71 None => error!(logger, "{self}"),
72 Some(err) => error!(logger, "{self}"; "nested_error" => ?err),
73 }
74 }
75 Self::Critical { nested_error, .. } => match nested_error {
76 None => crit!(logger, "{self}"),
77 Some(err) => crit!(logger, "{self}"; "nested_error" => ?err),
78 },
79 }
80 }
81}
82
83impl From<StdError> for RuntimeError {
84 fn from(value: StdError) -> Self {
85 Self::KeepState {
86 message: "Error caught, state preserved, will retry to cycle.".to_string(),
87 nested_error: Some(value),
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use anyhow::anyhow;
95 use std::path::Path;
96
97 use mithril_common::test_utils::TempDir;
98
99 use crate::test_tools::TestLogger;
100
101 use super::*;
102
103 fn write_log(log_file: &Path, error: &RuntimeError) {
105 let logger = TestLogger::file(log_file);
106 error.write_to_log(&logger);
107 }
108
109 fn nested_error_debug_string(error: &RuntimeError) -> String {
110 let error = match error {
111 RuntimeError::KeepState { nested_error, .. } => nested_error,
112 RuntimeError::Critical { nested_error, .. } => nested_error,
113 RuntimeError::ReInit { nested_error, .. } => nested_error,
114 };
115 match error {
116 None => String::new(),
117 Some(err) => {
118 format!("{err:?}")
119 }
120 }
121 }
122
123 #[test]
124 fn log_critical_without_nested_error() {
125 let log_file = TempDir::create(
126 "aggregator_runtime_error",
127 "log_critical_without_nested_error",
128 )
129 .join("file.log");
130
131 let error = RuntimeError::Critical {
132 message: "Critical error".to_string(),
133 nested_error: None,
134 };
135 write_log(&log_file, &error);
136
137 let log_content = std::fs::read_to_string(&log_file).unwrap();
138 assert!(log_content.contains(&format!("{error}")));
139 assert!(!log_content.contains("nested_error"));
140 }
141
142 #[test]
143 fn log_critical_with_nested_error() {
144 let log_file =
145 TempDir::create("aggregator_runtime_error", "log_critical_with_nested_error")
146 .join("file.log");
147
148 let error = RuntimeError::Critical {
149 message: "Critical error".to_string(),
150 nested_error: Some(
151 anyhow!("Another context error")
152 .context("Context error")
153 .context("Critical nested error"),
154 ),
155 };
156 write_log(&log_file, &error);
157
158 let log_content = std::fs::read_to_string(&log_file).unwrap();
159 assert!(log_content.contains(&format!("{error}")));
160 assert!(log_content.contains(&nested_error_debug_string(&error)));
161 }
162
163 #[test]
164 fn log_keep_state_without_nested_error() {
165 let log_file = TempDir::create(
166 "aggregator_runtime_error",
167 "log_keep_state_without_nested_error",
168 )
169 .join("file.log");
170
171 let error = RuntimeError::KeepState {
172 message: "KeepState error".to_string(),
173 nested_error: None,
174 };
175 write_log(&log_file, &error);
176
177 let log_content = std::fs::read_to_string(&log_file).unwrap();
178 assert!(log_content.contains(&format!("{error}")));
179 assert!(!log_content.contains("nested_error"));
180 }
181
182 #[test]
183 fn log_keep_state_with_nested_error() {
184 let log_file = TempDir::create(
185 "aggregator_runtime_error",
186 "log_keep_state_with_nested_error",
187 )
188 .join("file.log");
189
190 let error = RuntimeError::KeepState {
191 message: "KeepState error".to_string(),
192 nested_error: Some(
193 anyhow!("Another context error")
194 .context("Context error")
195 .context("KeepState nested error"),
196 ),
197 };
198 write_log(&log_file, &error);
199
200 let log_content = std::fs::read_to_string(&log_file).unwrap();
201 assert!(log_content.contains(&format!("{error}")));
202 assert!(log_content.contains(&nested_error_debug_string(&error)));
203 }
204
205 #[test]
206 fn log_reinit_without_nested_error() {
207 let log_file = TempDir::create(
208 "aggregator_runtime_error",
209 "log_reinit_without_nested_error",
210 )
211 .join("file.log");
212
213 let error = RuntimeError::ReInit {
214 message: "ReInit error".to_string(),
215 nested_error: None,
216 };
217 write_log(&log_file, &error);
218
219 let log_content = std::fs::read_to_string(&log_file).unwrap();
220 assert!(log_content.contains(&format!("{error}")));
221 assert!(!log_content.contains("nested_error"));
222 }
223
224 #[test]
225 fn log_reinit_with_nested_error() {
226 let log_file = TempDir::create("aggregator_runtime_error", "log_reinit_with_nested_error")
227 .join("file.log");
228
229 let error = RuntimeError::ReInit {
230 message: "ReInit error".to_string(),
231 nested_error: Some(
232 anyhow!("Another context error")
233 .context("Context error")
234 .context("ReInit nested error"),
235 ),
236 };
237 write_log(&log_file, &error);
238
239 let log_content = std::fs::read_to_string(&log_file).unwrap();
240 assert!(log_content.contains(&format!("{error}")));
241 assert!(log_content.contains(&nested_error_debug_string(&error)));
242 }
243}