Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions glib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ v2_82 = ["v2_80", "glib-sys/v2_82", "gobject-sys/v2_82"]
v2_84 = ["v2_82", "glib-sys/v2_84", "gobject-sys/v2_84"]
v2_86 = ["v2_84", "glib-sys/v2_86", "gobject-sys/v2_86"]
log = ["rs-log"]
log_kv = ["log", "rs-log/kv"]
log_macros = ["log"]
compiletests = []
gio = ["gio-sys"]
Expand Down
105 changes: 103 additions & 2 deletions glib/src/bridged_logging.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Take a look at the license at the top of the repository in the LICENSE file.

use crate::{gstr, log as glib_log, log_structured_array, translate::*, LogField};
use crate::{gstr, log as glib_log, log_structured_array, translate::*, LogField, LogWriterOutput};

// rustdoc-stripper-ignore-next
/// Enumeration of the possible formatting behaviours for a
Expand Down Expand Up @@ -262,7 +262,108 @@ pub fn rust_log_handler(domain: Option<&str>, level: glib_log::LogLevel, message
glib_log::LogLevel::Debug => rs_log::Level::Debug,
};

rs_log::log!(target: domain.unwrap_or("<null>"), level, "{}", message);
rs_log::log!(target: domain.unwrap_or_default(), level, "{message}");
}

#[cfg(feature = "log_kv")]
struct LogFields<'field>(&'field [LogField<'field>]);

#[cfg(feature = "log_kv")]
impl<'fields> rs_log::kv::Source for LogFields<'fields> {
fn visit<'kvs>(
&'kvs self,
visitor: &mut dyn rs_log::kv::VisitSource<'kvs>,
) -> Result<(), rs_log::kv::Error> {
use rs_log::kv::{Key, Value};

for field in self.0 {
let key = Key::from_str(field.key());
let value = field
.value_str()
.map(Value::from)
.unwrap_or_else(Value::null);
visitor.visit_pair(key, value)?;
}

Ok(())
}

fn count(&self) -> usize {
self.0.len()
}
}

// rustdoc-stripper-ignore-next
/// Provides a glib log writer which routes all structured logging messages to the
/// [`log crate`](https://crates.io/crates/log).
///
/// In order to use this function, `glib` must be built with the `log` feature
/// enabled.
///
/// Use this function if you want to use the log crate as the main logging
/// output in your application, and want to route all structured logging happening in
/// glib to the log crate. If you want the opposite, use [`GlibLogger`](struct.GlibLogger.html).
///
/// NOTE: This should never be used when [`GlibLogger`](struct.GlibLogger.html) is
/// registered as a logger, otherwise a stack overflow will occur.
///
/// ```no_run
/// glib::log_set_writer_func(glib::rust_log_writer);
/// ```
pub fn rust_log_writer(log_level: glib_log::LogLevel, fields: &[LogField<'_>]) -> LogWriterOutput {
let lvl = match log_level {
glib_log::LogLevel::Error | glib_log::LogLevel::Critical => rs_log::Level::Error,
glib_log::LogLevel::Warning => rs_log::Level::Warn,
glib_log::LogLevel::Info | glib_log::LogLevel::Message => rs_log::Level::Info,
glib_log::LogLevel::Debug => rs_log::Level::Debug,
};

if lvl > rs_log::STATIC_MAX_LEVEL {
return LogWriterOutput::Handled;
}

let mut domain = None::<&str>;
let mut message = None::<&str>;
let mut file = None::<&str>;
let mut line = None::<u32>;
let mut func = None::<&str>;

for field in fields {
let Some(value) = field.value_str() else {
continue;
};

match field.key() {
"GLIB_DOMAIN" => domain = Some(value),
"MESSAGE" => message = Some(value),
"CODE_FILE" => file = Some(value),
"CODE_LINE" => line = value.parse().ok(),
"CODE_FUNC" => func = Some(value),
_ => continue,
};
}

if let Some(message) = message {
let logger = rs_log::logger();
let mut record = rs_log::Record::builder();

#[cfg(feature = "log_kv")]
let fields = LogFields(fields);

record
.level(lvl)
.target(domain.unwrap_or_default())
.file(file)
.line(line)
.module_path(func);

#[cfg(feature = "log_kv")]
record.key_values(&fields);

logger.log(&record.args(format_args!("{message}")).build());
}

LogWriterOutput::Handled
}

// rustdoc-stripper-ignore-next
Expand Down
4 changes: 3 additions & 1 deletion glib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,9 @@ pub use self::log::{log_writer_is_journald, log_writer_supports_color};
mod bridged_logging;
#[cfg(feature = "log")]
#[cfg_attr(docsrs, doc(cfg(feature = "log")))]
pub use self::bridged_logging::{rust_log_handler, GlibLogger, GlibLoggerDomain, GlibLoggerFormat};
pub use self::bridged_logging::{
rust_log_handler, rust_log_writer, GlibLogger, GlibLoggerDomain, GlibLoggerFormat,
};

#[macro_use]
pub mod subclass;
Expand Down
Loading