From 08169aca96816ec7600c6176be1c5759bbc2857c Mon Sep 17 00:00:00 2001 From: Nick Steel Date: Sun, 21 Apr 2024 00:12:31 +0100 Subject: [PATCH 1/4] log: `Log` trait adapter around the GStreamer debug system Allows usage of normal `log` crate macros, and for other crates using those macros to have their log messages go to the GStreamer debug logs. This implementation is based on the one found in Servo. Fixes #187 --- gstreamer/Cargo.toml | 1 + gstreamer/src/lib.rs | 12 +++++----- gstreamer/src/log.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/gstreamer/Cargo.toml b/gstreamer/Cargo.toml index d6e20807b..7324a7566 100644 --- a/gstreamer/Cargo.toml +++ b/gstreamer/Cargo.toml @@ -23,6 +23,7 @@ num-rational = { version = "0.4", default-features = false, features = [] } futures-core = "0.3" futures-channel = "0.3" futures-util = { version = "0.3", default-features = false } +log = "0.4" muldiv = "1" opt-ops = { package = "option-operations", version = "0.5" } serde = { version = "1.0", optional = true, features = ["derive"] } diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 2d65fa6ad..71b499e27 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -50,12 +50,12 @@ mod serde_macros; #[macro_use] pub mod log; pub use crate::log::{ - DebugCategory, DebugLogFunction, DebugMessage, LoggedObject, CAT_BUFFER, CAT_BUFFER_LIST, - CAT_BUS, CAT_CALL_TRACE, CAT_CAPS, CAT_CLOCK, CAT_CONTEXT, CAT_DEFAULT, CAT_ELEMENT_PADS, - CAT_ERROR_SYSTEM, CAT_EVENT, CAT_GST_INIT, CAT_LOCKING, CAT_MEMORY, CAT_MESSAGE, CAT_META, - CAT_NEGOTIATION, CAT_PADS, CAT_PARAMS, CAT_PARENTAGE, CAT_PERFORMANCE, CAT_PIPELINE, - CAT_PLUGIN_INFO, CAT_PLUGIN_LOADING, CAT_PROBE, CAT_PROPERTIES, CAT_QOS, CAT_REFCOUNTING, - CAT_REGISTRY, CAT_RUST, CAT_SCHEDULING, CAT_SIGNAL, CAT_STATES, + DebugCategory, DebugCategoryLogger, DebugLogFunction, DebugMessage, LoggedObject, CAT_BUFFER, + CAT_BUFFER_LIST, CAT_BUS, CAT_CALL_TRACE, CAT_CAPS, CAT_CLOCK, CAT_CONTEXT, CAT_DEFAULT, + CAT_ELEMENT_PADS, CAT_ERROR_SYSTEM, CAT_EVENT, CAT_GST_INIT, CAT_LOCKING, CAT_MEMORY, + CAT_MESSAGE, CAT_META, CAT_NEGOTIATION, CAT_PADS, CAT_PARAMS, CAT_PARENTAGE, CAT_PERFORMANCE, + CAT_PIPELINE, CAT_PLUGIN_INFO, CAT_PLUGIN_LOADING, CAT_PROBE, CAT_PROPERTIES, CAT_QOS, + CAT_REFCOUNTING, CAT_REGISTRY, CAT_RUST, CAT_SCHEDULING, CAT_SIGNAL, CAT_STATES, }; #[cfg(target_os = "macos")] diff --git a/gstreamer/src/log.rs b/gstreamer/src/log.rs index 8c90f5d8d..a4bb96982 100644 --- a/gstreamer/src/log.rs +++ b/gstreamer/src/log.rs @@ -4,6 +4,7 @@ use std::{borrow::Cow, ffi::CStr, fmt, ptr}; use glib::{ffi::gpointer, prelude::*, translate::*}; use libc::c_char; +use log; use once_cell::sync::Lazy; use crate::DebugLevel; @@ -1064,6 +1065,42 @@ macro_rules! log_with_level( }}; ); +pub struct DebugCategoryLogger(DebugCategory); + +impl DebugCategoryLogger { + pub fn new(cat: DebugCategory) -> Self { + Self(cat) + } +} + +impl log::Log for DebugCategoryLogger { + fn enabled(&self, _metadata: &log::Metadata) -> bool { + true + } + + fn log(&self, record: &log::Record) { + let lvl = match record.level() { + log::Level::Error => DebugLevel::Error, + log::Level::Warn => DebugLevel::Warning, + log::Level::Info => DebugLevel::Info, + log::Level::Debug => DebugLevel::Debug, + log::Level::Trace => DebugLevel::Trace, + }; + let file = record.file().unwrap_or(""); + let file = glib::GStr::from_str_until_nul(file).unwrap_or_default(); + self.0.log( + None::<&glib::Object>, + lvl, + file, + record.module_path().unwrap_or(""), + record.line().unwrap_or(0), + record.args().clone(), + ); + } + + fn flush(&self) {} +} + unsafe extern "C" fn log_handler( category: *mut ffi::GstDebugCategory, level: ffi::GstDebugLevel, @@ -1308,6 +1345,22 @@ mod tests { memdump!(cat, obj: obj, "meh"); } + static LOGGER: Lazy = Lazy::new(|| { + DebugCategoryLogger::new(DebugCategory::new( + "Log_trait", + crate::DebugColorFlags::empty(), + Some("Using the Log trait"), + )) + }); + + #[test] + fn log_trait() { + crate::init().unwrap(); + + log::set_logger(&(*LOGGER)).expect("Failed to set logger"); + log::error!("meh"); + } + #[test] fn log_handler() { crate::init().unwrap(); From 1438fa88db8282cf82cf66d1b4b9bab9a6ea7a9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sun, 21 Apr 2024 09:22:32 +0000 Subject: [PATCH 2/4] Apply 1 suggestion(s) to 1 file(s) --- gstreamer/src/log.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/gstreamer/src/log.rs b/gstreamer/src/log.rs index a4bb96982..c3c1b7441 100644 --- a/gstreamer/src/log.rs +++ b/gstreamer/src/log.rs @@ -1065,6 +1065,7 @@ macro_rules! log_with_level( }}; ); +#[derive(Debug)] pub struct DebugCategoryLogger(DebugCategory); impl DebugCategoryLogger { From 8dd9a2d5ee114157212e6ab662fca12171ea4f0c Mon Sep 17 00:00:00 2001 From: Nick Steel Date: Sun, 21 Apr 2024 22:12:44 +0100 Subject: [PATCH 3/4] log: DebugCategoryLogger is optional via 'log' feature --- gstreamer/Cargo.toml | 3 ++- gstreamer/src/lib.rs | 14 ++++++++------ gstreamer/src/log.rs | 6 ++++++ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/gstreamer/Cargo.toml b/gstreamer/Cargo.toml index 7324a7566..214964006 100644 --- a/gstreamer/Cargo.toml +++ b/gstreamer/Cargo.toml @@ -23,7 +23,7 @@ num-rational = { version = "0.4", default-features = false, features = [] } futures-core = "0.3" futures-channel = "0.3" futures-util = { version = "0.3", default-features = false } -log = "0.4" +log = { version = "0.4", optional = true } muldiv = "1" opt-ops = { package = "option-operations", version = "0.5" } serde = { version = "1.0", optional = true, features = ["derive"] } @@ -49,6 +49,7 @@ v1_20 = ["ffi/v1_20", "v1_18"] v1_22 = ["ffi/v1_22", "v1_20"] v1_24 = ["ffi/v1_24", "v1_22"] serde = ["num-rational/serde", "dep:serde", "serde_bytes"] +log = ["dep:log"] [package.metadata.docs.rs] all-features = true diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 71b499e27..d3cf22f01 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -49,13 +49,15 @@ mod serde_macros; #[macro_use] pub mod log; +#[cfg(feature = "log")] +pub use crate::log::DebugCategoryLogger; pub use crate::log::{ - DebugCategory, DebugCategoryLogger, DebugLogFunction, DebugMessage, LoggedObject, CAT_BUFFER, - CAT_BUFFER_LIST, CAT_BUS, CAT_CALL_TRACE, CAT_CAPS, CAT_CLOCK, CAT_CONTEXT, CAT_DEFAULT, - CAT_ELEMENT_PADS, CAT_ERROR_SYSTEM, CAT_EVENT, CAT_GST_INIT, CAT_LOCKING, CAT_MEMORY, - CAT_MESSAGE, CAT_META, CAT_NEGOTIATION, CAT_PADS, CAT_PARAMS, CAT_PARENTAGE, CAT_PERFORMANCE, - CAT_PIPELINE, CAT_PLUGIN_INFO, CAT_PLUGIN_LOADING, CAT_PROBE, CAT_PROPERTIES, CAT_QOS, - CAT_REFCOUNTING, CAT_REGISTRY, CAT_RUST, CAT_SCHEDULING, CAT_SIGNAL, CAT_STATES, + DebugCategory, DebugLogFunction, DebugMessage, LoggedObject, CAT_BUFFER, CAT_BUFFER_LIST, + CAT_BUS, CAT_CALL_TRACE, CAT_CAPS, CAT_CLOCK, CAT_CONTEXT, CAT_DEFAULT, CAT_ELEMENT_PADS, + CAT_ERROR_SYSTEM, CAT_EVENT, CAT_GST_INIT, CAT_LOCKING, CAT_MEMORY, CAT_MESSAGE, CAT_META, + CAT_NEGOTIATION, CAT_PADS, CAT_PARAMS, CAT_PARENTAGE, CAT_PERFORMANCE, CAT_PIPELINE, + CAT_PLUGIN_INFO, CAT_PLUGIN_LOADING, CAT_PROBE, CAT_PROPERTIES, CAT_QOS, CAT_REFCOUNTING, + CAT_REGISTRY, CAT_RUST, CAT_SCHEDULING, CAT_SIGNAL, CAT_STATES, }; #[cfg(target_os = "macos")] diff --git a/gstreamer/src/log.rs b/gstreamer/src/log.rs index c3c1b7441..9479432e3 100644 --- a/gstreamer/src/log.rs +++ b/gstreamer/src/log.rs @@ -4,6 +4,7 @@ use std::{borrow::Cow, ffi::CStr, fmt, ptr}; use glib::{ffi::gpointer, prelude::*, translate::*}; use libc::c_char; +#[cfg(feature = "log")] use log; use once_cell::sync::Lazy; @@ -1065,15 +1066,18 @@ macro_rules! log_with_level( }}; ); +#[cfg(feature = "log")] #[derive(Debug)] pub struct DebugCategoryLogger(DebugCategory); +#[cfg(feature = "log")] impl DebugCategoryLogger { pub fn new(cat: DebugCategory) -> Self { Self(cat) } } +#[cfg(feature = "log")] impl log::Log for DebugCategoryLogger { fn enabled(&self, _metadata: &log::Metadata) -> bool { true @@ -1346,6 +1350,7 @@ mod tests { memdump!(cat, obj: obj, "meh"); } + #[cfg(feature = "log")] static LOGGER: Lazy = Lazy::new(|| { DebugCategoryLogger::new(DebugCategory::new( "Log_trait", @@ -1355,6 +1360,7 @@ mod tests { }); #[test] + #[cfg(feature = "log")] fn log_trait() { crate::init().unwrap(); From a77022ba0ef55a97827890900ca3a36b3a4a0906 Mon Sep 17 00:00:00 2001 From: Nick Steel Date: Mon, 22 Apr 2024 00:54:33 +0100 Subject: [PATCH 4/4] log: check category above threshold --- gstreamer/src/log.rs | 69 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 10 deletions(-) diff --git a/gstreamer/src/log.rs b/gstreamer/src/log.rs index 9479432e3..91bb9ad46 100644 --- a/gstreamer/src/log.rs +++ b/gstreamer/src/log.rs @@ -1075,22 +1075,30 @@ impl DebugCategoryLogger { pub fn new(cat: DebugCategory) -> Self { Self(cat) } -} -#[cfg(feature = "log")] -impl log::Log for DebugCategoryLogger { - fn enabled(&self, _metadata: &log::Metadata) -> bool { - true - } - - fn log(&self, record: &log::Record) { - let lvl = match record.level() { + fn to_level(level: log::Level) -> crate::DebugLevel { + match level { log::Level::Error => DebugLevel::Error, log::Level::Warn => DebugLevel::Warning, log::Level::Info => DebugLevel::Info, log::Level::Debug => DebugLevel::Debug, log::Level::Trace => DebugLevel::Trace, - }; + } + } +} + +#[cfg(feature = "log")] +impl log::Log for DebugCategoryLogger { + fn enabled(&self, metadata: &log::Metadata) -> bool { + let lvl = DebugCategoryLogger::to_level(metadata.level()); + is_active() && self.0.above_threshold(lvl) + } + + fn log(&self, record: &log::Record) { + if !self.enabled(record.metadata()) { + return; + } + let lvl = DebugCategoryLogger::to_level(record.level()); let file = record.file().unwrap_or(""); let file = glib::GStr::from_str_until_nul(file).unwrap_or_default(); self.0.log( @@ -1365,7 +1373,48 @@ mod tests { crate::init().unwrap(); log::set_logger(&(*LOGGER)).expect("Failed to set logger"); + log::set_max_level(log::LevelFilter::Trace); log::error!("meh"); + log::warn!("fish"); + + let (sender, receiver) = mpsc::channel(); + let sender = Arc::new(Mutex::new(sender)); + let handler = move |category: DebugCategory, + level: DebugLevel, + _file: &glib::GStr, + _function: &glib::GStr, + _line: u32, + _object: Option<&LoggedObject>, + message: &DebugMessage| { + let cat = DebugCategory::get("Log_trait").unwrap(); + + if category != cat { + // This test can run in parallel with other tests, including new_and_log above. + // We cannot be certain we only see our own messages. + return; + } + + assert_eq!(level, DebugLevel::Error); + assert_eq!(message.get().unwrap().as_ref(), "meh"); + let _ = sender.lock().unwrap().send(()); + }; + + remove_default_log_function(); + add_log_function(handler); + + let cat = LOGGER.0; + + cat.set_threshold(crate::DebugLevel::Warning); + log::error!("meh"); + receiver.recv().unwrap(); + + cat.set_threshold(crate::DebugLevel::Error); + log::error!("meh"); + receiver.recv().unwrap(); + + cat.set_threshold(crate::DebugLevel::None); + log::error!("fish"); + log::warn!("meh"); } #[test]