Skip to content

Ricemug/wineventlog

Repository files navigation

Windows Event Log API for Go

English | 繁體中文 | 简体中文

Go Reference License: MIT Ko-fi

A comprehensive, production-ready Go library for working with Windows Event Logs. This library provides a clean, idiomatic Go interface to the Windows Event Log API (wevtapi.dll).

Features

  • Subscribe to real-time events - Monitor event logs as events occur
  • Query historical events - Search and filter past events with XPath queries
  • Channel management - List, clear, and export event log channels
  • Bookmark support - Resume reading from specific positions
  • Query builder - Construct complex XPath queries easily
  • Full event details - Access all event properties (XML, structured data)
  • Sysmon support - Comprehensive support for Sysmon events with specialized parsing
  • Cross-platform stubs - Compile on non-Windows platforms (returns errors)
  • Production-ready - Proper error handling and resource cleanup

Installation

go get github.com/Ricemug/wineventlog

Requirements

  • Windows operating system
  • Go 1.21 or later
  • Administrator privileges may be required for certain operations (e.g., Security log)

Quick Start

Read Recent Events

package main

import (
    "fmt"
    "log"

    "github.com/Ricemug/wineventlog"
)

func main() {
    // Create a reader for the System channel
    reader, err := wineventlog.NewChannelReader("System")
    if err != nil {
        log.Fatal(err)
    }
    defer reader.Close()
    
    // Read last 10 events
    events, err := reader.ReadBatch(10)
    if err != nil {
        log.Fatal(err)
    }
    
    for _, event := range events {
        fmt.Printf("EventID: %d | Time: %s | Provider: %s\n",
            event.EventID,
            event.TimeCreated,
            event.ProviderName,
        )
        event.Close()
    }
}

Subscribe to Real-Time Events

package main

import (
    "fmt"
    "log"
    "os"
    "os/signal"

    "github.com/Ricemug/wineventlog"
)

func main() {
    // Create subscriber
    subscriber := wineventlog.NewSubscriber("System", 
        func(event *wineventlog.Event) error {
            fmt.Printf("New event: %d from %s\n", 
                event.EventID, 
                event.ProviderName,
            )
            return nil
        },
    )
    
    if err := subscriber.Start(); err != nil {
        log.Fatal(err)
    }
    defer subscriber.Stop()
    
    // Wait for Ctrl+C
    sigChan := make(chan os.Signal, 1)
    signal.Notify(sigChan, os.Interrupt)
    <-sigChan
}

Query with Filters

// Build a query
query := wineventlog.NewQueryBuilder().
    EventID(1074).              // Specific event ID
    Level(2).                   // Error level
    Provider("Microsoft-Windows-System").
    Build()

// Create reader with query
reader, err := wineventlog.NewChannelReader("System",
    wineventlog.WithQueryString(query),
)
if err != nil {
    log.Fatal(err)
}
defer reader.Close()

// Read matching events
events, err := reader.ReadBatch(100)
// ... process events

API Documentation

Core Types

Event

Represents a Windows event log event.

type Event struct {
    ProviderName  string    // Event provider
    EventID       uint16    // Event ID
    Level         uint8     // Event level (1-5)
    TimeCreated   time.Time // Event timestamp
    EventRecordID uint64    // Unique record ID
    Channel       string    // Channel name
    Computer      string    // Computer name
    XML           string    // Full event XML
    // ... more fields
}

Methods:

  • Close() error - Close the event handle
  • GetEventData() (map[string]string, error) - Extract event data as key-value pairs
  • String() string - Human-readable representation

Subscriber

Subscribe to real-time events from a channel.

subscriber := wineventlog.NewSubscriber(channel, callback, opts...)
err := subscriber.Start()
// ... events are delivered to callback
subscriber.Stop()

Options:

  • WithQuery(query string) - Filter events with XPath query

Query

Query historical events from a channel.

query, err := wineventlog.NewQuery(channel, opts...)
event, err := query.Next(timeout)
events, err := query.GetEvents(maxEvents, timeout)
query.Close()

Methods:

  • Next(timeout uint32) (*Event, error) - Get next event
  • GetEvents(maxEvents int, timeout uint32) ([]*Event, error) - Get batch of events
  • Seek(position int64, flags uint32) error - Seek to position
  • SeekToFirst() error - Seek to first event
  • SeekToLast() error - Seek to last event
  • Close() error - Close query handle

QueryBuilder

Build XPath queries easily.

query := wineventlog.NewQueryBuilder().
    EventID(1000).                    // Single event ID
    EventIDRange(1000, 2000).        // Event ID range
    Level(2).                         // Error level
    Provider("ProviderName").         // Provider filter
    TimeRange(startTime, endTime).   // Time range
    Build()

ChannelReader

Simplified interface for reading events.

reader, err := wineventlog.NewChannelReader(channel, opts...)
event, err := reader.Read()
events, err := reader.ReadBatch(maxEvents)
reader.Close()

Channel Operations

List Channels

channels, err := wineventlog.ListChannels()
for _, channel := range channels {
    fmt.Println(channel)
}

Clear Channel

// Clear with backup
err := wineventlog.ClearChannel("System", "backup.evtx")

// Clear without backup
err := wineventlog.ClearChannel("System")

Export Channel

// Export all events
err := wineventlog.ExportChannel("System", "export.evtx")

// Export with query
query := "*[System[Level=2]]" // Errors only
err := wineventlog.ExportChannel("System", "errors.evtx", query)

Read All Events

// Read all events from a channel
events, err := wineventlog.ReadAllEvents("Application")

// Read with query
events, err := wineventlog.ReadAllEvents("System", 
    "*[System[EventID=1074]]")

Count Events

