drmkit_log/macros.rs
1// SPDX-FileCopyrightText: (c) 2026 Joel Winarske
2// SPDX-License-Identifier: MIT
3
4//! The `log_*!` entry points.
5//!
6//! Each macro checks the active level *before* touching its arguments, so a
7//! record below the threshold costs one relaxed atomic load and a branch —
8//! the formatting arguments are never evaluated. This mirrors the C++
9//! templates, which pay formatting cost only when the level admits the record.
10
11/// Emit at [`LogLevel::Error`](crate::LogLevel::Error).
12#[macro_export]
13macro_rules! log_error {
14 ($($arg:tt)*) => {
15 $crate::__log_gated!($crate::LogLevel::Error, $($arg)*)
16 };
17}
18
19/// Emit at [`LogLevel::Warn`](crate::LogLevel::Warn).
20#[macro_export]
21macro_rules! log_warn {
22 ($($arg:tt)*) => {
23 $crate::__log_gated!($crate::LogLevel::Warn, $($arg)*)
24 };
25}
26
27/// Emit at [`LogLevel::Info`](crate::LogLevel::Info).
28#[macro_export]
29macro_rules! log_info {
30 ($($arg:tt)*) => {
31 $crate::__log_gated!($crate::LogLevel::Info, $($arg)*)
32 };
33}
34
35/// Emit at [`LogLevel::Debug`](crate::LogLevel::Debug).
36#[macro_export]
37macro_rules! log_debug {
38 ($($arg:tt)*) => {
39 $crate::__log_gated!($crate::LogLevel::Debug, $($arg)*)
40 };
41}
42
43/// Emit a line belonging to an opt-in diagnostic channel — one already gated
44/// by its own switch, such as the `DRM_ALLOC_DEBUG` / `DRM_EXT_DMABUF_DEBUG`
45/// environment variables on the C++ side.
46///
47/// **Deliberately bypasses the global level**: the channel's own gate *is* its
48/// threshold. This mirrors `GStreamer`, where `GST_DEBUG=cat:5` raises a named
49/// category above the default threshold — asking for a category by name is not
50/// vetoed by the default. Routing the other way would mean `DRM_ALLOC_DEBUG=1`
51/// printed nothing at the default `Info` level, which reads as the switch
52/// being broken.
53///
54/// What it does *not* bypass is the sink: channel output goes wherever
55/// [`set_log_sink`](crate::set_log_sink) points, so it survives on targets
56/// whose stderr goes nowhere.
57///
58/// Callers must check their own gate first — this pays full formatting cost
59/// unconditionally.
60///
61/// ```
62/// use drmkit_log::{LogLevel, log_channel};
63///
64/// if std::env::var_os("DRM_ALLOC_DEBUG").is_some() {
65/// log_channel!(LogLevel::Debug, "layer {} -> plane {}", 0, 31);
66/// }
67/// // Reaches the sink even at Silent -- the channel's own gate is its
68/// // threshold. Pinned by `channel_bypasses_level_but_not_sink`; not asserted
69/// // here because the level and sink are process-global.
70/// log_channel!(LogLevel::Debug, "always reaches the sink");
71/// ```
72#[macro_export]
73macro_rules! log_channel {
74 ($level:expr, $($arg:tt)*) => {
75 $crate::__emit($level, ::core::format_args!($($arg)*))
76 };
77}
78
79/// Shared body of the four level macros. Not public API.
80#[doc(hidden)]
81#[macro_export]
82macro_rules! __log_gated {
83 ($level:expr, $($arg:tt)*) => {{
84 let __drmkit_level = $level;
85 if $crate::log_level().admits(__drmkit_level) {
86 $crate::__emit(__drmkit_level, ::core::format_args!($($arg)*));
87 }
88 }};
89}