// Copyright 2023 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. //! `pw_log` is an extensible logging system that can delegate to //! pre-existing logging APIs without upstream changes. //! //! Clients of `pw_log` simply import and use the logging API, and //! log invocations will be handled by the provided logging backend. //! //! This flexibility is accomplished using Pigweed's //! [facade pattern](https://pigweed.dev/docs/facades.html), //! which uses build-system redirection to forward log invocations to the //! configured backend implementation. //! //! ``` //! use pw_log::{log, info, LogLevel}; //! //! log!(LogLevel::Info, "Thank you for signing up for Log Facts!"); //! info!("Log Fact: Logs can be either {}, {}, or {} sawn.", //! "flat" as &str, "quarter" as &str, "rift" as &str); //! ``` //! //! Today `printf` style format strings are well supported with Rust //! [`core::fmt`]/`println!()` style strings partially supported //! ([b/311232607](https://issues.pigweed.dev/issues/311232607)). //! //! Currently, when using a `stable` toolchain, "untyped" arguments (i.e. //! `{}` style) need to be in the form of an as-cast. Users with nightly //! toolchains can enable the `nightly_tait` feature to remove this restriction. //! //! TODO: - Document `pw_log`'s backend API. //! //! TODO: - Document how to configure facade backends. #![cfg_attr(not(feature = "std"), no_std)] #![deny(missing_docs)] pub use pw_log_backend_api::LogLevel; // Re-export dependences of `pw_log` macros to be accessed via `$crate::__private`. #[doc(hidden)] pub mod __private { pub use crate::*; // pub use pw_log_backend; pub use pw_log_backend::{pw_log_backend, pw_logf_backend}; } /// Emit a log message using `core::fmt` format string semantics. /// /// `log` takes a [`LogLevel`], a `core::fmt` style format string, and necessary /// arguments to that string and emits a log message to the logging backend. /// /// ``` /// use pw_log::{log, LogLevel}; /// /// log!(LogLevel::Info, "Log fact: A {} log has a Janka hardness of {} lbf.", /// "Spruce Pine" as &str, 700 as i32); /// ``` #[macro_export] macro_rules! log { ($log_level:expr, $format_string:literal) => {{ use $crate::__private as __pw_log_crate; $crate::__private::pw_log_backend!($log_level, $format_string) }}; ($log_level:expr, $format_string:literal, $($args:expr),*) => {{ use $crate::__private as __pw_log_crate; $crate::__private::pw_log_backend!($log_level, $format_string, $($args),*) }}; } /// Emit a log message using `printf` format string semantics. /// /// `logf` takes a [`LogLevel`], a `printf` style format string, and necessary /// arguments to that string and emits a log message to the logging backend. /// /// ``` /// use pw_log::{logf, LogLevel}; /// /// logf!(LogLevel::Info, "Log fact: A %s log has a Janka hardness of %d lbf.", /// "Spruce Pine", 700); /// ``` #[macro_export] macro_rules! logf { ($log_level:expr, $format_string:literal) => {{ use $crate::__private as __pw_log_crate; $crate::__private::pw_logf_backend!($log_level, $format_string) }}; ($log_level:expr, $format_string:literal, $($args:expr),*) => {{ use $crate::__private as __pw_log_crate; $crate::__private::pw_logf_backend!($log_level, $format_string, $($args),*) }}; } /// Deprecated alias for [`logf!`]. #[macro_export] macro_rules! pw_logf { ($($args:expr),*) => {{ logf!($($args),*) }} } /// Emit a debug level log message using `core:fmt` format string semantics. /// /// ``` /// use pw_log::debug; /// /// debug!("Log Fact: The American toy Lincoln Logs were inspired by the {} in {}.", /// "Imperial Hotel" as &str, "Tokyo" as &str); /// ``` #[macro_export] macro_rules! debug { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::log!(__pw_log_crate::LogLevel::Debug, $($args),*) }}; } /// Emit a debug level log message using `printf` format string semantics. /// /// ``` /// use pw_log::debugf; /// /// debugf!("Log Fact: The American toy Lincoln Logs were inspired by the %s in %s.", /// "Imperial Hotel", "Tokyo"); /// ``` #[macro_export] macro_rules! debugf { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::logf!(__pw_log_crate::LogLevel::Debug, $($args),*) }}; } /// Deprecated alias for [`debugf!`]. #[macro_export] macro_rules! pw_log_debugf { ($($args:expr),*) => {{ debugf!($($args),*) }} } /// Emit an info level log message using `core:fmt` format string semantics. /// /// ``` /// use pw_log::info; /// /// info!( /// "Log Fact: The American president Abraham Lincoln (born {:x}) once lived in a log cabin.", /// 0x1809 as u32); /// ``` #[macro_export] macro_rules! info { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::log!(__pw_log_crate::LogLevel::Info, $($args),*) }}; } /// Emit an info level log message using `printf` format string semantics. /// /// ``` /// use pw_log::infof; /// /// infof!( /// "Log Fact: The American president Abraham Lincoln (born %x) once lived in a log cabin.", /// 0x1809); /// ``` #[macro_export] macro_rules! infof { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::logf!(__pw_log_crate::LogLevel::Info, $($args),*) }}; } /// Deprecated alias for [`infof!`]. #[macro_export] macro_rules! pw_log_infof { ($($args:expr),*) => {{ infof!($($args),*) }} } /// Emit a warn level log message using `core::fmt` format string semantics. /// /// ``` /// use pw_log::warn; /// /// warn!( /// "Log Fact: Made from a log, an {} year old dugout canoe is the oldest discovered boat in {}.", /// 8000 as i32, "Africa" as &str); /// ``` #[macro_export] macro_rules! warn { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::log!(__pw_log_crate::LogLevel::Warn, $($args),*) }}; } /// Emit a warn level log message using `printf` format string semantics. /// /// ``` /// use pw_log::warnf; /// /// warnf!( /// "Log Fact: Made from a log, an %d year old dugout canoe is the oldest discovered boat in %s.", /// 8000, "Africa"); /// ``` #[macro_export] macro_rules! warnf { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::logf!(__pw_log_crate::LogLevel::Warn, $($args),*) }}; } /// Deprecated alias for [`warnf!`]. #[macro_export] macro_rules! pw_log_warnf { ($($args:expr),*) => {{ warnf!($($args),*) }} } /// Emit an error level log message using `core::fmt` format string semantics. /// /// ``` /// use pw_log::error; /// /// error!( /// "Log Fact: Before saws were invented, the {} was used prepare logs for use.", /// "adze" as &str); /// ``` #[macro_export] macro_rules! error { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::log!(__pw_log_crate::LogLevel::Error, $($args),*) }}; } /// Emit an error level log message using `printf` format string semantics. /// /// ``` /// use pw_log::errorf; /// /// errorf!( /// "Log Fact: Before saws were invented, the %s was used prepare logs for use.", /// "adze"); /// ``` #[macro_export] macro_rules! errorf { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::logf!(__pw_log_crate::LogLevel::Error, $($args),*) }}; } /// Deprecated alias for [`errorf!`]. #[macro_export] macro_rules! pw_log_errorf { ($($args:expr),*) => {{ errorf!($($args),*) }} } /// Emit a critical level log message using `core::fmt` format string semantics. /// /// ``` /// use pw_log::critical; /// /// critical!( /// "Log Fact: Until the {}th century, all ships' masts were made from a single log.", /// 19 as u32); /// ``` #[macro_export] macro_rules! critical { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::log!(__pw_log_crate::LogLevel::Critical, $($args),*) }}; } /// Emit a critical level log message using `printf` format string semantics. /// /// ``` /// use pw_log::{criticalf, LogLevel}; /// /// criticalf!( /// "Log Fact: Until the %dth century, all ships' masts were made from a single log.", /// 19); /// ``` #[macro_export] macro_rules! criticalf { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::logf!(__pw_log_crate::LogLevel::Critical, $($args),*) }}; } /// Deprecated alias for [`criticalf!`]. #[macro_export] macro_rules! pw_log_criticalf { ($($args:expr),*) => {{ criticalf!($($args),*) }} } /// Emit a fatal level log message using `core::fmt` format string semantics. /// /// *Note*: `fatal` only emits a log message and does not cause a `panic!()` /// /// ``` /// use pw_log::fatal; /// /// fatal!("Log Fact: All out of log facts! Timber!"); /// ``` #[macro_export] macro_rules! fatal { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::log!(__pw_log_crate::LogLevel::Fatal, $($args),*) }}; } /// Emit a fatal level log message using `printf` format string semantics. /// /// *Note*: `fatalf` only emits a log message and does not cause a `panic!()` /// /// ``` /// use pw_log::{fatalf, LogLevel}; /// /// fatalf!("Log Fact: All out of log facts! Timber!"); /// ``` #[macro_export] macro_rules! fatalf { ($($args:expr),*) => {{ use $crate::__private as __pw_log_crate; __pw_log_crate::logf!(__pw_log_crate::LogLevel::Fatal, $($args),*) }}; } /// Deprecated alias for [`fatalf!`]. #[macro_export] macro_rules! pw_log_fatalf { ($($args:expr),*) => {{ fatalf!($($args),*) }} } #[cfg(test)] mod tests { // TODO(b/311262163): Add infrastructure for testing behavior of `pw_log` API. // The syntax of that API is verified through doctests. }