Skip to main content

media_pp/core/
pp_log.rs

1//! Contextual logging identity and macros used by pipeline elements.
2//!
3//! A [`PpLog`] stores the stable, structured identity for one element. The `pp_*`
4//! macros send records only to [`crate::log`]'s opt-in private file writer,
5//! keeping them isolated from an embedding application's global logger.
6
7use std::sync::Arc;
8
9/// Stable contextual identity attached to a pipeline element's log records.
10#[derive(Debug, Clone)]
11pub struct PpLog {
12    pipeline_id: Option<Arc<str>>,
13    element: Arc<str>,
14    name: Arc<str>,
15}
16
17impl PpLog {
18    /// Creates a logging identity.
19    ///
20    /// `element` is the element type (for example `FileDemuxer`), while
21    /// `name` is the caller-selected instance name (for example `demux`).
22    /// `pipeline_id` is omitted until the element is attached to a pipeline.
23    pub fn new(element: &str, name: &str, pipeline_id: Option<&str>) -> Self {
24        Self {
25            pipeline_id: pipeline_id.map(Arc::from),
26            element: Arc::from(element),
27            name: Arc::from(name),
28        }
29    }
30
31    /// Returns the pipeline identity attached to this logging context, if any.
32    pub fn pipeline_id(&self) -> Option<&str> {
33        self.pipeline_id.as_deref()
34    }
35
36    /// Returns the element type label attached to this logging context.
37    pub fn element(&self) -> &str {
38        &self.element
39    }
40
41    /// Returns the element instance name attached to this logging context.
42    pub fn name(&self) -> &str {
43        &self.name
44    }
45}
46
47#[doc(hidden)]
48pub mod __private {
49    pub use crate::log::{Level, emit, enabled};
50}
51
52#[doc(hidden)]
53#[macro_export]
54macro_rules! __pp_log {
55    ($level:expr, pp_log: $pp_log:expr, $($arg:tt)+) => {{
56        let level = $level;
57        if $crate::pp_log::__private::enabled(level) {
58            $crate::pp_log::__private::emit(
59                level,
60                $pp_log,
61                format_args!($($arg)+),
62            );
63        }
64    }};
65    ($level:expr, $self:ident, $($arg:tt)+) => {{
66        let level = $level;
67        if $crate::pp_log::__private::enabled(level) {
68            $crate::pp_log::__private::emit(
69                level,
70                &$self.pp_log,
71                format_args!($($arg)+),
72            );
73        }
74    }};
75}
76
77/// Logs at [`Level::Info`](crate::log::Level::Info) — sparse lifecycle and
78/// topology changes, not per-buffer activity.
79///
80/// Takes either an explicit identity (`pp_info!(pp_log: &self.pp_log, "..")`)
81/// or, for a type with a `pp_log` field, the receiver itself
82/// (`pp_info!(self, "..")`). Formatting is skipped entirely when the level is
83/// disabled, so a call on a hot path costs a level check rather than a
84/// formatted string.
85#[macro_export]
86macro_rules! pp_info {
87    ($($arg:tt)+) => {
88        $crate::__pp_log!($crate::pp_log::__private::Level::Info, $($arg)+)
89    };
90}
91
92/// Logs at [`Level::Debug`](crate::log::Level::Debug) — diagnostic state. Same
93/// forms and cost as [`pp_info!`].
94#[macro_export]
95macro_rules! pp_debug {
96    ($($arg:tt)+) => {
97        $crate::__pp_log!($crate::pp_log::__private::Level::Debug, $($arg)+)
98    };
99}
100
101/// Logs at [`Level::Warn`](crate::log::Level::Warn) — degraded or recovered
102/// conditions. Same forms and cost as [`pp_info!`].
103#[macro_export]
104macro_rules! pp_warn {
105    ($($arg:tt)+) => {
106        $crate::__pp_log!($crate::pp_log::__private::Level::Warn, $($arg)+)
107    };
108}
109
110/// Logs at [`Level::Error`](crate::log::Level::Error) — a failed operation.
111/// Same forms and cost as [`pp_info!`].
112#[macro_export]
113macro_rules! pp_error {
114    ($($arg:tt)+) => {
115        $crate::__pp_log!($crate::pp_log::__private::Level::Error, $($arg)+)
116    };
117}
118
119/// Logs at [`Level::Trace`](crate::log::Level::Trace) — EOS and control-flow
120/// detail at element and thread boundaries. Same forms and cost as
121/// [`pp_info!`].
122#[macro_export]
123macro_rules! pp_trace {
124    ($($arg:tt)+) => {
125        $crate::__pp_log!($crate::pp_log::__private::Level::Trace, $($arg)+)
126    };
127}
128
129pub use crate::{pp_debug, pp_error, pp_info, pp_trace, pp_warn};
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134
135    #[test]
136    fn keeps_each_identity_field_separate() {
137        let pp_log = PpLog::new("FileDemuxer", "demux", Some("app-sink"));
138        assert_eq!(pp_log.pipeline_id(), Some("app-sink"));
139        assert_eq!(pp_log.element(), "FileDemuxer");
140        assert_eq!(pp_log.name(), "demux");
141    }
142}