Skip to main content

pw_log/
pw_log.rs

1// Copyright 2023 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15//! `pw_log` is an extensible logging system that can delegate to
16//! pre-existing logging APIs without upstream changes.
17//!
18//! Clients of `pw_log` simply import and use the logging API, and
19//! log invocations will be handled by the provided logging backend.
20//!
21//! This flexibility is accomplished using Pigweed's
22//! [facade pattern](https://pigweed.dev/docs/facades.html),
23//! which uses build-system redirection to forward log invocations to the
24//! configured backend implementation.
25//!
26//! ```
27//! use pw_log::{log, info, LogLevel};
28//!
29//! log!(LogLevel::Info, "Thank you for signing up for Log Facts!");
30//! info!("Log Fact: Logs can be either {}, {}, or {} sawn.",
31//!   "flat" as &str, "quarter" as &str, "rift" as &str);
32//! ```
33//!
34//! Today `printf` style format strings are well supported with Rust
35//! [`core::fmt`]/`println!()` style strings partially supported
36//! ([b/311232607](https://issues.pigweed.dev/issues/311232607)).
37//!
38//! Currently, when using a `stable` toolchain, "untyped" arguments (i.e.
39//! `{}` style) need to be in the form of an as-cast.  Users with nightly
40//! toolchains can enable the `nightly_tait` feature to remove this restriction.
41//!
42//! TODO: <pwbug.dev/311266298> - Document `pw_log`'s backend API.
43//!
44//! TODO: <pwbug.dev/311232605> - Document how to configure facade backends.
45#![cfg_attr(not(feature = "std"), no_std)]
46#![deny(missing_docs)]
47
48pub use pw_log_backend_api::LogLevel;
49
50// Re-export dependencies of `pw_log` macros to be accessed via `$crate::__private`.
51#[doc(hidden)]
52pub mod __private {
53    pub use pw_log_backend::{pw_log_backend, pw_logf_backend};
54
55    pub use crate::*;
56}
57
58/// Emit a log message using `core::fmt` format string semantics.
59///
60/// `log` takes a [`LogLevel`], a `core::fmt` style format string, and necessary
61/// arguments to that string and emits a log message to the logging backend.
62///
63/// ```
64/// use pw_log::{log, LogLevel};
65///
66/// log!(LogLevel::Info, "Log fact: A {} log has a Janka hardness of {} lbf.",
67///      "Spruce Pine" as &str, 700 as i32);
68/// ```
69///
70/// Multiple string literals can be concatenated using the `PW_FMT_CONCAT` operator.
71///
72/// This is particularly useful when writing wrapper macros that need to prepend
73/// a prefix to a format string.
74///
75/// ```
76/// use pw_log::{log, LogLevel};
77///
78/// macro_rules! my_info_log {
79///     ($format_string:literal $(, $args:expr)* $(,)?) => {
80///         log!(LogLevel::Info, "[MyModule] " PW_FMT_CONCAT $format_string $(, $args)*)
81///     };
82/// }
83///
84/// my_info_log!("The answer is {}.", 42 as i32);
85/// ```
86#[macro_export]
87macro_rules! log {
88  ($log_level:expr, $($format_string:literal)PW_FMT_CONCAT+ $(, $args:expr)* $(,)?) => {{
89    use $crate::__private as __pw_log_crate;
90    $crate::__private::pw_log_backend!($log_level, $($format_string)PW_FMT_CONCAT+, $($args),*)
91  }};
92
93  ($log_level:expr, $format_string:literal $(, $args:expr)* $(,)?) => {{
94    use $crate::__private as __pw_log_crate;
95    $crate::__private::pw_log_backend!($log_level, $format_string, $($args),*)
96  }};
97}
98
99/// Emit a log message using `printf` format string semantics.
100///
101/// `logf` takes a [`LogLevel`], a `printf` style format string, and necessary
102/// arguments to that string and emits a log message to the logging backend.
103///
104/// ```
105/// use pw_log::{logf, LogLevel};
106///
107/// logf!(LogLevel::Info, "Log fact: A %s log has a Janka hardness of %d lbf.",
108///     "Spruce Pine", 700);
109/// ```
110#[macro_export]
111macro_rules! logf {
112  ($log_level:expr, $format_string:literal $(,)?) => {{
113    use $crate::__private as __pw_log_crate;
114    $crate::__private::pw_logf_backend!($log_level, $format_string)
115  }};
116
117  ($log_level:expr, $format_string:literal, $($args:expr),* $(,)?) => {{
118    use $crate::__private as __pw_log_crate;
119    $crate::__private::pw_logf_backend!($log_level, $format_string, $($args),*)
120  }};
121}
122
123/// Deprecated alias for [`logf!`].
124#[macro_export]
125macro_rules! pw_logf {
126  ($($args:expr),* $(,)?) => {{
127    logf!($($args),*)
128  }}
129}
130
131/// Emit a debug level log message using `core:fmt` format string semantics.
132///
133/// ```
134/// use pw_log::debug;
135///
136/// debug!("Log Fact: The American toy Lincoln Logs were inspired by the {} in {}.",
137///     "Imperial Hotel" as &str, "Tokyo" as &str);
138/// ```
139#[macro_export]
140macro_rules! debug {
141  ($($args:tt)*) => {{
142    use $crate::__private as __pw_log_crate;
143    __pw_log_crate::log!(__pw_log_crate::LogLevel::Debug, $($args)*)
144  }};
145}
146
147/// Emit a debug level log message using `printf` format string semantics.
148///
149/// ```
150/// use pw_log::debugf;
151///
152/// debugf!("Log Fact: The American toy Lincoln Logs were inspired by the %s in %s.",
153///     "Imperial Hotel", "Tokyo");
154/// ```
155#[macro_export]
156macro_rules! debugf {
157  ($($args:expr),* $(,)?) => {{
158    use $crate::__private as __pw_log_crate;
159    __pw_log_crate::logf!(__pw_log_crate::LogLevel::Debug, $($args),*)
160  }};
161}
162
163/// Deprecated alias for [`debugf!`].
164#[macro_export]
165macro_rules! pw_log_debugf {
166  ($($args:expr),* $(,)?) => {{
167    debugf!($($args),*)
168  }}
169}
170
171/// Emit an info level log message using `core:fmt` format string semantics.
172///
173/// ```
174/// use pw_log::info;
175///
176/// info!(
177///     "Log Fact: The American president Abraham Lincoln (born {:x}) once lived in a log cabin.",
178///     0x1809 as u32);
179/// ```
180#[macro_export]
181macro_rules! info {
182  ($($args:tt)*) => {{
183    use $crate::__private as __pw_log_crate;
184    __pw_log_crate::log!(__pw_log_crate::LogLevel::Info, $($args)*)
185  }};
186}
187
188/// Emit an info level log message using `printf` format string semantics.
189///
190/// ```
191/// use pw_log::infof;
192///
193/// infof!(
194///     "Log Fact: The American president Abraham Lincoln (born %x) once lived in a log cabin.",
195/// 0x1809);
196/// ```
197#[macro_export]
198macro_rules! infof {
199  ($($args:expr),* $(,)?) => {{
200    use $crate::__private as __pw_log_crate;
201    __pw_log_crate::logf!(__pw_log_crate::LogLevel::Info, $($args),*)
202  }};
203}
204
205/// Deprecated alias for [`infof!`].
206#[macro_export]
207macro_rules! pw_log_infof {
208  ($($args:expr),* $(,)?) => {{
209    infof!($($args),*)
210  }}
211}
212
213/// Emit a warn level log message using `core::fmt` format string semantics.
214///
215/// ```
216/// use pw_log::warn;
217///
218/// warn!(
219///     "Log Fact: Made from a log, an {} year old dugout canoe is the oldest discovered boat in {}.",
220///     8000 as i32, "Africa" as &str);
221/// ```
222#[macro_export]
223macro_rules! warn {
224  ($($args:tt)*) => {{
225    use $crate::__private as __pw_log_crate;
226    __pw_log_crate::log!(__pw_log_crate::LogLevel::Warn, $($args)*)
227  }};
228}
229
230/// Emit a warn level log message using `printf` format string semantics.
231///
232/// ```
233/// use pw_log::warnf;
234///
235/// warnf!(
236///     "Log Fact: Made from a log, an %d year old dugout canoe is the oldest discovered boat in %s.",
237///     8000, "Africa");
238/// ```
239#[macro_export]
240macro_rules! warnf {
241  ($($args:expr),* $(,)?) => {{
242    use $crate::__private as __pw_log_crate;
243    __pw_log_crate::logf!(__pw_log_crate::LogLevel::Warn, $($args),*)
244  }};
245}
246
247/// Deprecated alias for [`warnf!`].
248#[macro_export]
249macro_rules! pw_log_warnf {
250  ($($args:expr),* $(,)?) => {{
251    warnf!($($args),*)
252  }}
253}
254
255/// Emit an error level log message using `core::fmt` format string semantics.
256///
257/// ```
258/// use pw_log::error;
259///
260/// error!(
261///     "Log Fact: Before saws were invented, the {} was used prepare logs for use.",
262///     "adze" as &str);
263/// ```
264#[macro_export]
265macro_rules! error {
266  ($($args:tt)*) => {{
267    use $crate::__private as __pw_log_crate;
268    __pw_log_crate::log!(__pw_log_crate::LogLevel::Error, $($args)*)
269  }};
270}
271
272/// Emit an error level log message using `printf` format string semantics.
273///
274/// ```
275/// use pw_log::errorf;
276///
277/// errorf!(
278///     "Log Fact: Before saws were invented, the %s was used prepare logs for use.",
279///     "adze");
280/// ```
281#[macro_export]
282macro_rules! errorf {
283  ($($args:expr),* $(,)?) => {{
284    use $crate::__private as __pw_log_crate;
285    __pw_log_crate::logf!(__pw_log_crate::LogLevel::Error, $($args),*)
286  }};
287}
288
289/// Deprecated alias for [`errorf!`].
290#[macro_export]
291macro_rules! pw_log_errorf {
292  ($($args:expr),* $(,)?) => {{
293    errorf!($($args),*)
294  }}
295}
296
297/// Emit a critical level log message using `core::fmt` format string semantics.
298///
299/// ```
300/// use pw_log::critical;
301///
302/// critical!(
303///     "Log Fact: Until the {}th century, all ships' masts were made from a single log.",
304///     19 as u32);
305/// ```
306#[macro_export]
307macro_rules! critical {
308  ($($args:tt)*) => {{
309    use $crate::__private as __pw_log_crate;
310    __pw_log_crate::log!(__pw_log_crate::LogLevel::Critical, $($args)*)
311  }};
312}
313
314/// Emit a critical level log message using `printf` format string semantics.
315///
316/// ```
317/// use pw_log::criticalf;
318///
319/// criticalf!(
320///     "Log Fact: Until the %dth century, all ships' masts were made from a single log.",
321///     19);
322/// ```
323#[macro_export]
324macro_rules! criticalf {
325  ($($args:expr),* $(,)?) => {{
326    use $crate::__private as __pw_log_crate;
327    __pw_log_crate::logf!(__pw_log_crate::LogLevel::Critical, $($args),*)
328  }};
329}
330
331/// Deprecated alias for [`criticalf!`].
332#[macro_export]
333macro_rules! pw_log_criticalf {
334  ($($args:expr),* $(,)?) => {{
335    criticalf!($($args),*)
336  }}
337}
338
339/// Emit a fatal level log message using `core::fmt` format string semantics.
340///
341/// *Note*: `fatal` only emits a log message and does not cause a `panic!()`
342///
343/// ```
344/// use pw_log::fatal;
345///
346/// fatal!("Log Fact: All out of log facts! Timber!");
347/// ```
348#[macro_export]
349macro_rules! fatal {
350  ($($args:tt)*) => {{
351    use $crate::__private as __pw_log_crate;
352    __pw_log_crate::log!(__pw_log_crate::LogLevel::Fatal, $($args)*)
353  }};
354}
355
356/// Emit a fatal level log message using `printf` format string semantics.
357///
358/// *Note*: `fatalf` only emits a log message and does not cause a `panic!()`
359///
360/// ```
361/// use pw_log::fatalf;
362///
363/// fatalf!("Log Fact: All out of log facts! Timber!");
364/// ```
365#[macro_export]
366macro_rules! fatalf {
367  ($($args:expr),* $(,)?) => {{
368    use $crate::__private as __pw_log_crate;
369    __pw_log_crate::logf!(__pw_log_crate::LogLevel::Fatal, $($args),*)
370  }};
371}
372
373/// Deprecated alias for [`fatalf!`].
374#[macro_export]
375macro_rules! pw_log_fatalf {
376  ($($args:expr),* $(,)?) => {{
377    fatalf!($($args),*)
378  }}
379}
380
381#[cfg(test)]
382mod tests {
383    // TODO(b/311262163): Add infrastructure for testing behavior of `pw_log` API.
384    // The syntax of that API is verified through doctests.
385}