Sunday, September 1, 2013

.net 4.5 EventSource & Windows Event Log - Microsoft's Nuget Package

EventSource allows to separate the event authoring request from writing the event. This is exactly how SLAB works. It provides mechanisms for writing the events data. We can change the tools / mechanism for writing events data later in the lifecycle of the application without making any changes to how those events are authored. It also allows to listen for those events in-proc and out-proc.

Can we consume these events by Windows Event Log. We now have a new Nuget package which helps us logging those events in the Windows Event Log. Looking at the documentation of the package, it mentions about channel support, this just means streaming of the events in Windows Event Log. The package allows new definition of EventSource with additional capabilities for logging into Windows Event Log. It also provides additional tools and build target to generate additional files in the output directory.

If you are using Package Manager console to install the package, make sure to use -pre switch with Install-Package command.

After installing the package, you should see Microsoft.Diagnostics.Tracing.EventSource assembly in project's references section. This assembly contains the new definition of EventSource class with added-on features. You would just need to update namespaces section in the file where EventSource is overridden. It has to be seamless integration otherwise.

In addition to the new assembly containing EventSource class, the package also includes the documentation to use the new type. Please notice _EventSourceUserGuide.docx above. If you look at the project definition then you can notice the additional reference for a new build targets file being added.

Build-Time Extra Validations in the New Type Provided by the Package
There are a few checks at build time to avoid run-time failures. Since the event keywords would be used for generating ETW manifest data, the inner type for keywords must be public. Hence this shouldn't work (It should have public visibility.)

Another check introduced is that the EventSource specialization type must be sealed. You can notice that the error comes from a tool copied by the nuget package. You can find eventRegister tools inside the nuget package directory.

My personal favorite is where it matches the EventId from Event attribtute to the WriteEvent method in the logging method. Here I mistakenly used a different Id and it is clearly helping me to correct this.

Event Channel
Let's now provide a complete definition of our EventSource. As a regular event source, it need to inherit from EventSource type and provide definition of the logging methods. By default the EventSource name is the same as the class name. It is recommended to use a specific name based on organization policies for registering event sources. Check with your system administrator about the naming conventions. You can notice that we have decorated the class with EventSourceAttribute and have specified a name there, it is for just that purpose.

We need to decorate the event source method with the appropriate description of Event Channel. Here we have used Admin channel. The other options available are Operational, Analytic and Debug. There is also a None option available.

Event channels are used to target the events for different audiences. They are described perfectly here. Admin and Operational channels are targeted for IT professionals and administrators, while Analytic and Debug channels are targeted for developers. It seems the Analytic and Debug channels are not enabled by default.

Building the project should generate these extra files in the output directory. We will be using these later to register events in the system.

The contents of the manifest file has the details about the events, channels, tasks and opcodes. Here is a sample manifest file for our project. You should see an extra event here. We would be adding that later in this post.

I know the XML is big and it can be difficult to find the details and scan for your information. First, you can read about the schema for this XML here. In order to make our life easier we can use ECMANGEN command line utility. Using the tool, We can also add more publishers or add further to the existing publisher. We need to run this by providing the manifest file as input as follows:

It should be show the manifest data for our event as follows:

We should be able to open the manifest dll file in Visual Studio. Here is the file generated for our project. You can notice the WEVT_TEMPLATE entry. Actually this entry is used for event log registration, which we are going to be discussing next.

The Dll just has manifest and no code. Opening the file in ILDASM, it look as follows:

Windows Event Log Registration
We must remember that just defining the type would provide a definition for EventSource which can be used by any EventListener. The nuget package would help us in writing to Windows Event Log but it would not register the event source on the system. We still need to register those events. wevtutil is used for registration of the event source. It is command line utility for Windows events. Addition of the additional build target should generate the required manifest and dll file for event registrations. We need to use im command [install-manifest] for event source registration. The command must run with administrative privileges. Here is the information about the utility from Microsoft: Enables you to retrieve information about event logs and publishers, install and uninstall event manifests, run queries, and export, archive, and clear logs. Just remember that you need to provide complete path with rf and mf switches.

After running the above command, you should be able to see the Event Source in Event Viewer tool. You can verify that the Admin channel is being used. You might need to restart Event Viewer tool to see the new event provider as refreshing the providers list didn't work for me either.

Unlike me, just make sure that you provide complete path with /rf and /mf switches. Otherwise you would continue to see this and wonder what in the world I don't understand here.

The same wevtutil is used to un-register the provider. We can use this with um command [uninstall-mainfest]. We just need to provide the name of the manifest file. For the above event provider, we can use the following:

Using Multiple Event Channels
You might be wondering about one thing. Here we are providing the event channel details on the event method. What if we need to use different channels for different events. Actually, this is totally supported. Let's add the following method to the event source. It is using Operational channel instead.

Now we can use the same wevutil im command to register the event. This would register the provider as follows:

You can notice that different icons are used based on the event channel type. Finally we should be able to see the logs in Event Viewer.

Where are the Logs generated?
On a Windows 7 machine, you should be able to see the logs generating in System32 folder. You can change this from the property window of the Event Channel in Event Viewer.

Using PerfView
In a previous post we discussed about using PerfView with EventSource. We can run the code with PerfView tool as a follows:

The event appears in the tool as follows:

Windows Event Log Service
Just make sure that Windows Event Log service is running before you log any events.

There is only one issue I noticed and couldn't work around it. It seems that the package has issues with logging an event without any parameters. The events can be seen in PerfView tool. Just add the following method to your EventSource, you wouldn't be able to see any data in EventLog when this is used.

To verify if this is an actual defect, I have logged it on connect. Let's see if we are missing something here.



עמית אפל said...

I see you have a Database keyword set but in the event output we see "Session3;Session2;Session1;Session0" and no Database, do you know why?

עמית אפל said...

I see you have a Database keyword set but in the event output we see "Session3;Session2;Session1;Session0" and no Database, do you know why?

Muhammad Shujaat Siddiqi said...

There is a bug with the implementation. It adds your keyword to the end.