use std::collections::HashMap;
use windows_erg::etw::{EventTrace, SystemProvider};
fn main() -> windows_erg::Result<()> {
println!("Starting ETW Multi-Provider Monitor...");
println!("Monitoring: Process, Registry, FileIo, ImageLoad");
println!("Press Ctrl+C to stop\n");
let mut trace = EventTrace::builder("MultiProviderMonitor")
.system_provider(SystemProvider::Process)
.system_provider(SystemProvider::Registry)
.system_provider(SystemProvider::FileIo)
.system_provider(SystemProvider::ImageLoad)
.buffer_size(256) .min_buffers(10)
.max_buffers(50)
.flush_interval(1)
.channel_capacity(20000) .start()?;
println!("✓ ETW session started: {}", trace.name());
println!("✓ Monitoring 4 kernel providers\n");
let mut stats = EventStats::new();
let mut events = Vec::with_capacity(200);
loop {
match trace.next_batch(&mut events) {
Ok(count) if count > 0 => {
for event in &events[..count] {
stats.record(event);
if stats.total.is_multiple_of(100) {
print_event_summary(event, stats.total);
}
}
if stats.total.is_multiple_of(1000) {
stats.print_summary();
}
}
Ok(_) => {
std::thread::sleep(std::time::Duration::from_millis(100));
}
Err(e) => {
eprintln!("Error fetching events: {}", e);
break;
}
}
}
println!("\n=== Final Statistics ===");
stats.print_summary();
println!("\nTotal events processed: {}", trace.events_processed());
Ok(())
}
struct EventStats {
total: usize,
by_provider: HashMap<&'static str, usize>,
by_level: HashMap<u8, usize>,
}
impl EventStats {
fn new() -> Self {
EventStats {
total: 0,
by_provider: HashMap::new(),
by_level: HashMap::new(),
}
}
fn record(&mut self, event: &windows_erg::etw::TraceEvent) {
self.total += 1;
let provider = match event.id {
1..=9 => "Process",
10..=19 => "Registry",
20..=29 => "FileIo",
30..=39 => "ImageLoad",
_ => "Other",
};
*self.by_provider.entry(provider).or_insert(0) += 1;
*self.by_level.entry(event.level).or_insert(0) += 1;
}
fn print_summary(&self) {
println!("\n--- Event Statistics (Total: {}) ---", self.total);
println!("By Provider:");
let mut providers: Vec<_> = self.by_provider.iter().collect();
providers.sort_by_key(|(_, count)| std::cmp::Reverse(*count));
for (provider, count) in providers {
let percentage = (*count as f64 / self.total as f64) * 100.0;
println!(" {:<12} {:>6} ({:>5.1}%)", provider, count, percentage);
}
println!("By Level:");
let mut levels: Vec<_> = self.by_level.iter().collect();
levels.sort_by_key(|(level, _)| **level);
for (level, count) in levels {
let level_name = match level {
1 => "Critical",
2 => "Error",
3 => "Warning",
4 => "Info",
5 => "Verbose",
_ => "Unknown",
};
let percentage = (*count as f64 / self.total as f64) * 100.0;
println!(" {:<10} {:>6} ({:>5.1}%)", level_name, count, percentage);
}
}
}
fn print_event_summary(event: &windows_erg::etw::TraceEvent, count: usize) {
println!(
"[{}] Event ID: {}, Level: {}, PID: {}, Data: {} bytes",
count,
event.id,
event.level,
event.process_id,
event.data.len()
);
}