Skip to main content

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}