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