summaryrefslogtreecommitdiff
path: root/rust/src
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2024-11-11 17:05:44 -0500
committerMason Reed <mason@vector35.com>2024-11-11 17:05:44 -0500
commite856d391d377d0a723563925bb0a841ead5ae012 (patch)
tree197df92e0dfc44e1f1e243bf4b35cd08ef8c1cfd /rust/src
parent911203528b5a5bfc7a98e86ad55b80f7a1385969 (diff)
Add actual logger api to rust
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/logger.rs91
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);