male - 2010-02-23 - LogParser example for accessing the Windows event log
package require tcl 8.6 package require tcom namespace eval ::eventLog { variable types; variable columns; variable hexMap unset -nocomplain types columns hexMap; proc RecordsToList {records} { variable types; variable columns; set list [list]; try { if {![info exists types]} { # create the record-tcl type mapping # set types [list \ [$records REAL_TYPE] { set type double; set command getValue; set eval ""; } \ [$records INTEGER_TYPE] { set type integer; set command getValue; set eval ""; } \ [$records TIMESTAMP_TYPE] { set type timestamp; set command toNativeString; set eval [list apply [list {value} { return [clock scan $value -format {%Y-%m-%d %H:%M:%S}]; } [namespace current]]]; } \ [$records NULL_TYPE] { set type NULL; set command getValue; set eval ""; } \ [$records STRING_TYPE] - \ default { set type string; set command getValue; set eval ""; } \ ]; } if { ![info exists columns] || [$records getColumnCount] != [dict size $columns]} { # create the columns data set # set columns [dict create]; for {set i 0; set end [$records getColumnCount]} {$i < $end} {incr i} { set column [dict create name "" type "" command "" eval ""]; dict with column { set name [$records getColumnName $i]; switch [$records getColumnType $i] $types; switch $name { EvntType { set name EventTypeName; set eval [list apply [list {value} {return [string tolower $value];} [namespace current]]]; } EventCategoryName { set eval [list apply [list {value} { return [expr {[string first {The name for category } $value] == -1 ? $value : ""}]; } [namespace current]]]; } Message { set eval [list apply [list {value} {return [string trim $value];} [namespace current]]]; } Data { set eval [list apply [list {value} { variable hexMap; if {![info exists hexMap]} { for {set i 0} {$i < 256} {incr i} { lappend hexMap [format {%02X} $i] [format {%c} $i]; } } set value [string map $hexMap $value]; if {[string first "\x0" $value] >= 0} { if {[string first "\x0\x0" $value] == -1} { set temp [string trim [encoding convertfrom unicode $value]]; if {[string is print -strict $temp]} { set value $temp; } } } else { set value [string trim $value]; } return $value; } [namespace current]]]; } } }; dict set columns $i $column; } } # convert the records set into a tcl list of dictionaries # set list [list]; while {![$records atEnd]} { set row [dict create]; set record [$records getRecord]; for {set i 0; set end [dict size $columns]} {$i < $end} {incr i} { set column [dict get $columns $i]; dict with column { set value ""; if {![$record isNull $i]} { set value [$record $command $i]; if {$eval ne ""} { set value [{*}$eval $value]; } } dict set row $name $value; } } lappend list $row; unset record; $records moveNext; } } on error {result options} { error $result [dict get $options -errorinfo] [dict get $options -errorcode]; } finally { $records close; } return $list; } proc get {source types {undefined 0}} { try { set lgp [tcom::ref createobject MSUtil.LogQuery]; set evt [tcom::ref createobject MSUtil.LogQuery.EventLogInputFormat]; $evt resolveSIDs 1; $evt binaryFormat HEX; set records [$lgp Execute \ [format \ "SELECT SID, TO_LOWERCASE(REPLACE_STR(EventTypeName,' event','')) As EvntType, TimeGenerated, SourceName, EventCategoryName, EventCategory, EventID, Message, Data FROM %s WHERE EvntType IN ('%s') %s ORDER BY EvntType, TimeGenerated DESC" \ $source \ [join [string tolower $types] {';'}] \ [expr {$undefined ? "" : "AND NOT Message LIKE 'The description for Event ID %'"}] \ ] \ $evt \ ]; set list [RecordsToList $records]; } on error {result options} { error $result [dict get $options -errorinfo] [dict get $options -errorcode]; } finally { unset -nocomplain lgp evt records; } return $list; } namespace export -clear {[a-z]*}; namespace ensemble create; } set apps [eventLog get Application {warning error}]; puts ""; set system [eventLog get System {warning error}]; puts "";