// Count all events
count, err := wineventlog.CountEvents("System")

// Count with query
count, err := wineventlog.CountEvents("System", 
    "*[System[Level=2]]")

Bookmarks

Bookmarks allow you to save your position in an event log and resume later.

// Create bookmark
bookmark, err := wineventlog.NewBookmark()
defer bookmark.Close()

// Update bookmark with event
err = bookmark.Update(event)

// Get bookmark XML (save this)
xml, err := bookmark.GetXML()

// Later, restore bookmark
bookmark, err = wineventlog.NewBookmark(xml)

Event Levels

  • 1 - Critical
  • 2 - Error
  • 3 - Warning
  • 4 - Information
  • 5 - Verbose

Common Channels

  • System - System events
  • Application - Application events
  • Security - Security audit events (requires admin)
  • Setup - Setup events
  • Microsoft-Windows-PowerShell/Operational - PowerShell events
  • Microsoft-Windows-Sysmon/Operational - Sysmon events (if installed)
  • Many more... (use ListChannels() to discover)

Sysmon Support

This library includes comprehensive support for Microsoft Sysmon events. See SYSMON.md for detailed documentation.

Quick Sysmon Examples

Monitor process creation:

if !wineventlog.IsSysmonInstalled() {
    log.Fatal("Sysmon is not installed")
}

query := wineventlog.NewSysmonQuery().ProcessCreate().Build()
subscriber := wineventlog.NewSysmonSubscriber(
    func(event *wineventlog.SysmonEvent) error {
        fmt.Printf("New Process: %s (PID: %d)\n", 
            event.Image, event.ProcessId)
        fmt.Printf("  Command: %s\n", event.CommandLine)
        fmt.Printf("  Parent: %s\n", event.ParentImage)
        return nil
    },
    wineventlog.WithQuery(query),
)
subscriber.Start()
defer subscriber.Stop()

Monitor network connections:

query := wineventlog.NewSysmonQuery().NetworkConnect().Build()
subscriber := wineventlog.NewSysmonSubscriber(
    func(event *wineventlog.SysmonEvent) error {
        fmt.Printf("Connection: %s:%d → %s:%d\n",
            event.SourceIp, event.SourcePort,
            event.DestinationIp, event.DestinationPort)
        return nil
    },
    wineventlog.WithQuery(query),
)
subscriber.Start()
defer subscriber.Stop()

See SYSMON.md for comprehensive Sysmon documentation and examples.

XPath Query Examples

// All events
"*"

// Specific event ID
"*[System[EventID=1074]]"

// Event ID range
"*[System[EventID>=1000 and EventID<=2000]]"

// Error level only
"*[System[Level=2]]"

// Multiple conditions
"*[System[EventID=1074 and Level=4]]"

// Provider filter
"*[System[Provider[@Name='Microsoft-Windows-Kernel-Power']]]"

// Time range
"*[System[TimeCreated[@SystemTime>='2024-01-01T00:00:00' and @SystemTime<='2024-12-31T23:59:59']]]"

// Complex query
"*[System[(EventID=1074 or EventID=6006) and Level<=3]]"

Error Handling

All functions return errors following Go conventions:

reader, err := wineventlog.NewChannelReader("NonExistent")
if err != nil {
    // Handle error (channel doesn't exist, permission denied, etc.)
    log.Printf("Failed to create reader: %v", err)
    return
}
defer reader.Close()

Common errors:

  • ERROR_ACCESS_DENIED - Insufficient permissions (try running as admin)
  • ERROR_EVT_CHANNEL_NOT_FOUND - Channel doesn't exist
  • ERROR_NO_MORE_ITEMS - No more events to read
  • ERROR_INSUFFICIENT_BUFFER - Internal buffer issue (usually handled automatically)

Resource Management

Always close resources when done:

// Events
event, err := reader.Read()
// ... use event
event.Close() // Important!

// Queries and readers
query, err := wineventlog.NewQuery(...)
defer query.Close()

// Subscribers
subscriber := wineventlog.NewSubscriber(...)
defer subscriber.Stop()

// Bookmarks
bookmark, err := wineventlog.NewBookmark()
defer bookmark.Close()

Performance Tips

  1. Batch reads - Use ReadBatch() instead of multiple Read() calls
  2. Close events - Always close events to free memory
  3. Use queries - Filter at the API level rather than in Go
  4. Seek efficiently - Use SeekToLast() for recent events
  5. Limit results - Don't read entire logs at once for large logs

Examples

See the examples directory for complete working examples:

  1. List all channels
  2. Read events from a channel
  3. Subscribe to real-time events
  4. Query with filters
  5. Export events to file
  6. Use bookmarks
  7. Count events
  8. Subscribe with custom query

Cross-Platform Support

The library compiles on non-Windows platforms but returns errNotSupported errors. This allows you to write cross-platform code:

events, err := wineventlog.ReadAllEvents("System")
if err != nil {
    if err.Error() == "wineventlog: not supported on this platform" {
        // Handle non-Windows platform
        return
    }
    // Handle actual error
}

Testing

# Run tests on Windows
go test ./...

# Run with verbose output
go test -v ./...

Note: Some tests require administrator privileges.

License

MIT License - see LICENSE file for details

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests if applicable
  5. Submit a pull request

Support

For issues, questions, or contributions:

Donate

If you find this project helpful, consider supporting its development:

ko-fi

References

Changelog

v1.0.0 (Initial Release)

  • Full Windows Event Log API support
  • Subscribe to real-time events
  • Query historical events
  • Channel management
  • Bookmark support
  • Query builder
  • Cross-platform stubs
  • Comprehensive examples and documentation

About

Production-ready Windows Event Log API for Go with comprehensive Sysmon support

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages