Skip to main content

webdav_server/logger/
macro.rs

1/// Emits an informational log entry through the global logging service.
2///
3/// This macro is a complete no-op if the logger has not been initialized (i.e., if
4/// [`crate::logger::GLOBAL_LOGGER`] is empty). The format string is never evaluated in
5/// that case, so there is no runtime cost on the happy path.
6///
7/// The entry is dispatched via [`tokio::sync::mpsc::Sender::try_send`], which is
8/// non-blocking. If the channel is full, the entry is silently dropped rather than
9/// blocking the calling request thread.
10///
11/// # Parameters
12///
13/// - `$module` — A [`crate::logger::Module`] variant identifying the subsystem emitting
14///   the log.
15/// - `$($arg)+` — A format string and its arguments, following the same syntax as
16///   [`std::format!`].
17///
18/// # Usage
19///
20/// ```ignore
21/// info!(Module::Api, "request received from user {}", user_id);
22/// info!(Module::Storage, "blob committed: {}", hash);
23/// ```
24#[macro_export]
25macro_rules! info {
26    ($module:expr, $($arg:tt)+) => {
27        if let Some(logger) = $crate::logger::GLOBAL_LOGGER.get() {
28            let message = format!($($arg)+);
29
30            let entry = $crate::logger::Entry {
31                module: $module,
32                level: $crate::logger::Level::Info,
33                timestamp_ms: chrono::Utc::now().timestamp_millis(),
34                message,
35            };
36            let _ = logger.try_send(entry);
37        }
38	};
39}
40
41/// Emits a warning log entry through the global logging service.
42///
43/// Use this level for abnormal but non-fatal events: authentication failures,
44/// request conflicts, resource-not-found responses, or any condition that is
45/// unexpected but does not indicate a server malfunction.
46///
47/// This macro is a complete no-op if the logger has not been initialized.
48/// See [`info!`] for parameter documentation and general behaviour.
49///
50/// # Usage
51///
52/// ```ignore
53/// warn!(Module::Api, "unauthorized access attempt for blob {}", hash);
54/// ```
55#[macro_export]
56macro_rules! warn {
57    ($module:expr, $($arg:tt)+) => {
58        if let Some(logger) = $crate::logger::GLOBAL_LOGGER.get() {
59            let message = format!($($arg)+);
60
61            let entry = $crate::logger::Entry {
62                module: $module,
63                level: $crate::logger::Level::Warning,
64                timestamp_ms: chrono::Utc::now().timestamp_millis(),
65                message,
66            };
67            let _ = logger.try_send(entry);
68        }
69	};
70}
71
72/// Emits an error log entry through the global logging service.
73///
74/// Use this level for unexpected failures that affect a single request but do not
75/// crash the service: database query failures, storage write errors, or any condition
76/// that results in a 5xx response being returned to the client.
77///
78/// This macro is a complete no-op if the logger has not been initialized.
79/// See [`info!`] for parameter documentation and general behaviour.
80///
81/// # Usage
82///
83/// ```ignore
84/// error!(Module::Database, "query failed: {}", e);
85/// ```
86#[macro_export]
87macro_rules! error {
88    ($module:expr, $($arg:tt)+) => {
89        if let Some(logger) = $crate::logger::GLOBAL_LOGGER.get() {
90            let message = format!($($arg)+);
91
92            let entry = $crate::logger::Entry {
93                module: $module,
94                level: $crate::logger::Level::Error,
95                timestamp_ms: chrono::Utc::now().timestamp_millis(),
96                message,
97            };
98            let _ = logger.try_send(entry);
99        }
100	};
101}
102
103/// Emits a shutdown sentinel entry and signals the logging service to stop.
104///
105/// This macro sends an entry with [`crate::logger::Level::Shutdown`] and the
106/// module hardcoded to [`crate::logger::Module::Server`]. When the background
107/// service receives this entry, it exits its receive loop cleanly.
108///
109/// This must be called during the server's graceful shutdown sequence, before
110/// awaiting [`crate::logger::service::LoggerHandler::shutdown_with_grace`].
111///
112/// This macro is a no-op if the logger has not been initialized.
113///
114/// # Usage
115///
116/// ```ignore
117/// // In the graceful shutdown sequence:
118/// shutdown!("Waiting to flush remaining entries...");
119/// logger_handle.shutdown_with_grace(10).await;
120/// ```
121#[macro_export]
122macro_rules! shutdown {
123    ($($arg:tt)+) => {
124        if let Some(logger) = $crate::logger::GLOBAL_LOGGER.get() {
125            let message = format!($($arg)+);
126
127            let entry = $crate::logger::Entry {
128                module: $crate::logger::Module::Server,
129                level: $crate::logger::Level::Shutdown,
130                timestamp_ms: chrono::Utc::now().timestamp_millis(),
131                message,
132            };
133            let _ = logger.try_send(entry);
134        }
135	};
136}
137
138/// Emits a fatal log entry through the global logging service.
139///
140/// Use this level for critical failures that indicate the server may be in an
141/// unrecoverable state: the vault directory is missing at startup, a background
142/// task has panicked, or a grace period has timed out. A `Fatal` entry does not
143/// automatically terminate the process; the caller is responsible for deciding
144/// whether to initiate shutdown.
145///
146/// This macro is a complete no-op if the logger has not been initialized.
147/// See [`info!`] for parameter documentation and general behaviour.
148///
149/// # Usage
150///
151/// ```ignore
152/// fatal!(Module::Server, "grace period timed out, forcefully terminating: {}", e);
153/// ```
154#[macro_export]
155macro_rules! fatal {
156    ($module:expr, $($arg:tt)+) => {
157        if let Some(logger) = $crate::logger::GLOBAL_LOGGER.get() {
158            let message = format!($($arg)+);
159
160            let entry = $crate::logger::Entry {
161                module: $module,
162                level: $crate::logger::Level::Fatal,
163                timestamp_ms: chrono::Utc::now().timestamp_millis(),
164                message,
165            };
166            let _ = logger.try_send(entry);
167        }
168    }
169}