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}