qubit_lock/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 pub unmet_condition_level: Option<log::Level>,
37
38 /// Message logged when the execution condition is not met.
39 pub unmet_condition_message: String,
40
41 /// Log level for prepare-action failure lines; `None` skips them.
42 pub prepare_failed_level: Option<log::Level>,
43
44 /// Prefix for prepare-failure lines, formatted as `"{prefix}: {error}"`.
45 pub prepare_failed_message: String,
46
47 /// Log level for prepare-commit failure lines; `None` skips them.
48 pub prepare_commit_failed_level: Option<log::Level>,
49
50 /// Prefix for prepare-commit failure lines, formatted as `"{prefix}: {error}"`.
51 pub prepare_commit_failed_message: String,
52
53 /// Log level for prepare-rollback failure lines; `None` skips them.
54 pub prepare_rollback_failed_level: Option<log::Level>,
55
56 /// Prefix for prepare-rollback failure lines, formatted as
57 /// `"{prefix}: {error}"`.
58 pub 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 /// Updates logging for the case where the double-checked condition is not met
89 /// (the tester returns `false` before or after taking the lock).
90 ///
91 /// When [`Self::unmet_condition_level`] is [`None`], [`Self::log_unmet_condition`]
92 /// becomes a no-op. The `message` is still stored and used if the level is set
93 /// to [`Some`] later.
94 ///
95 /// # Parameters
96 ///
97 /// * `level` - Optional severity for the line written through the `log` crate,
98 /// or [`None`] to disable this event.
99 /// * `message` - Full line text (not a prefix); passed to [`log::log!`] as the
100 /// format argument when logging runs.
101 #[inline]
102 pub fn set_unmet_condition(&mut self, level: Option<log::Level>, message: impl Into<String>) {
103 self.unmet_condition_level = level;
104 self.unmet_condition_message = message.into();
105 }
106
107 /// Updates logging for a failed optional prepare action (before the lock is taken).
108 ///
109 /// When [`Self::prepare_failed_level`] is [`None`], [`Self::log_prepare_failed`]
110 /// becomes a no-op.
111 ///
112 /// # Parameters
113 ///
114 /// * `level` - Optional severity for the diagnostic line, or [`None`] to disable.
115 /// * `message_prefix` - Text placed before the error; the emitted line has the
116 /// form `"{prefix}: {error}"`.
117 #[inline]
118 pub fn set_prepare_failure(
119 &mut self,
120 level: Option<log::Level>,
121 message_prefix: impl Into<String>,
122 ) {
123 self.prepare_failed_level = level;
124 self.prepare_failed_message = message_prefix.into();
125 }
126
127 /// Updates logging for a failed prepare commit action (after a successful task
128 /// when prepare had completed).
129 ///
130 /// When [`Self::prepare_commit_failed_level`] is [`None`],
131 /// [`Self::log_prepare_commit_failed`] becomes a no-op.
132 ///
133 /// # Parameters
134 ///
135 /// * `level` - Optional severity for the diagnostic line, or [`None`] to disable.
136 /// * `message_prefix` - Text placed before the error; the emitted line has the
137 /// form `"{prefix}: {error}"`.
138 #[inline]
139 pub fn set_prepare_commit_failure(
140 &mut self,
141 level: Option<log::Level>,
142 message_prefix: impl Into<String>,
143 ) {
144 self.prepare_commit_failed_level = level;
145 self.prepare_commit_failed_message = message_prefix.into();
146 }
147
148 /// Updates logging for a failed prepare rollback action (after a failed second
149 /// check or task when prepare had completed).
150 ///
151 /// When [`Self::prepare_rollback_failed_level`] is [`None`],
152 /// [`Self::log_prepare_rollback_failed`] becomes a no-op.
153 ///
154 /// # Parameters
155 ///
156 /// * `level` - Optional severity for the diagnostic line, or [`None`] to disable.
157 /// * `message_prefix` - Text placed before the error; the emitted line has the
158 /// form `"{prefix}: {error}"`.
159 #[inline]
160 pub fn set_prepare_rollback_failure(
161 &mut self,
162 level: Option<log::Level>,
163 message_prefix: impl Into<String>,
164 ) {
165 self.prepare_rollback_failed_level = level;
166 self.prepare_rollback_failed_message = message_prefix.into();
167 }
168
169 /// Emits the condition-unmet log line if enabled.
170 ///
171 /// Does nothing when [`Self::unmet_condition_level`] is [`None`]. Otherwise
172 /// writes [`Self::unmet_condition_message`] through the `log` facade at the
173 /// configured level, subject to the crate-wide maximum log level (for example
174 /// set via [`log::set_max_level`] or compile-time filters).
175 #[inline]
176 pub fn log_unmet_condition(&self) {
177 let Some(level) = self.unmet_condition_level else {
178 return;
179 };
180 log::log!(level, "{}", self.unmet_condition_message);
181 }
182
183 /// Emits a diagnostic line when the prepare action fails.
184 ///
185 /// Does nothing when [`Self::prepare_failed_level`] is [`None`]. Otherwise
186 /// logs `"{prefix}: {err}"` at the configured level via the `log` facade,
187 /// where `prefix` is [`Self::prepare_failed_message`], subject to the
188 /// crate-wide maximum log level.
189 ///
190 /// # Type Parameters
191 ///
192 /// * `E` - Displayable error or message value appended after the prefix.
193 ///
194 /// # Parameters
195 ///
196 /// * `err` - Failure to record next to the configured prefix.
197 #[inline]
198 pub fn log_prepare_failed<E: fmt::Display>(&self, err: E) {
199 let Some(level) = self.prepare_failed_level else {
200 return;
201 };
202 log::log!(level, "{}: {}", self.prepare_failed_message, err);
203 }
204
205 /// Emits a diagnostic line when the prepare commit action fails.
206 ///
207 /// Does nothing when [`Self::prepare_commit_failed_level`] is [`None`].
208 /// Otherwise logs `"{prefix}: {err}"` at the configured level, where `prefix`
209 /// is [`Self::prepare_commit_failed_message`], subject to the crate-wide
210 /// maximum log level.
211 ///
212 /// # Type Parameters
213 ///
214 /// * `E` - Displayable error or message value appended after the prefix.
215 ///
216 /// # Parameters
217 ///
218 /// * `err` - Commit failure to record next to the configured prefix.
219 #[inline]
220 pub fn log_prepare_commit_failed<E: fmt::Display>(&self, err: E) {
221 let Some(level) = self.prepare_commit_failed_level else {
222 return;
223 };
224 log::log!(level, "{}: {}", self.prepare_commit_failed_message, err);
225 }
226
227 /// Emits a diagnostic line when the prepare rollback action fails.
228 ///
229 /// Does nothing when [`Self::prepare_rollback_failed_level`] is [`None`].
230 /// Otherwise logs `"{prefix}: {err}"` at the configured level, where `prefix`
231 /// is [`Self::prepare_rollback_failed_message`], subject to the crate-wide
232 /// maximum log level.
233 ///
234 /// # Type Parameters
235 ///
236 /// * `E` - Displayable error or message value appended after the prefix.
237 ///
238 /// # Parameters
239 ///
240 /// * `err` - Rollback failure to record next to the configured prefix.
241 #[inline]
242 pub fn log_prepare_rollback_failed<E: fmt::Display>(&self, err: E) {
243 let Some(level) = self.prepare_rollback_failed_level else {
244 return;
245 };
246 log::log!(level, "{}: {}", self.prepare_rollback_failed_message, err);
247 }
248}