qubit_dcl/double_checked/execution_logger.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # Execution Logger
10//!
11//! Logging configuration and helpers for the double-checked lock executor.
12//!
13//! # Author
14//!
15//! Haixing Hu
16
17use std::fmt;
18
19/// Logger for double-checked execution (condition unmet, prepare failures,
20/// prepare commit failures, and prepare rollback failures).
21///
22/// Each event has its own optional [`log::Level`] and message. `None` means
23/// that event does not emit logs. For prepare-style events the message is a
24/// prefix formatted as `"{prefix}: {error}"`.
25///
26/// [`ExecutionLogger::default`] matches the previous `Option` logger unset
27/// behavior: condition-unmet is silent (`None`); prepare lifecycle lines use
28/// [`log::Level::Error`] with English default prefixes.
29///
30/// # Author
31///
32/// Haixing Hu
33#[derive(Debug, Clone)]
34pub struct ExecutionLogger {
35 /// Log level for the condition-unmet message; `None` skips it.
36 unmet_condition_level: Option<log::Level>,
37
38 /// Message logged when the execution condition is not met.
39 unmet_condition_message: String,
40
41 /// Log level for prepare-action failure lines; `None` skips them.
42 prepare_failed_level: Option<log::Level>,
43
44 /// Prefix for prepare-failure lines, formatted as `"{prefix}: {error}"`.
45 prepare_failed_message: String,
46
47 /// Log level for prepare-commit failure lines; `None` skips them.
48 prepare_commit_failed_level: Option<log::Level>,
49
50 /// Prefix for prepare-commit failure lines, formatted as `"{prefix}: {error}"`.
51 prepare_commit_failed_message: String,
52
53 /// Log level for prepare-rollback failure lines; `None` skips them.
54 prepare_rollback_failed_level: Option<log::Level>,
55
56 /// Prefix for prepare-rollback failure lines, formatted as
57 /// `"{prefix}: {error}"`.
58 prepare_rollback_failed_message: String,
59}
60
61impl Default for ExecutionLogger {
62 /// Returns the logger configuration used when the executor builder does not
63 /// apply any logging overrides.
64 ///
65 /// Condition-unmet logging is disabled ([`ExecutionLogger::unmet_condition_level`]
66 /// is [`None`]). Prepare lifecycle failures log at [`log::Level::Error`] with
67 /// short English default prefixes (see the field defaults on [`ExecutionLogger`]).
68 ///
69 /// # Returns
70 ///
71 /// A new [`ExecutionLogger`] with the values described above.
72 #[inline]
73 fn default() -> Self {
74 Self {
75 unmet_condition_level: None,
76 unmet_condition_message: String::new(),
77 prepare_failed_level: Some(log::Level::Error),
78 prepare_failed_message: "Prepare action failed".to_string(),
79 prepare_commit_failed_level: Some(log::Level::Error),
80 prepare_commit_failed_message: "Prepare commit action failed".to_string(),
81 prepare_rollback_failed_level: Some(log::Level::Error),
82 prepare_rollback_failed_message: "Prepare rollback action failed".to_string(),
83 }
84 }
85}
86
87impl ExecutionLogger {
88 /// Returns the configured level for unmet-condition logging.
89 ///
90 /// [`None`] means the event does not emit a log line.
91 #[inline]
92 pub fn unmet_condition_level(&self) -> Option<log::Level> {
93 self.unmet_condition_level
94 }
95
96 /// Returns the message used for unmet-condition logging.
97 #[inline]
98 pub fn unmet_condition_message(&self) -> &str {
99 &self.unmet_condition_message
100 }
101
102 /// Returns the configured level for prepare-action failures.
103 ///
104 /// [`None`] means the event does not emit a log line.
105 #[inline]
106 pub fn prepare_failed_level(&self) -> Option<log::Level> {
107 self.prepare_failed_level
108 }
109
110 /// Returns the message prefix used for prepare-action failures.
111 #[inline]
112 pub fn prepare_failed_message(&self) -> &str {
113 &self.prepare_failed_message
114 }
115
116 /// Returns the configured level for prepare-commit failures.
117 ///
118 /// [`None`] means the event does not emit a log line.
119 #[inline]
120 pub fn prepare_commit_failed_level(&self) -> Option<log::Level> {
121 self.prepare_commit_failed_level
122 }
123
124 /// Returns the message prefix used for prepare-commit failures.
125 #[inline]
126 pub fn prepare_commit_failed_message(&self) -> &str {
127 &self.prepare_commit_failed_message
128 }
129
130 /// Returns the configured level for prepare-rollback failures.
131 ///
132 /// [`None`] means the event does not emit a log line.
133 #[inline]
134 pub fn prepare_rollback_failed_level(&self) -> Option<log::Level> {
135 self.prepare_rollback_failed_level
136 }
137
138 /// Returns the message prefix used for prepare-rollback failures.
139 #[inline]
140 pub fn prepare_rollback_failed_message(&self) -> &str {
141 &self.prepare_rollback_failed_message
142 }
143
144 /// Updates logging for the case where the double-checked condition is not met
145 /// (the tester returns `false` before or after taking the lock).
146 ///
147 /// When [`Self::unmet_condition_level`] is [`None`], [`Self::log_unmet_condition`]
148 /// becomes a no-op. The `message` is still stored and used if the level is set
149 /// to [`Some`] later.
150 ///
151 /// # Parameters
152 ///
153 /// * `level` - Optional severity for the line written through the `log` crate,
154 /// or [`None`] to disable this event.
155 /// * `message` - Full line text (not a prefix); passed to [`log::log!`] as the
156 /// format argument when logging runs.
157 #[inline]
158 pub fn set_unmet_condition(&mut self, level: Option<log::Level>, message: impl Into<String>) {
159 self.unmet_condition_level = level;
160 self.unmet_condition_message = message.into();
161 }
162
163 /// Disables logging for unmet double-checked conditions.
164 ///
165 /// This keeps the stored message unchanged so a later call to
166 /// [`Self::set_unmet_condition`] can re-enable the event with a new message.
167 #[inline]
168 pub fn disable_unmet_condition(&mut self) {
169 self.unmet_condition_level = None;
170 }
171
172 /// Updates logging for a failed optional prepare action (before the lock is taken).
173 ///
174 /// When [`Self::prepare_failed_level`] is [`None`], [`Self::log_prepare_failed`]
175 /// becomes a no-op.
176 ///
177 /// # Parameters
178 ///
179 /// * `level` - Optional severity for the diagnostic line, or [`None`] to disable.
180 /// * `message_prefix` - Text placed before the error; the emitted line has the
181 /// form `"{prefix}: {error}"`.
182 #[inline]
183 pub fn set_prepare_failure(
184 &mut self,
185 level: Option<log::Level>,
186 message_prefix: impl Into<String>,
187 ) {
188 self.prepare_failed_level = level;
189 self.prepare_failed_message = message_prefix.into();
190 }
191
192 /// Disables logging for prepare-action failures.
193 #[inline]
194 pub fn disable_prepare_failure(&mut self) {
195 self.prepare_failed_level = None;
196 }
197
198 /// Updates logging for a failed prepare commit action (after a successful task
199 /// when prepare had completed).
200 ///
201 /// When [`Self::prepare_commit_failed_level`] is [`None`],
202 /// [`Self::log_prepare_commit_failed`] becomes a no-op.
203 ///
204 /// # Parameters
205 ///
206 /// * `level` - Optional severity for the diagnostic line, or [`None`] to disable.
207 /// * `message_prefix` - Text placed before the error; the emitted line has the
208 /// form `"{prefix}: {error}"`.
209 #[inline]
210 pub fn set_prepare_commit_failure(
211 &mut self,
212 level: Option<log::Level>,
213 message_prefix: impl Into<String>,
214 ) {
215 self.prepare_commit_failed_level = level;
216 self.prepare_commit_failed_message = message_prefix.into();
217 }
218
219 /// Disables logging for prepare-commit failures.
220 #[inline]
221 pub fn disable_prepare_commit_failure(&mut self) {
222 self.prepare_commit_failed_level = None;
223 }
224
225 /// Updates logging for a failed prepare rollback action (after a failed second
226 /// check or task when prepare had completed).
227 ///
228 /// When [`Self::prepare_rollback_failed_level`] is [`None`],
229 /// [`Self::log_prepare_rollback_failed`] becomes a no-op.
230 ///
231 /// # Parameters
232 ///
233 /// * `level` - Optional severity for the diagnostic line, or [`None`] to disable.
234 /// * `message_prefix` - Text placed before the error; the emitted line has the
235 /// form `"{prefix}: {error}"`.
236 #[inline]
237 pub fn set_prepare_rollback_failure(
238 &mut self,
239 level: Option<log::Level>,
240 message_prefix: impl Into<String>,
241 ) {
242 self.prepare_rollback_failed_level = level;
243 self.prepare_rollback_failed_message = message_prefix.into();
244 }
245
246 /// Disables logging for prepare-rollback failures.
247 #[inline]
248 pub fn disable_prepare_rollback_failure(&mut self) {
249 self.prepare_rollback_failed_level = None;
250 }
251
252 /// Emits the condition-unmet log line if enabled.
253 ///
254 /// Does nothing when [`Self::unmet_condition_level`] is [`None`]. Otherwise
255 /// writes [`Self::unmet_condition_message`] through the `log` facade at the
256 /// configured level, subject to the crate-wide maximum log level (for example
257 /// set via [`log::set_max_level`] or compile-time filters).
258 #[inline]
259 pub fn log_unmet_condition(&self) {
260 let Some(level) = self.unmet_condition_level else {
261 return;
262 };
263 log::log!(level, "{}", self.unmet_condition_message);
264 }
265
266 /// Emits a diagnostic line when the prepare action fails.
267 ///
268 /// Does nothing when [`Self::prepare_failed_level`] is [`None`]. Otherwise
269 /// logs `"{prefix}: {err}"` at the configured level via the `log` facade,
270 /// where `prefix` is [`Self::prepare_failed_message`], subject to the
271 /// crate-wide maximum log level.
272 ///
273 /// # Type Parameters
274 ///
275 /// * `E` - Displayable error or message value appended after the prefix.
276 ///
277 /// # Parameters
278 ///
279 /// * `err` - Failure to record next to the configured prefix.
280 #[inline]
281 pub fn log_prepare_failed<E: fmt::Display>(&self, err: E) {
282 let Some(level) = self.prepare_failed_level else {
283 return;
284 };
285 log::log!(level, "{}: {}", self.prepare_failed_message, err);
286 }
287
288 /// Emits a diagnostic line when the prepare commit action fails.
289 ///
290 /// Does nothing when [`Self::prepare_commit_failed_level`] is [`None`].
291 /// Otherwise logs `"{prefix}: {err}"` at the configured level, where `prefix`
292 /// is [`Self::prepare_commit_failed_message`], subject to the crate-wide
293 /// maximum log level.
294 ///
295 /// # Type Parameters
296 ///
297 /// * `E` - Displayable error or message value appended after the prefix.
298 ///
299 /// # Parameters
300 ///
301 /// * `err` - Commit failure to record next to the configured prefix.
302 #[inline]
303 pub fn log_prepare_commit_failed<E: fmt::Display>(&self, err: E) {
304 let Some(level) = self.prepare_commit_failed_level else {
305 return;
306 };
307 log::log!(level, "{}: {}", self.prepare_commit_failed_message, err);
308 }
309
310 /// Emits a diagnostic line when the prepare rollback action fails.
311 ///
312 /// Does nothing when [`Self::prepare_rollback_failed_level`] is [`None`].
313 /// Otherwise logs `"{prefix}: {err}"` at the configured level, where `prefix`
314 /// is [`Self::prepare_rollback_failed_message`], subject to the crate-wide
315 /// maximum log level.
316 ///
317 /// # Type Parameters
318 ///
319 /// * `E` - Displayable error or message value appended after the prefix.
320 ///
321 /// # Parameters
322 ///
323 /// * `err` - Rollback failure to record next to the configured prefix.
324 #[inline]
325 pub fn log_prepare_rollback_failed<E: fmt::Display>(&self, err: E) {
326 let Some(level) = self.prepare_rollback_failed_level else {
327 return;
328 };
329 log::log!(level, "{}: {}", self.prepare_rollback_failed_message, err);
330 }
331}