From c545290e3c8a20872e4ec8857c3c6ca29f7599e6 Mon Sep 17 00:00:00 2001 From: itsscb Date: Wed, 4 Jun 2025 12:08:18 +0000 Subject: [PATCH] Update src/eventlog.rs --- src/eventlog.rs | 133 ++++++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 62 deletions(-) diff --git a/src/eventlog.rs b/src/eventlog.rs index 6ffed91..a7f6baf 100644 --- a/src/eventlog.rs +++ b/src/eventlog.rs @@ -1,69 +1,84 @@ use std::collections::HashMap; -use std::ffi::CString; use tracing::field::Visit; use tracing::{Level, Subscriber}; use tracing_subscriber::registry::LookupSpan; use tracing_subscriber::Layer; -use winapi::shared::minwindef::DWORD; -use winapi::um::winbase::{DeregisterEventSource, RegisterEventSourceA, ReportEventA}; -use winapi::um::winnt::{EVENTLOG_ERROR_TYPE, EVENTLOG_INFORMATION_TYPE, EVENTLOG_WARNING_TYPE}; +use windows::core::{HSTRING, PCWSTR}; +use windows::Win32::Foundation::HANDLE; +use windows::Win32::System::EventLog::{DeregisterEventSource, RegisterEventSourceW, ReportEventW, EVENTLOG_ERROR_TYPE, EVENTLOG_INFORMATION_TYPE, EVENTLOG_WARNING_TYPE}; -#[allow(clippy::manual_c_str_literals)] -pub fn write_to_event_log(event_id: u32, level: Level, message: &str, log_name: &str) { - let event_source = unsafe { - RegisterEventSourceA( - std::ptr::null(), - format!("{log_name}\0").as_ptr().cast::(), - ) - }; +/// Wrapper to mark the HANDLE as Send & Sync +#[repr(transparent)] +#[derive(Clone, Copy, Debug)] +struct EventSourceHandle { + hwnd: *mut std::ffi::c_void, +} +unsafe impl Send for EventSourceHandle {} +unsafe impl Sync for EventSourceHandle {} - if event_source.is_null() { - eprintln!("Failed to register event source"); - return; +impl From for HANDLE { + fn from(value: EventSourceHandle) -> Self { + Self(value.hwnd) } +} +impl From for EventSourceHandle { + fn from(value: HANDLE) -> Self { + Self{ hwnd: value.0 } + } +} + +pub fn write_to_event_log(event_source: HANDLE, event_id: u32, level: Level, message: &str) { let event_type = match level { Level::ERROR => EVENTLOG_ERROR_TYPE, Level::WARN => EVENTLOG_WARNING_TYPE, Level::INFO | Level::DEBUG | Level::TRACE => EVENTLOG_INFORMATION_TYPE, }; - let Ok(message_cstr) = CString::new(message) else { - eprintln!("failed to create CString from message: {message}"); - return; - }; - - let result = unsafe { - ReportEventA( + let message = HSTRING::from(message); + if let Err(e) = unsafe { + ReportEventW( event_source, event_type, 0, - event_id as DWORD, - std::ptr::null_mut(), - 1, + event_id, + None, 0, - &mut message_cstr.as_ptr(), - std::ptr::null_mut(), + Some(&[PCWSTR(message.as_ptr())]), + None, ) + } { + eprintln!("Failed to write to event log: {:?}", e); }; - - if result == 0 { - eprintln!("Failed to write to event log"); - } - - unsafe { - DeregisterEventSource(event_source); - } } pub struct EventLogLayer { - log_name: String, + event_source: EventSourceHandle, + default_id: Option +} + +impl Drop for EventLogLayer { + fn drop(&mut self) { + let _ = unsafe { DeregisterEventSource(self.event_source.into()) }; + } } impl EventLogLayer { - #[must_use] - pub const fn new(log_name: String) -> Self { - Self { log_name } + pub fn new(log_name: &str) -> Result { + Self::new_with_default_id(log_name, None) + } + + pub fn new_with_default_id(log_name: &str, default_id: Option) -> Result { + let log_name = HSTRING::from(log_name); + let Ok(event_source) = (unsafe { + RegisterEventSourceW( + None, + PCWSTR(log_name.as_ptr()) + ) + }) else { + return Err(windows_result::Error::from_win32()); + }; + Ok(Self { event_source: event_source.into(), default_id }) } } impl Layer for EventLogLayer @@ -74,11 +89,12 @@ where let metadata = event.metadata(); let mut visitor = EventVisitor { + event_source: self.event_source.into(), + default_id: self.default_id, id: None, message: None, parents: None, log_level: *metadata.level(), - log_name: &self.log_name, fields: HashMap::new(), }; @@ -113,50 +129,44 @@ where } #[derive(Debug)] -struct EventVisitor<'a> { +struct EventVisitor { + event_source: HANDLE, + default_id: Option, id: Option, log_level: Level, message: Option, parents: Option, fields: HashMap, - log_name: &'a str, } -impl<'a> EventVisitor<'a> { +impl EventVisitor { fn log(&self) { - let id: u32 = self.id.unwrap_or(match self.log_level { - Level::TRACE => 0, - Level::DEBUG => 1, - Level::INFO => 2, - Level::WARN => 3, - Level::ERROR => 4, - }); + let id: u32 = self.id.unwrap_or(self.default_id.unwrap_or_default()); - let mut msg = format!("ID: {id}\n\n"); + let mut msg = String::new(); + + if let Some(m) = &self.message { + msg.push_str(&format!("{m}\n\n")); + } if let Some(m) = &self.parents { msg.push_str(&format!("source: {m}\n")); } - if let Some(m) = &self.message { - msg.push_str(&format!("message: {m}\n")); - } - self.fields.iter().for_each(|i| { msg.push_str(&format!("{}: {:?}\n", i.0, i.1.replace(r"\\", r"\"))); }); - write_to_event_log(id, self.log_level, &msg, self.log_name); + write_to_event_log(self.event_source, id, self.log_level, &msg); } } -impl<'a> Visit for EventVisitor<'a> { +impl Visit for EventVisitor { #[allow(clippy::cast_possible_truncation)] fn record_u64(&mut self, field: &tracing::field::Field, value: u64) { if field.name().to_lowercase() == "id" && value <= u32::MAX.into() { self.id = Some(value as u32); } else { - self.fields - .insert(field.name().to_string(), format!("{value}")); + self.record_debug(field, &value); } } @@ -165,8 +175,7 @@ impl<'a> Visit for EventVisitor<'a> { if field.name().to_lowercase() == "id" && value >= 0 && value <= u32::MAX.into() { self.id = Some(value as u32); } else { - self.fields - .insert(field.name().to_string(), format!("{value:?}")); + self.record_debug(field, &value); } } @@ -198,4 +207,4 @@ impl<'a> Visit for EventVisitor<'a> { fn record_str(&mut self, field: &tracing::field::Field, value: &str) { self.record_debug(field, &value); } -} +} \ No newline at end of file