Using the event_logs module

The examples here all refer to the event_logs module.

Log an event against an event source

Log an information event against a WinSys event source, creating it if does not already exist. Once the event is written, remove the event source.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from winsys import event_logs

try:
  source = event_logs.event_source ("WinSys")
except event_logs.x_not_found:
  source = event_logs.EventSource.create ("WinSys")

try:
  source.log_event (type="information", message="Testing")
finally:
  source.delete ()

Discussion

Events are always logged against a specific event source. We can create a simple event source which will render single-string messages. For the purposes of demonstration, we attempt to pick up the event source if it already exists and to create it if it does not. We use the class-level convenience function to log the event against the source, which simply hands off to the module-level function of the same name.

An event source can be deleted at any time: its records simply become “orphans” in that the system will no longer be able to format their messages since it won’t know the location of the DLL which contains the corresponding strings.

Note

The logging library in Python’s stdlib already has an NTEventLog handler, so if all you want to do is to log events in a standard manner, then it’s probably best to use that.

List the 10 most recent records in each event log

Go through each event log on the system and list the 10 most recent events.

1
2
3
4
5
6
7
8
9
from winsys import event_logs

for log in event_logs.event_logs ():
  print log
  for n_event, event in enumerate (reversed (log)):
    if n_event == 10: break
    print event.time_generated, event

  print

Discussion

By default, iterating over an event log starts oldest first. To pick up the most recent records, we reverse the iterator. This makes use of the EventLog.__reversed__() magic method which starts a reverse iterator. Without that, the implementation would fall back to a __getitem__-based sequence solution, asking for [-1] and then [-2] and so on. Since our EventLog.__getitem__() implementation actually iterates anyway, this would be a less-than-optimal solution.

The standard __str__ for an event log record shows the record number, the source and the event type. We add here the record’s timestamp.

Write to CSV selected events from a remote event log

Go through the a remote System event log and write to CSV the record number, id and message for records matching a particular event source and type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import os
import csv
from winsys import event_logs, dialogs

def remote_events (computer, event_source, event_type_id):
  for event in event_logs.event_log (r"\\%s\system" % computer):
    if event.source_name.upper () == event_source and event.event_type == event_type_id:
      yield event
  
computer, event_source, (event_type_name, event_type_id) = dialogs.dialog (
  "Computer", 
  ("Computer Name", "."),
  ("Event Source", "DHCP"),
  ("Event Type", event_logs.EVENTLOG_TYPE.items ())
)

csv.writer (open ("dhcp.csv", "wb")).writerows (
  (event.record_number, event.time_generated, event.event_id, event.message) for
    event in remote_events (computer, event_source.upper (), event_type_id)
)

os.startfile ("dhcp.csv")

Discussion

We use the winsys dialogs.dialog module convenience function to request the name of the remote computer and the source and event type from the user. It would be possible to pick out the list of event sources for a computer (using the event_sources() function), but there’s no mechanism within the dialogs module for updating one field on the basis of another, so we could only pre-populate with the valid list for one particular computer.

The module-level convenience function event_log() returns an instance of an EventLog matching the computer and event log name in the UNC-style moniker. The standard iterator goes from the oldest first forwards. If we wanted to see the records in reverse chronological order, we’d use the reversed builtin to invoke the class’s EventLog.__reversed__() method.