use std::cell::UnsafeCell;
use std::ffi::CString;
use std::sync::Once;
use log::{Level, Metadata, Record};
use winapi::um::winnt::HANDLE;
pub struct Logger {
handle: UnsafeCell<HANDLE>,
handle_init: Once,
log_name: &'static str,
}
unsafe impl Send for Logger {}
unsafe impl Sync for Logger {}
pub static LOGGER: Logger = Logger::new("Rust Application");
pub fn init() {
try_init().unwrap();
}
pub fn try_init() -> Result<(), log::SetLoggerError> {
log::set_logger(&LOGGER).map(|()| log::set_max_level(log::LevelFilter::Debug))
}
pub fn try_init_with_name(name: &'static str) -> Result<(), log::SetLoggerError> {
let logger = Box::leak(Box::new(Logger::new(name)));
log::set_logger(logger).map(|()| log::set_max_level(log::LevelFilter::Debug))
}
pub fn init_with_name(name: &'static str) {
let logger = Box::leak(Box::new(Logger::new(name)));
log::set_logger(logger).map(|()| log::set_max_level(log::LevelFilter::Debug)).unwrap();
}
impl Logger {
const fn new(log_name: &'static str) -> Self {
Self {
handle: UnsafeCell::new(std::ptr::null_mut()),
log_name,
handle_init: Once::new(),
}
}
}
impl log::Log for Logger {
fn enabled(&self, metadata: &Metadata) -> bool {
metadata.level() <= Level::Debug
}
fn log(&self, record: &Record) {
if self.enabled(record.metadata()) {
self.handle_init.call_once(|| {
let c_str = CString::new(self.log_name).unwrap();
let handle = unsafe {
winapi::um::winbase::RegisterEventSourceA(std::ptr::null_mut(), c_str.as_ptr())
};
unsafe { *self.handle.get() = handle };
});
let msg = format!(
"{}({}): {} - {}",
record.file().unwrap_or("<unknown>"),
record.line().unwrap_or(0),
record.level(),
record.args()
);
let event_type = match record.metadata().level() {
Level::Trace => winapi::um::winnt::EVENTLOG_INFORMATION_TYPE,
Level::Debug => winapi::um::winnt::EVENTLOG_INFORMATION_TYPE,
Level::Info => winapi::um::winnt::EVENTLOG_INFORMATION_TYPE,
Level::Warn => winapi::um::winnt::EVENTLOG_WARNING_TYPE,
Level::Error => winapi::um::winnt::EVENTLOG_ERROR_TYPE,
};
let wide_msg = widestring::U16CString::from_str(msg).unwrap();
let mut strings = [wide_msg.as_ptr()];
let handle = unsafe { *self.handle.get() };
unsafe {
winapi::um::winbase::ReportEventW(
handle,
event_type,
0,
0,
std::ptr::null_mut(),
1, 0,
&mut strings as *mut *const _,
std::ptr::null_mut(),
)
};
}
}
fn flush(&self) {}
}
impl Drop for Logger {
fn drop(&mut self) {
let handle = *self.handle.get_mut();
let _ = unsafe { winapi::um::winbase::DeregisterEventSource(handle) };
}
}