Compare commits

...

5 commits

Author SHA1 Message Date
Nick Steel 707f03cd47 Merge branch 'log-trait-adapter' into 'main'
log: `Log` trait adapter around the GStreamer debug system

Closes #187

See merge request gstreamer/gstreamer-rs!1426
2024-04-25 13:48:23 +00:00
Nick Steel a77022ba0e log: check category above threshold 2024-04-22 01:05:38 +01:00
Nick Steel 8dd9a2d5ee log: DebugCategoryLogger is optional via 'log' feature 2024-04-21 22:23:36 +01:00
Sebastian Dröge 1438fa88db Apply 1 suggestion(s) to 1 file(s) 2024-04-21 09:22:32 +00:00
Nick Steel 08169aca96 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
2024-04-21 00:12:31 +01:00
3 changed files with 113 additions and 0 deletions

View file

@ -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 = { version = "0.4", optional = true }
muldiv = "1"
opt-ops = { package = "option-operations", version = "0.5" }
serde = { version = "1.0", optional = true, features = ["derive"] }
@ -48,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

View file

@ -49,6 +49,8 @@ mod serde_macros;
#[macro_use]
pub mod log;
#[cfg(feature = "log")]
pub use crate::log::DebugCategoryLogger;
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,

View file

@ -4,6 +4,8 @@ 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;
use crate::DebugLevel;
@ -1064,6 +1066,54 @@ 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)
}
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(
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<T>(
category: *mut ffi::GstDebugCategory,
level: ffi::GstDebugLevel,
@ -1308,6 +1358,65 @@ mod tests {
memdump!(cat, obj: obj, "meh");
}
#[cfg(feature = "log")]
static LOGGER: Lazy<DebugCategoryLogger> = Lazy::new(|| {
DebugCategoryLogger::new(DebugCategory::new(
"Log_trait",
crate::DebugColorFlags::empty(),
Some("Using the Log trait"),
))
});
#[test]
#[cfg(feature = "log")]
fn log_trait() {
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]
fn log_handler() {
crate::init().unwrap();