defmt/
lib.rs

1//! A highly efficient logging framework that targets resource-constrained
2//! devices, like microcontrollers.
3//!
4//! Check out the defmt book at <https://defmt.ferrous-systems.com> for more
5//! information about how to use it.
6//!
7//! # Compatibility
8//!
9//! The `defmt` wire format might change between minor versions. Attempting to
10//! read a defmt stream with an incompatible version will result in an error,
11//! and any tool used to process that stream should first check for a symbol
12//! named like `_defmt_version_ = X`, where X indicates the wire format version
13//! in use.
14//!
15//! Updating your version of defmt might mean you also have to update your
16//! version of `defmt-print` or `defmt-decoder`.
17
18#![cfg_attr(not(feature = "unstable-test"), no_std)]
19// NOTE if you change this URL you'll also need to update all other crates in this repo
20#![doc(html_logo_url = "https://knurling.ferrous-systems.com/knurling_logo_light_text.svg")]
21#![warn(missing_docs)]
22
23#[cfg(feature = "alloc")]
24extern crate alloc;
25
26// This must be in the root lib.rs, otherwise it doesn't appear in the final binary.
27
28/// The defmt ABI and wire format version.
29///
30/// This number has to be updated every time there is a backwards-incompatible change to
31/// - the symbol naming scheme
32/// - the symbol and section layout
33/// - the data encoding / wire format
34#[used]
35#[cfg_attr(target_os = "macos", link_section = ".defmt,end.VERSION")]
36#[cfg_attr(not(target_os = "macos"), link_section = ".defmt.end")]
37#[export_name = "_defmt_version_ = 4"]
38static DEFMT_VERSION: u8 = 0;
39
40#[used]
41#[cfg_attr(target_os = "macos", link_section = ".defmt,end.ENCODING")]
42#[cfg_attr(not(target_os = "macos"), link_section = ".defmt.end")]
43#[cfg_attr(feature = "encoding-raw", export_name = "_defmt_encoding_ = raw")]
44#[cfg_attr(
45    not(feature = "encoding-raw"),
46    export_name = "_defmt_encoding_ = rzcobs"
47)]
48#[allow(missing_docs)]
49#[doc(hidden)]
50pub static DEFMT_ENCODING: u8 = 0;
51
52mod encoding;
53#[doc(hidden)]
54pub mod export;
55mod formatter;
56mod impls;
57#[cfg(all(test, feature = "unstable-test"))]
58mod tests;
59mod traits;
60
61pub use crate::{
62    encoding::Encoder,
63    formatter::{Formatter, Str},
64    impls::adapter::{Debug2Format, Display2Format},
65    traits::{Format, Logger},
66};
67
68#[cfg(all(test, not(feature = "unstable-test")))]
69compile_error!(
70    "to run unit tests enable the `unstable-test` feature, e.g. `cargo t --features unstable-test`"
71);
72
73/// Just like the [`core::assert!`] macro but `defmt` is used to log the panic message
74///
75/// [`core::assert!`]: https://doc.rust-lang.org/core/macro.assert.html
76///
77/// If used, the format string must follow the defmt syntax (documented in [the manual])
78///
79/// [the manual]: https://defmt.ferrous-systems.com/macros.html
80pub use defmt_macros::assert_ as assert;
81
82/// Just like the [`core::assert_eq!`] macro but `defmt` is used to log the panic message
83///
84/// [`core::assert_eq!`]: https://doc.rust-lang.org/core/macro.assert_eq.html
85///
86/// If used, the format string must follow the defmt syntax (documented in [the manual])
87///
88/// [the manual]: https://defmt.ferrous-systems.com/macros.html
89pub use defmt_macros::assert_eq_ as assert_eq;
90
91/// Just like the [`core::assert_ne!`] macro but `defmt` is used to log the panic message
92///
93/// [`core::assert_ne!`]: https://doc.rust-lang.org/core/macro.assert_ne.html
94///
95/// If used, the format string must follow the defmt syntax (documented in [the manual])
96///
97/// [the manual]: https://defmt.ferrous-systems.com/macros.html
98pub use defmt_macros::assert_ne_ as assert_ne;
99
100/// Just like the [`core::debug_assert!`] macro but `defmt` is used to log the panic message
101///
102/// [`core::debug_assert!`]: https://doc.rust-lang.org/core/macro.debug_assert.html
103///
104/// If used, the format string must follow the defmt syntax (documented in [the manual])
105///
106/// [the manual]: https://defmt.ferrous-systems.com/macros.html
107pub use defmt_macros::debug_assert_ as debug_assert;
108
109/// Just like the [`core::debug_assert_eq!`] macro but `defmt` is used to log the panic message
110///
111/// [`core::debug_assert_eq!`]: https://doc.rust-lang.org/core/macro.debug_assert_eq.html
112///
113/// If used, the format string must follow the defmt syntax (documented in [the manual])
114///
115/// [the manual]: https://defmt.ferrous-systems.com/macros.html
116pub use defmt_macros::debug_assert_eq_ as debug_assert_eq;
117
118/// Just like the [`core::debug_assert_ne!`] macro but `defmt` is used to log the panic message
119///
120/// [`core::debug_assert_ne!`]: https://doc.rust-lang.org/core/macro.debug_assert_ne.html
121///
122/// If used, the format string must follow the defmt syntax (documented in [the manual])
123///
124/// [the manual]: https://defmt.ferrous-systems.com/macros.html
125pub use defmt_macros::debug_assert_ne_ as debug_assert_ne;
126
127/// Just like the [`core::unreachable!`] macro but `defmt` is used to log the panic message
128///
129/// [`core::unreachable!`]: https://doc.rust-lang.org/core/macro.unreachable.html
130///
131/// If used, the format string must follow the defmt syntax (documented in [the manual])
132///
133/// [the manual]: https://defmt.ferrous-systems.com/macros.html
134pub use defmt_macros::unreachable_ as unreachable;
135
136/// Just like the [`core::todo!`] macro but `defmt` is used to log the panic message
137///
138/// [`core::todo!`]: https://doc.rust-lang.org/core/macro.todo.html
139///
140/// If used, the format string must follow the defmt syntax (documented in [the manual])
141///
142/// [the manual]: https://defmt.ferrous-systems.com/macros.html
143pub use defmt_macros::todo_ as todo;
144
145/// Just like the [`core::unimplemented!`] macro but `defmt` is used to log the panic message
146///
147/// [`core::unimplemented!`]: https://doc.rust-lang.org/core/macro.unimplemented.html
148///
149/// If used, the format string must follow the defmt syntax (documented in [the manual])
150///
151/// [the manual]: https://defmt.ferrous-systems.com/macros.html
152pub use defmt_macros::todo_ as unimplemented;
153
154/// Just like the [`core::panic!`] macro but `defmt` is used to log the panic message
155///
156/// [`core::panic!`]: https://doc.rust-lang.org/core/macro.panic.html
157///
158/// If used, the format string must follow the defmt syntax (documented in [the manual])
159///
160/// [the manual]: https://defmt.ferrous-systems.com/macros.html
161pub use defmt_macros::panic_ as panic;
162
163/// Unwraps an `Option` or `Result`, panicking if it is `None` or `Err`.
164///
165/// This macro is roughly equivalent to `{Option,Result}::{expect,unwrap}` but invocation looks
166/// a bit different because this is a macro and not a method. The other difference is that
167/// `unwrap!`-ing a `Result<T, E>` value requires that the error type `E` implements the `Format`
168/// trait
169///
170/// The following snippet shows the differences between core's unwrap method and defmt's unwrap
171/// macro:
172///
173/// ```
174/// use defmt::unwrap;
175///
176/// # let option = Some(());
177/// let x = option.unwrap();
178/// let x = unwrap!(option);
179///
180/// # let result = Ok::<(), ()>(());
181/// let x = result.unwrap();
182/// let x = unwrap!(result);
183///
184/// let x = result.expect("text");
185/// let x = unwrap!(result, "text");
186///
187/// # let arg = ();
188/// let x = result.expect(&format!("text {:?}", arg));
189/// let x = unwrap!(result, "text {:?}", arg); // arg must be implement `Format`
190/// ```
191///
192/// If used, the format string must follow the defmt syntax (documented in [the manual])
193///
194/// [the manual]: https://defmt.ferrous-systems.com/macros.html
195pub use defmt_macros::unwrap;
196
197/// This is an alias for defmt's [`unwrap`] macro which supports messages like std's except.
198/// ```
199/// use defmt::expect;
200///
201/// # let result = Ok::<(), ()>(());
202/// # let arg = ();
203/// let x = result.expect(&format!("text {:?}", arg));
204/// let x = expect!(result, "text {:?}", arg); // arg must be implement `Format`
205/// ```
206///
207/// For the complete documentation see that of defmt's *unwrap* macro.
208// note: Linking to unwrap is broken as of 2024-10-09, it links back to expect
209pub use defmt_macros::unwrap as expect;
210
211/// Overrides the panicking behavior of `defmt::panic!`
212///
213/// By default, `defmt::panic!` calls `core::panic!` after logging the panic message using `defmt`.
214/// This can result in the panic message being printed twice in some cases. To avoid that issue use
215/// this macro. See [the manual] for details.
216///
217/// [the manual]: https://defmt.ferrous-systems.com/panic.html
218///
219/// # Inter-operation with built-in attributes
220///
221/// This attribute cannot be used together with the `export_name` or `no_mangle` attributes
222pub use defmt_macros::panic_handler;
223
224/// Creates an interned string ([`Str`]) from a string literal.
225///
226/// This must be called on a string literal, and will allocate the literal in the object file. At
227/// runtime, only a small string index is required to refer to the string, represented as the
228/// [`Str`] type.
229///
230/// # Example
231///
232/// ```
233/// let interned = defmt::intern!("long string literal taking up little space");
234/// ```
235///
236/// [`Str`]: struct.Str.html
237pub use defmt_macros::intern;
238
239/// Always logs data irrespective of log level.
240///
241/// Please refer to [the manual] for documentation on the syntax.
242///
243/// [the manual]: https://defmt.ferrous-systems.com/macros.html
244pub use defmt_macros::println;
245
246/// Logs data at *debug* level.
247///
248/// Please refer to [the manual] for documentation on the syntax.
249///
250/// [the manual]: https://defmt.ferrous-systems.com/macros.html
251pub use defmt_macros::debug;
252/// Logs data at *error* level.
253///
254/// Please refer to [the manual] for documentation on the syntax.
255///
256/// [the manual]: https://defmt.ferrous-systems.com/macros.html
257pub use defmt_macros::error;
258/// Logs data at *info* level.
259///
260/// Please refer to [the manual] for documentation on the syntax.
261///
262/// [the manual]: https://defmt.ferrous-systems.com/macros.html
263pub use defmt_macros::info;
264/// Logs data at *trace* level.
265///
266/// Please refer to [the manual] for documentation on the syntax.
267///
268/// [the manual]: https://defmt.ferrous-systems.com/macros.html
269pub use defmt_macros::trace;
270/// Logs data at *warn* level.
271///
272/// Please refer to [the manual] for documentation on the syntax.
273///
274/// [the manual]: https://defmt.ferrous-systems.com/macros.html
275pub use defmt_macros::warn;
276
277/// Just like the [`std::dbg!`] macro but `defmt` is used to log the message at `TRACE` level.
278///
279/// [`std::dbg!`]: https://doc.rust-lang.org/std/macro.dbg.html
280pub use defmt_macros::dbg;
281
282/// Writes formatted data to a [`Formatter`].
283///
284/// [`Formatter`]: struct.Formatter.html
285pub use defmt_macros::write;
286
287/// Defines the global defmt logger.
288///
289/// `#[global_logger]` needs to be put on a unit struct type declaration. This struct has to
290/// implement the [`Logger`] trait.
291///
292/// # Example
293///
294/// ```
295/// use defmt::{Logger, global_logger};
296///
297/// #[global_logger]
298/// struct MyLogger;
299///
300/// unsafe impl Logger for MyLogger {
301///     fn acquire() {
302/// # todo!()
303///         // ...
304///     }
305///     unsafe fn flush() {
306///         # todo!()
307///         // ...
308///     }
309///     unsafe fn release() {
310/// # todo!()
311///         // ...
312///     }
313///     unsafe fn write(bytes: &[u8]) {
314/// # todo!()
315///         // ...
316///     }
317/// }
318/// ```
319///
320/// [`Logger`]: trait.Logger.html
321pub use defmt_macros::global_logger;
322
323/// Defines the global timestamp provider for defmt.
324///
325/// This macro can be used to attach a timestamp or other data to every defmt message. Its syntax
326/// works exactly like the logging macros, except that no local variables can be accessed and the
327/// macro should be placed in a module instead of a function.
328///
329/// `timestamp!` must only be used once across the crate graph.
330///
331/// If no crate defines a timestamp, no timestamp will be included in the logged messages.
332///
333/// # Examples
334///
335/// ```
336/// # use core::sync::atomic::{AtomicU32, Ordering};
337///
338/// static COUNT: AtomicU32 = AtomicU32::new(0);
339/// defmt::timestamp!("{=u32:us}", COUNT.fetch_add(1, Ordering::Relaxed));
340/// ```
341pub use defmt_macros::timestamp;
342
343/// Generates a bitflags structure that can be formatted with defmt.
344///
345/// This macro is a wrapper around the [`bitflags!`] crate, and provides an (almost) identical
346/// interface. Refer to [its documentation] for an explanation of the syntax.
347///
348/// [its documentation]: https://docs.rs/bitflags/1/bitflags/
349///
350/// # Limitations
351///
352/// This macro only supports bitflags structs represented as one of Rust's built-in unsigned integer
353/// types (`u8`, `u16`, `u32`, `u64`, or `u128`). Custom types are not supported. This restriction
354/// is necessary to support defmt's efficient encoding.
355///
356/// # Examples
357///
358/// The example from the bitflags crate works as-is:
359///
360/// ```
361/// defmt::bitflags! {
362///     struct Flags: u32 {
363///         const A = 0b00000001;
364///         const B = 0b00000010;
365///         const C = 0b00000100;
366///         const ABC = Self::A.bits | Self::B.bits | Self::C.bits;
367///     }
368/// }
369///
370/// defmt::info!("Flags::ABC: {}", Flags::ABC);
371/// defmt::info!("Flags::empty(): {}", Flags::empty());
372/// ```
373pub use defmt_macros::bitflags;
374
375#[doc(hidden)] // documented as the `Format` trait instead
376pub use defmt_macros::Format;
377
378// There is no default timestamp format. Instead, the decoder looks for a matching ELF symbol. If
379// absent, timestamps are turned off.
380#[export_name = "__defmt_default_timestamp"]
381fn default_timestamp(_f: Formatter<'_>) {}
382
383#[export_name = "__defmt_default_panic"]
384fn default_panic() -> ! {
385    core::panic!()
386}
387
388/// Block until host has read all pending data.
389///
390/// The flush operation will not fail, but might not succeed in flushing _all_ pending data. It is
391/// implemented as a "best effort" operation.
392///
393/// This calls the method `flush` of the used "global [`Logger`]". The logger is likely provided by
394/// [`defmt-rtt`](https://crates.io/crates/defmt-rtt) or [`defmt-itm`](https://crates.io/crates/defmt-itm).
395pub fn flush() {
396    match () {
397        #[cfg(feature = "unstable-test")]
398        () => {
399            // no-op when run on host
400        }
401
402        #[cfg(not(feature = "unstable-test"))]
403        () => {
404            extern "Rust" {
405                fn _defmt_acquire();
406                fn _defmt_flush();
407                fn _defmt_release();
408            }
409            // SAFETY:
410            // * we call these function in the correct order: first acquire the lock, then flush and
411            //   finally release the lock
412            // * these function should be provided by the macro `#[global_logger]` and therefore
413            //   trustworthy to call through FFI-bounds
414            unsafe {
415                _defmt_acquire();
416                _defmt_flush();
417                _defmt_release()
418            }
419        }
420    }
421}
422
423#[cfg(not(feature = "unstable-test"))]
424#[doc(hidden)]
425pub struct IdRanges {
426    pub trace: core::ops::Range<u16>,
427    pub debug: core::ops::Range<u16>,
428    pub info: core::ops::Range<u16>,
429    pub warn: core::ops::Range<u16>,
430    pub error: core::ops::Range<u16>,
431}
432
433#[cfg(not(feature = "unstable-test"))]
434impl IdRanges {
435    pub fn get() -> Self {
436        extern "C" {
437            static __DEFMT_MARKER_TRACE_START: u8;
438            static __DEFMT_MARKER_TRACE_END: u8;
439            static __DEFMT_MARKER_DEBUG_START: u8;
440            static __DEFMT_MARKER_DEBUG_END: u8;
441            static __DEFMT_MARKER_INFO_START: u8;
442            static __DEFMT_MARKER_INFO_END: u8;
443            static __DEFMT_MARKER_WARN_START: u8;
444            static __DEFMT_MARKER_WARN_END: u8;
445            static __DEFMT_MARKER_ERROR_START: u8;
446            static __DEFMT_MARKER_ERROR_END: u8;
447        }
448
449        let trace_start = unsafe { &__DEFMT_MARKER_TRACE_START as *const u8 as u16 };
450        let trace_end = unsafe { &__DEFMT_MARKER_TRACE_END as *const u8 as u16 };
451        let debug_start = unsafe { &__DEFMT_MARKER_DEBUG_START as *const u8 as u16 };
452        let debug_end = unsafe { &__DEFMT_MARKER_DEBUG_END as *const u8 as u16 };
453        let info_start = unsafe { &__DEFMT_MARKER_INFO_START as *const u8 as u16 };
454        let info_end = unsafe { &__DEFMT_MARKER_INFO_END as *const u8 as u16 };
455        let warn_start = unsafe { &__DEFMT_MARKER_WARN_START as *const u8 as u16 };
456        let warn_end = unsafe { &__DEFMT_MARKER_WARN_END as *const u8 as u16 };
457        let error_start = unsafe { &__DEFMT_MARKER_ERROR_START as *const u8 as u16 };
458        let error_end = unsafe { &__DEFMT_MARKER_ERROR_END as *const u8 as u16 };
459        Self {
460            trace: trace_start..trace_end,
461            debug: debug_start..debug_end,
462            info: info_start..info_end,
463            warn: warn_start..warn_end,
464            error: error_start..error_end,
465        }
466    }
467}