July 25, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Programming the Windows Vista Event Log

  • August 4, 2006
  • By Nick Wienholt
  • Send Email »
  • More Articles »

The Windows Vista Event Log (codename: Crimson) is a significant enhancement to the current Windows Event Log in terms of its developer and administrator story. For a developer, the event log represents a unification of the multiple event and logging options in prior versions of Windows. For network administrators and IT professionals, it allows them to subscribe to events and provides a rich UI for managing events. The new event log is available only via native functions in the Windows SDK (though Microsoft's David Aiken offers an example of a managed wrapper on his blog).

Creating and Compiling the Manifest

Every application that publishes to the event log using the new API first needs to create a manifest (this is obviously not the case with legacy and managed client support, which will continue to use the simpler ReportEvent-style APIs). The manifest file is an XML-based representation of all the events that an application will raise. The message compiler (MC.exe) uses it to produce a header file (*.h) and get a resource file (*.rc) ready for inclusion in a C++ project. Hopefully, by the time Vista reaches RTM, a GUI tool will be available for manifest definition.

The full schema for the event log manifest is available in the MSDN library. The sample application in this article covers only a few of the simpler elements.

One of the most important elements in a manifest is the specification of which channels are available for writing to. The concept of a channel is new to the Vista Event Log. It provides separate output for events depending on audience and volume (see my previous article or the SDK documentation for more details on channel types). The sample application uses two channels: the operational channel and the debug channel. The following XML specifies that the application will use these two channels to raise events:

<channels>
   <importChannel chid="C1" name="Application"/>
      <channel chid="MyOpChannel"
               name="DotNetPerformance-TechalWriting-EventLogSample/
                     Operational"
               type="Operational"
               symbol="DOTNETPERFORMANCE"
               isolation="Application" enabled="true"/>
      <channel chid="MyDebugChannel"
               name="DotNetPerformance-TechalWriting-EventLogSample/
                     Debug"
               type="Debug"
               symbol="DOTNETPERFORMANCE"
               isolation="Application" enabled="true"/>

Once the channels have been defined, the next task is to define a template that will specify the basic shape of the events that will be raised. Like the old Event Log API, the Vista Event Log supports the use of %1-style symbols that are replaced with localized text. For the sample, the entire contents of the message text will be supplied at runtime:

<template tid="SimpleEvent" message="$(string.SimpleMessage)">
   <data name="Message" inType="win:UnicodeString"/>
   <UserData>
      <SimpleEvent xmlns="http://manifests.microsoft.com/win/2004/
                          08/windows/simpleevent">
         <ExceptionMessage>%1</ExceptionMessage>
      </SimpleEvent>
   </UserData>
</template>

The final piece that needs to be added to the manifest is the actual events that the application will raise. For simplicity, one event is defined for each channel and each uses the same template:

<event value="1"
       level="win:Informational"
       template="SimpleEvent"
       opcode="win:Info"
       channel="MyOpChannel"
       symbol=" DNP_OP_EVENT"
       message="$(string.SimpleMessage)"/>
<event value="2"
       level="win:Informational"
       template="SimpleEvent"
       opcode="win:Info"
       channel="MyDebugChannel"
       symbol=" DNP_DEBUG_EVENT"
       message="$(string.SimpleMessage)"/>

The full XML file is available with the code samples that accompany the article. The Message Compiler (mc.exe) now can be used to compile the manifest into header and resources files.

Raising Events

Actually raising events in code is considerably easier than defining the manifest file. As mentioned previously, the message compiler produces a header file that contains the definition of events and event publishers that need to be passed to the SDK functions. For the manifest shown above, the header file will contain the following definitions:

EXTERN_C __declspec(selectany) const
   GUID DOTNETPERFORMANCE_TECHNICALWRITING_PUBLISHER = {
      0x9cde86c9, 0xdfb9, 0x463f, {0xb2, 0xc5,0x71,0xee,0xc2,0x32,
                                   0xa6,0x9c}};
#define DOTNETPERFORMANCEOP 0x10
#define DOTNETPERFORMANCEDEBUG 0x0
EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR OP_EVENT = {
   0x1, 0x0, 0x10, 0x4, 0x0, 0x0, 0x8000000000000000};
#define DNP_OP_EVENT_value 0x1
EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR DEBUG_EVENT =
   {0x2, 0x0, 0x0, 0x4, 0x0, 0x0, 0x4000000000000000};
#define DNP_DEBUG_EVENT_value 0x2
#define MSG_SimpleMessage                0xB0000001L

To begin using these events in code, you use the generated header file containing the event definitions, windows.h (if the application is a console application), evntprov.h (which contains all the Event Tracing for Windows (ETW) definitions, which is the plumbing the Vista Event Log is based on), and winevt.h (which contains all the new Vista Event Log declarations). After bringing in the required headers, the event publisher can be registered with a call to EventRegister:

REGHANDLE hPub = NULL;
EventRegister(
   &DOTNETPERFORMANCE_TECHNICALWRITING_PUBLISHER,
      NULL, NULL, &hPub);

Actually raising an event is a simple exercise: creating an event descriptor and passing it to the EventWrite function:

EVENT_DATA_DESCRIPTOR opEventDesc;
PWSTR pwsOp = L"My Operational Event";
EventDataDescCreate(&opEventDesc, pwsOp,
                    ((ULONG)wcslen(pwsOp)+1)*sizeof(WCHAR));
EventWrite(hPub, &DNP_OP_EVENT, 1, &opEventDesc);

The EventDataDescCreate macro, which is used in the code sample above and defined in Evntprov.h, simply provides a shorter syntax for setting the members of an EVENT_DATA_DESCRIPTOR variable.

When events no longer need to be written to a particular publisher, the event publisher can simply be unregistered:

EventUnregister(hPub)

Deployment

Once the newly instrumented application is complete and has been deployed, the manifest file needs to be registered by using the following command line:

wevtutil install-manifest manifestFileName.xml

The wevtutil utility, which ships with Windows Vista, will parse the manifest and add the required settings to the Vista Event Log. If wevtutil is not run, events can still be successfully raised, but will not be visible in the event log.

If all the pieces of the puzzle have fallen into place, events will successfully end up in the Vista Event Log, as shown in Figure 1.



Click here for a larger image.

Figure 1. The End Result—A Successful Vista Log Message

Download the Code

To download the accompanying source code for the example, click here.

About the Author

Nick Wienholt is an independent Windows and .NET consultant based in Sydney, Australia. He is the author of Maximizing .NET Performance from Apress, and specializes in system-level software architecture and development with a particular focus on performance, security, interoperability, and debugging. Nick can be reached at NickW@dotnetperformance.com.






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel