Skip to main content

Module evt

Module evt 

Source
Expand description

Windows Event Log (evt) - Query and read events from Windows Event Logs.

This module provides ergonomic access to Windows Event Logs with support for:

  • Reading from event log channels (Security, System, Application, etc.)
  • Reading from .evtx log files
  • Flexible XPath-based or builder-based queries
  • Optional event message rendering with publisher metadata caching
  • Optional EventData extraction with field name interning
  • Custom parsing APIs for performance-critical scenarios
  • Detailed error reporting including corrupted event information

§Choosing the Right API

This module provides multiple ways to process events, each optimized for different use cases:

§Quick Start: Standard Event Processing

Use the built-in Event struct with builder options:

use windows_erg::evt::EventLog;

let log = EventLog::open("Security")?;
let mut query = log.query_stream("*[System[EventID=4624]]")?
    .with_event_data()   // Extract EventData key-value pairs (opt-in)
    .with_message();     // Format event messages via EvtFormatMessage (opt-in)

let mut batch = Vec::new();
while query.next_batch(&mut batch)? > 0 {
    for event in &batch {
        println!("Event {}: {}", event.id, event.formatted_message.as_deref().unwrap_or(""));
        if let Some(ref data) = event.data {
            for (key, value) in data {
                println!("  {}: {}", key, value);  // Common fields use Cow::Borrowed (zero-copy)
            }
        }
    }
}

When to use: Most applications. Provides structured Event objects with opt-in features.

§Explicit Corruption Handling

Use next_batch_with_results when you need to handle corrupted events explicitly:

use windows_erg::evt::EventLog;

let log = EventLog::open("System")?;
let mut query = log.query_stream("*")?;
let mut batch = Vec::new();

while query.next_batch_with_results(&mut batch)? > 0 {
    for result in &batch {
        match result {
            Ok(event) => println!("Event: {}", event.id),
            Err(corrupted) => {
                eprintln!("Corrupted event at record {}: {}",
                    corrupted.record_id.unwrap_or(0),
                    corrupted.reason
                );
            }
        }
    }
}

When to use: When parsing untrusted or potentially corrupted logs. Returns both Ok(Event) and Err(CorruptedEvent) in the same vector.

§Custom Types: Maximum Performance

Use next_batch_raw_with_filter when you need custom event types without allocating intermediate Event structs:

use windows_erg::evt::{EventLog, types::{extract_event_id, extract_provider}};

#[derive(Debug)]
struct LightweightEvent {
    id: u32,
    provider: String,
}

let log = EventLog::open("Application")?;
let mut query = log.query_stream("*")?;
let mut events = Vec::new();

query.next_batch_raw_with_filter(
    &mut events,
    |handle| {
        Ok(LightweightEvent {
            id: extract_event_id(handle)?,
            provider: extract_provider(handle)?,
        })
    },
    |event| event.id < 1000,  // Filter AFTER conversion (on your custom type)
)?;

When to use: High-throughput scenarios where you only need a subset of event fields. Avoids allocating full Event structs.

§Custom Types: Serde Deserialization

Use next_batch_deserialize (requires serde feature) for owned XML deserialization:

use windows_erg::evt::EventLog;
use serde::Deserialize;

#[derive(Deserialize)]
struct CustomEvent {
    #[serde(rename = "System")]
    system: SystemData,
}

#[derive(Deserialize)]
struct SystemData {
    #[serde(rename = "EventID")]
    event_id: u32,
    #[serde(rename = "Provider")]
    provider: ProviderData,
}

#[derive(Deserialize)]
struct ProviderData {
    #[serde(rename = "@Name")]
    name: String,
}

let log = EventLog::open("Security")?;
let mut query = log.query_stream("*")?;
let mut events: Vec<CustomEvent> = Vec::new();

query.next_batch_deserialize(&mut events)?;

When to use: When you need flexible custom event types with straightforward, owned Rust data structures.

§Performance Considerations

§Field Name Interning

Common EventData field names (e.g., “TargetUserName”, “ProcessId”, “CommandLine”) are automatically interned as Cow::Borrowed(&'static str) via a compile-time match statement. This reduces allocations by ~30% for typical Windows security logs.

§Publisher Metadata Caching

Event message formatting via with_message() caches publisher metadata handles with RwLock for concurrent read access. First message format per provider is ~5ms, subsequent formats are <0.1ms.

§Buffer Reuse

All next_batch_* methods clear and reuse the provided output vector. Preallocate with Vec::with_capacity(batch_size) to avoid repeated allocations.

§Examples

§Basic query

use windows_erg::evt::{EventLog, query::QueryBuilder};

let log = EventLog::open("Security")?;
let query = QueryBuilder::new().event_id(4688);
let result = log.query(&query)?;

for event in result.events {
    println!("Event ID: {}, Level: {}", event.id, event.level);
}

§Batch processing with buffer reuse

use windows_erg::evt::{EventLog, EventQuery};

let log = EventLog::open("System")?;
let mut query = log.query_stream("*")?;  // All events
let mut batch = Vec::with_capacity(64);

while query.next_batch(&mut batch)? > 0 {
    for event in &batch {
        println!("Event: {}", event.provider);
    }
}

§Query with filtering

use windows_erg::evt::{EventLog, types::EventLevel, query::QueryBuilder};

let log = EventLog::open("Application")?;
let query = QueryBuilder::new()
    .level(EventLevel::Error)
    .provider("MyApp");
let result = log.query(&query)?;

Modules§

query
Event query building and XPath query construction.
render
Event rendering with publisher metadata caching.
types
Event Log types with optimized string handling.

Structs§

EventLog
Handle to an opened event log or log file.
EventQuery
Query result stream for batch iteration with reusable buffers.