log parser

Log Parser

There are some amazing utilities available which never seem to get much recognition. One of these in my opinion is Microsoft’s Log Parser; you can download v2.2 from here and find an introduction here. It gives you the ability to use SQL-like queries on common log files. While it is presented as a command line program most of the work is done by the accompanying DLL so would it be possible to access it from Python.

Looking in the Log Parser help file it documents a COM interface which gives us our way in. Before you can use the COM interface you must register the DLL with the following command

regsvr32 LogParser.dll

All the examples are in VBScript unsurprisingly but we can use them with a bit of trial and error. The first item of interest is the name of the COM object, MSUtil.LogQuery. Now we know what to pass to the dispatch method. If you have used a library that confirms to the Python database API think of this as the connect method.

Next comes the two ways of working, batch or interactive. Interactive seems the most natural place to start so we need to use the Execute method. This takes the SQL-like query and optionally the input format. We’ll leave it to guess the input format for this test.

The execute method returns a LogRecordSet. Here is where the VBScript example helps. This is an interface to a set a records (obviously) and allows us to find out the columns and get the records. At a stretch you can think of it as cursor. Putting all this together we can query the System event log to find out all the times the computer was switched on (Event ID 12) with the following code

import win32com.client
lp = win32com.client.Dispatch("MSUtil.LogQuery")
sql = "SELECT * FROM System WHERE EventID = 12"
lrs = lp.Execute(sql)
for col in range(rs.getColumnCount()):
    print col, rs.getColumnName(col)

Now we have the result of query in the record set we need to get at the values. We can get each record sequentially using the record set interface. This returns a LogRecord object which basically just allows you to get each value by specifying the index you want. The example above gives us two columns we could use, I’ll use the TimeGenerated one. So lets display them

# continuing on from above
while not lrs.atEnd():
    lr = lrs.getRecord()
    print "Computer started at",lr.getValue(2)

With a working COM interface, I wrote the following program to allow the SQL statements to be run from the command line in an interactive environment. The output formatting is poor but it makes a good example program.