diff options
| author | Mason Reed <mason@vector35.com> | 2024-11-11 17:05:44 -0500 |
|---|---|---|
| committer | Mason Reed <mason@vector35.com> | 2024-11-11 17:05:44 -0500 |
| commit | e856d391d377d0a723563925bb0a841ead5ae012 (patch) | |
| tree | 197df92e0dfc44e1f1e243bf4b35cd08ef8c1cfd /rust/src | |
| parent | 911203528b5a5bfc7a98e86ad55b80f7a1385969 (diff) | |
Add actual logger api to rust
Diffstat (limited to 'rust/src')
| -rw-r--r-- | rust/src/logger.rs | 91 |
1 files changed, 72 insertions, 19 deletions
diff --git a/rust/src/logger.rs b/rust/src/logger.rs index 4e9dd1f9..487761e3 100644 --- a/rust/src/logger.rs +++ b/rust/src/logger.rs @@ -3,11 +3,11 @@ //! To use logging in your script, do something like: //! //! ```no-test -//! use binaryninja::logger; +//! use binaryninja::logger::Logger; //! use log::{info, LevelFilter}; //! //! fn main() { -//! logger::init(LevelFilter::Warn).expect("Unable to initialize logger"); +//! Logger::default().init(); //! info!("The logger has been initialized!"); //! // Your code here... //! } @@ -16,12 +16,12 @@ //! or //! //!```no-test -//! use binaryninja::logger; +//! use binaryninja::logger::Logger; //! use log::{info, LevelFilter}; //! //! #[no_mangle] //! pub extern "C" fn CorePluginInit() -> bool { -//! logger::init(LevelFilter::Warn).expect("Unable to initialize logger"); +//! Logger::new("My Plugin").with_level(LevelFilter::Warn).init(); //! info!("The logger has been initialized!"); //! // Your code here... //! true @@ -30,14 +30,73 @@ //! pub use binaryninjacore_sys::BNLogLevel as Level; -use binaryninjacore_sys::{BNLogListener, BNUpdateLogListeners}; +use binaryninjacore_sys::{ + BNFreeLogger, BNLogCreateLogger, BNLogListener, BNLogger, BNLoggerGetName, + BNLoggerGetSessionId, BNUpdateLogListeners, +}; +use crate::string::BnString; use log; -use std::ffi::CStr; +use log::LevelFilter; +use std::ffi::{CStr, CString}; use std::os::raw::{c_char, c_void}; +use std::ptr::NonNull; -struct Logger; -static LOGGER: Logger = Logger; +const LOGGER_DEFAULT_SESSION_ID: usize = 0; + +pub struct Logger { + handle: NonNull<BNLogger>, + level: LevelFilter, +} + +impl Logger { + pub fn new(name: &str) -> Logger { + Self::new_with_session(name, LOGGER_DEFAULT_SESSION_ID) + } + + pub fn new_with_session(name: &str, session_id: usize) -> Logger { + let name_raw = CString::new(name).unwrap(); + let handle = unsafe { BNLogCreateLogger(name_raw.as_ptr(), session_id) }; + Logger { + handle: NonNull::new(handle).unwrap(), + level: LevelFilter::Debug, + } + } + + pub fn with_level(mut self, level: LevelFilter) -> Logger { + self.level = level; + self + } + + /// Calling this will set the global logger to `self`. + /// + /// NOTE: There is no guarantee that logs will be sent to BinaryNinja as another log sink + /// may have already been initialized beforehand. + pub fn init(self) { + log::set_max_level(self.level); + let _ = log::set_boxed_logger(Box::new(self)); + } + + pub fn name(&self) -> BnString { + unsafe { BnString::from_raw(BNLoggerGetName(self.handle.as_ptr())) } + } + + pub fn session_id(&self) -> usize { + unsafe { BNLoggerGetSessionId(self.handle.as_ptr()) } + } +} + +impl Default for Logger { + fn default() -> Self { + Logger::new("Default") + } +} + +impl Drop for Logger { + fn drop(&mut self) { + unsafe { BNFreeLogger(self.handle.as_ptr()) }; + } +} impl log::Log for Logger { fn enabled(&self, _metadata: &log::Metadata) -> bool { @@ -48,7 +107,6 @@ impl log::Log for Logger { use self::Level::*; use binaryninjacore_sys::BNLog; use log::Level; - use std::ffi::CString; let level = match record.level() { Level::Error => ErrorLog, @@ -59,11 +117,12 @@ impl log::Log for Logger { if let Ok(msg) = CString::new(format!("{}", record.args())) { let percent_s = CString::new("%s").expect("'%s' has no null bytes"); + let logger_name = self.name(); unsafe { BNLog( - 0, + self.session_id(), level, - std::ptr::null(), + logger_name.into_raw(), 0, percent_s.as_ptr(), msg.as_ptr(), @@ -75,14 +134,8 @@ impl log::Log for Logger { fn flush(&self) {} } -/// Uses BinaryNinja's logging functionality as the sink for Rust's `log` crate. -/// -/// NOTE: There is no guarantee that logs will be sent to BinaryNinja as another log sink -/// may have already been initialized beforehand. -pub fn init(filter: log::LevelFilter) { - log::set_max_level(filter); - let _ = log::set_logger(&LOGGER); -} +unsafe impl Send for Logger {} +unsafe impl Sync for Logger {} pub trait LogListener: 'static + Sync { fn log(&self, session: usize, level: Level, msg: &CStr, logger_name: &CStr, tid: usize); |
