diff --git a/Cargo.toml b/Cargo.toml index 9e6fd81f56..d7447ca40d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ edition = "2018" url = "2.0" bitflags = "2.1.0" libc = "0.2" -log = "0.4.8" +log = "0.4.22" libgit2-sys = { path = "libgit2-sys", version = "0.17.0" } [target."cfg(all(unix, not(target_os = \"macos\")))".dependencies] diff --git a/src/lib.rs b/src/lib.rs index e52efb3734..84e2fad71e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -136,7 +136,7 @@ pub use crate::status::{StatusEntry, StatusIter, StatusOptions, StatusShow, Stat pub use crate::submodule::{Submodule, SubmoduleUpdateOptions}; pub use crate::tag::Tag; pub use crate::time::{IndexTime, Time}; -pub use crate::tracing::{trace_set, TraceLevel}; +pub use crate::tracing::{trace_set, trace_shim_log_crate, TraceLevel}; pub use crate::transaction::Transaction; pub use crate::tree::{Tree, TreeEntry, TreeIter, TreeWalkMode, TreeWalkResult}; pub use crate::treebuilder::TreeBuilder; diff --git a/src/tracing.rs b/src/tracing.rs index 5acae8a850..9baeaa83d9 100644 --- a/src/tracing.rs +++ b/src/tracing.rs @@ -1,6 +1,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use libc::c_char; +use log::RecordBuilder; use crate::{panic, raw, util::Binding}; @@ -57,6 +58,28 @@ impl Binding for TraceLevel { } } +impl TraceLevel { + /// Attempt to convert this [TraceLevel] to a [log::LevelFilter]. + /// + /// This function is not public to avoid having a public dependency on [`log`]. + /// + /// This is done trivially with two exceptions: + /// - [TraceLevel::None] goes to [None] + /// - [TraceLevel::Fatal] goes to [log::Level::Error]. + const fn as_log_level(self) -> Option { + use log::Level; + + match self { + Self::None => None, + Self::Fatal | Self::Error => Some(Level::Error), + Self::Warn => Some(Level::Warn), + Self::Info => Some(Level::Info), + Self::Debug => Some(Level::Debug), + Self::Trace => Some(Level::Trace), + } + } +} + //TODO: pass raw &[u8] and leave conversion to consumer (breaking API) /// Callback type used to pass tracing events to the subscriber. /// see `trace_set` to register a subscriber. @@ -64,7 +87,7 @@ pub type TracingCb = fn(TraceLevel, &str); static CALLBACK: AtomicUsize = AtomicUsize::new(0); -/// +/// Set the tracing callback. pub fn trace_set(level: TraceLevel, cb: TracingCb) -> bool { CALLBACK.store(cb as usize, Ordering::SeqCst); @@ -75,6 +98,27 @@ pub fn trace_set(level: TraceLevel, cb: TracingCb) -> bool { return true; } +/// Passes [trace_set] a shim function to pass tracing info to the [log] crate. +pub fn trace_shim_log_crate() { + // Use `trace` to get all tracing events -- let the user configure filtering + // through the `log` crate. + trace_set(TraceLevel::Trace, |level, msg| { + // Convert the trace level to a log level. + let log_level = level + .as_log_level() + .expect("libgit2 should not produce tracing events with level=None"); + + // Build a record to pass to the logger. + let mut record_builder = RecordBuilder::new(); + + // Set the target and level. + record_builder.target("libgit2").level(log_level); + + // Log the trace event to the global logger. + log::logger().log(&record_builder.args(format_args!("{}", msg)).build()); + }); +} + extern "C" fn tracing_cb_c(level: raw::git_trace_level_t, msg: *const c_char) { let cb = CALLBACK.load(Ordering::SeqCst); panic::wrap(|| unsafe {