Windows NT Eventlog

Python's win32 access for the Eventlog


If you need to scan the eventlog of many servers or do specific filtering based off of the event log, python's win32evtlog win32evtlogutil libraries give you an means to do it efficiently.

The library of primary importance is win32evtlog. With it you can connect to a server's eventlog with the call.

Example

Here is the basic call:

logtype='System'

hand=win32evtlog.OpenEventLog(server,logtype)

This returns a handle from which you can make calls such as one that will give you the total number of events or another examine the details for each event. The logtype variable is set to the type of log you want to look at. The default ones are: Application, Security, and System.

After you have the handle you can get ask for things such as the number of records, or the specific event records:

total=win32evtlog.GetNumberOfEventLogRecords(hand)

flags = win32evtlog.EVENTLOG_BACKWARDS_READ|win32evtlog.EVENTLOG_SEQUENTIAL_READ

events=win32evtlog.ReadEventLog(hand,flags,0)

ReadEventLog returns a number of event objects which may not be all of them. You need to continously check in a loop until there are no more events returned by ReadEventLog. You may notice that ReadEventLog has a flags argument. The flags (which are convinently available with the win32evtlog library) specify how to read the event log.


Here is a simple loop getting the data from the events that ReadEventLog returned:

for ev_obj in events:

	the_time=ev_obj.TimeGenerated.Format() #'12/23/99 15:54:09'

	evt_id=str(winerror.HRESULT_CODE(ev_obj.EventID))

	computer=str(ev_obj.ComputerName)

	cat=ev_obj.EventCategory

	seconds=date2sec(the_time)

	record=ev_obj.RecordNumber

	msg=str(win32evtlogutil.SafeFormatMessage(ev_obj, logtype))

	source=str(ev_obj.SourceName)

We use the library win32evtlogutil to get the actual text body for the event. To get a easily readable date for the event, you need to specify the 'Format' method for the TimeGenerated part of the event object.


The win32evtlogutil comes in handy to give us the actual text body of the eventlog message. If you want to do any sorting based of off time, here is a handy function that converts the eventlog's time format into seconds using's python's time and regexp library:

def date2sec(self,evt_date):

	'''

	converts '12/23/99 15:54:09' to seconds

	print '333333',evt_date

	'''

	regexp=re.compile('(.*)\\s(.*)')

	reg_result=regexp.search(evt_date)

	date=reg_result.group(1)

	the_time=reg_result.group(2)

	(mon,day,yr)=map(lambda x: string.atoi(x),string.split(date,'/'))

	(hr,min,sec)=map(lambda x: string.atoi(x),string.split(the_time,':'))

	tup=[yr,mon,day,hr,min,sec,0,0,0]

	sec=time.mktime(tup)

	return sec

If you want to get the current localtime in seconds, you can make the call: begin_sec=time.time(). To convert that to a date use: begin_time=str(time.strftime('%H:%M:%S ',time.localtime( begin_sec )))


Finally here is all the code that puts together an application which looks for all events for a server since a certain time.


Find events:

import win32evtlog

import win32evtlogutil

import win32security

import win32con

import winerror

import time

import re

import string

import sys

import traceback



def date2sec(evt_date):

	'''

	This function converts dates with format

	'12/23/99 15:54:09' to seconds since 1970.

	'''

	regexp=re.compile('(.*)\\s(.*)') #store result in site

	reg_result=regexp.search(evt_date)

	date=reg_result.group(1)

	the_time=reg_result.group(2)

	(mon,day,yr)=map(lambda x: string.atoi(x),string.split(date,'/'))

	(hr,min,sec)=map(lambda x: string.atoi(x),string.split(the_time,':'))

	tup=[yr,mon,day,hr,min,sec,0,0,0]



	sec=time.mktime(tup)



	return sec



####Main program

#initialize variables

flags = win32evtlog.EVENTLOG_BACKWARDS_READ|\\

		win32evtlog.EVENTLOG_SEQUENTIAL_READ



#This dict converts the event type into a human readable form

evt_dict={win32con.EVENTLOG_AUDIT_FAILURE:'EVENTLOG_AUDIT_FAILURE',\\

		  win32con.EVENTLOG_AUDIT_SUCCESS:'EVENTLOG_AUDIT_SUCCESS',\\

		  win32con.EVENTLOG_INFORMATION_TYPE:'EVENTLOG_INFORMATION_TYPE',\\

		  win32con.EVENTLOG_WARNING_TYPE:'EVENTLOG_WARNING_TYPE',\\

		  win32con.EVENTLOG_ERROR_TYPE:'EVENTLOG_ERROR_TYPE'}

computer='bedrock'

logtype='System'

begin_sec=time.time()

begin_time=time.strftime('%H:%M:%S  ',time.localtime(begin_sec))



#open event log

hand=win32evtlog.OpenEventLog(computer,logtype)

print logtype,' events found in the last 8 hours since:',begin_time



try:

  events=1

  while events:

    events=win32evtlog.ReadEventLog(hand,flags,0)

      for ev_obj in events:

	#check if the event is recent enough

	#only want data from last 8hrs

	the_time=ev_obj.TimeGenerated.Format()

	seconds=date2sec(the_time)

	if seconds < begin_sec-28800: break



	#data is recent enough, so print it out

	computer=str(ev_obj.ComputerName)

	cat=str(ev_obj.EventCategory)

	src=str(ev_obj.SourceName)

	record=str(ev_obj.RecordNumber)

	evt_id=str(winerror.HRESULT_CODE(ev_obj.EventID))

	evt_type=str(evt_dict[ev_obj.EventType])

	msg = str(win32evtlogutil.SafeFormatMessage(ev_obj, logtype))

	print string.join((the_time,computer,src,cat,record,evt_id,evt_type,msg[0:15]),':')



    if seconds < begin_sec-28800: break #get out of while loop as well

  win32evtlog.CloseEventLog(hand)

except:

    print traceback.print_exc(sys.exc_info())





	Some useful additions to this would be to make it

multi-threaded and deploy it as a web application, to look at many servers.

Have a great time with programming with python!

John Nielsen   nielsenjf@my-deja.com