Welcome to MSDN Blogs Sign in | Join | Help
How to consume ETW events from C#

In my previous post I explained how to collect ETW events from URL Rewrite (or any other IIS provider) and then display those structured events in the Event Viewer. Now I want to show you how to collect ETW events using C#.

The .NET Framework 3.5 provides a new namespace System.Diagnostics.Eventing.Reader where you can find useful classes for publishing ETW events, but doesn’t provide a mechanism for consuming, so I had to write a class EventTraceWatcher for simplify things.

I want to use this class for tracking, in real time, all the URL Rewrite Events.

Setup Event Trace Session

The first thing to do is to setup the session, open “Reliability and Performance Monitor”, go to Event Trace Sessions and add a new Data Collector Set named “Rewrite”; my previous post has more detailed steps, once you create the collector set, go to its properties and add the provider “IIS: WWW Server” and the Keyword 0x400 (Rewrite) and set the Level to 5. Here is how it should be:

Trace Providers

Use stream mode “Real Time”

By default the Data Collector Set will write the collected events in the file system. Change it from File to “Real Time”. Your .NET Application will be listening those real time events. Open the data collector properties and in the Trace Session tab change this setting.

Trace Session

Make sure to start the Rewrite Collector once you are finish with this settings.

EventTraceWatcher class

The EventTraceWatcher class is very trivial to use, you need to provide the name of the Data Collector Set to it’s constructor (“Rewrite” in our example), hook the event “EventArrived” in your code and then just set the property Enabled to true to start the asynchronous processing of the ETW Events.

using System;
using Microsoft.Iis.Samples.Eventing;

class Program {
   
static void Main() {
       
try {
           
new Program().Run();
       
}
       
catch (Exception ex) {
           
Console.Error.WriteLine(ex);
       
}
   
}

   
private void Run() {
       
Guid RewriteProviderId = new Guid("0469abfa-1bb2-466a-b645-e3e15a02f38b");

       
using (EventTraceWatcher watcher = new EventTraceWatcher("Rewrite")) {

           
watcher.EventArrived += delegate(object sender, EventArrivedEventArgs e) {

               
if (e.EventException != null) {
                   
// Handle the exception
                    Console.Error.WriteLine(e.EventException);
                   
Environment.Exit(-1);
               
}

               
// Process only URL Rewrite events
                if (e.ProviderId != RewriteProviderId) {
                   
return;
               
}

               
// Dump the event name (e.g. URL_REWRITE_START, ABORT_REQUEST_ACTION, etc).
                Console.WriteLine("Event Name: " + e.EventName);

               
// Dump properties (e.g. RewriteURL, Pattern, etc).
                foreach (var p in e.Properties) {
                   
Console.WriteLine("\t" + p.Key + " -- " + p.Value);
               
}
               
Console.WriteLine();
           
};

           
// Start listening
            watcher.Enabled = true;
            // Listen events until user press <Enter>
           
Console.WriteLine("Press <Enter> to exit");
           
Console.ReadLine();
       
}
   
}
}

With this code you can write tools to help you to filter in real time information from IIS. Download the EventTraceWatcher class from:

http://code.msdn.microsoft.com/EventTraceWatcher

Posted: Monday, February 02, 2009 5:30 PM by Daniel Vasquez Lopez
Filed under: , , ,

Comments

logus2k said:

Daniel,

Thank you for this article.

I'm trying to use EventProviderTraceListener to publish to ETW infrastructure and then read those events from managed code. I still couldn't run your code to test if could use it to a general purpose publisher (instead of only IIS), it always gives me an "access denied" message when I try to run it.

I'm also having some difficulty understanding what can/should I do programmatically to receive the events from an ETW session )and how can I create one from code).

I understand there is no current official support to reading ETW events from managed code...? Is there something else I can use?

Thanks in advance for your help,

António Cruz

# February 8, 2009 2:47 PM

Daniel Vasquez Lopez said:

I updated the post to add another example that includes support for custom events.

This is only for Vista/Windows 2008. Make sure to the consumer application with Administrative privileges.

1. Compile everything.

2. Run Producer.exe (it uses EventProviderTraceListener)

3. From command line (as Admin), run 'logman start MySession -p {13D5F7EF-9404-47ea-AF13-85484F09F2A7} -ets'

4. Open 'Reliability and Performance Monitor' and change the stream mode, in MySession's properties, from File to Real Time.

5. Run Consume.exe

6. Type something in the Producer.exe and press <Enter>

Expected: Consume[r].exe should echo what you typed in Producer.exe

When you are done, run 'logman stop MySession -ets' to stop the custom ETW session.

The events produced by EventProviderTraceListener doesn't have any schema, so what I did was to take the UserData 'as is' and convert it to string (be aware that this is just a guess, the data could not be a string).

Hope this helps

# February 14, 2009 3:28 PM

Adam Machanic said:

Thanks so much for sharing this library!  

I'm using it to consume ETW output from SQL Server 2008 Extended Events, and have hit a couple of issues:

A) The event names do not appear to be populating.  If I dump the ETL file they are there, so I assume it would be in the real time output as well?

B) Any chance it can be extended to be a bit more flexible with regard to non-top level properties?  For example the trace I'm working with right now sends back 11 top level properties and two non-top level properties (I'm not sure of the right term for "non-top level") -- these are just Unicode strings, so no difficulties with maps, etc.  I tried to modify the code to consume them and wound up with all sorts of garbage data; I suspect the pointers are not correct...

I'm happy to send you an example of how to set this up if you're interested in seeing what I'm talking about.  Drop me a line at amachanic [at] gmail [dot] com ... it would be great to get this thing fully working so I hope so :-)

Either way, thanks again!

# February 16, 2009 9:08 PM

walkerc said:

Hello Daniel,

I am using the EventTraceWater class to consume KernelTrace Events.

I backed the class into .Net 2.0 by replacing ReaderWriterLockSlim with ReaderWriterLock.

The class functions flawlessly on Vista64, on Windows7 (32 bit, build 7000) it ... , on XP 32 bit,

int error = NativeMethods.ProcessTrace(array, 1, IntPtr.Zero, IntPtr.Zero); in ProcessTraceInBackground fails.

I have not been able to find a documented reason for this failure since ProcessTrace is supported on XP.

http://msdn.microsoft.com/en-us/library/aa364093(VS.85).aspx

Any ideas?

I was also considering unwrapping ProcessTraceInBackground out of a delegate and using the entire class from a background thread in order to simplify the code and perhaps reduce failure modes that way. Your thoughts?

Again thanks for the class, hopefully this functionality will make it to the framework sooner rather than later.

# February 26, 2009 5:26 PM

walkerc said:

Sorry, I forgot I left a statement hanging:

on Windows7 (32 bit, build 7000) it ...

I was waiting for the error to occur again to be more specific, the class runs for a while and then throws a NullReference exception, just FYI. I don't have a dev environment on Win 7 yet to debug.

# February 26, 2009 5:29 PM

walkerc said:

One final question, really I promise.

I noticed that

_logFile.EventRecordCallback = EventRecordCallback;

in StartTracing, was not using a delegate. Would using a delegate here provide some benefit?

I apologize if this seems ignorant, even though I have been programming for 30 years, my C# is pretty shabby.

# February 26, 2009 5:44 PM

walkerc said:

OK, new years resolution, become more familar with code before commenting on it...

1) _logFile.EventRecordCallback = EventRecordCallback; is using a delegate.

2) int error = NativeMethods.ProcessTrace(array, 1, IntPtr.Zero, IntPtr.Zero); in ProcessTraceInBackground  

blocks.

It does not matter if EventTraceWatcher.enabled (and in turn, StartTracing and NativeMethods.ProcessTrace is called from a separate external thread or as originally implemented.

3) ProcessTrace still fails in XP and reason is still a mystery to me.

# February 28, 2009 8:00 PM

dixi said:

An extraordinary and very useful piece of work. Congrats Daniel. I noticed that some people are having troubles with the class in Win7. Actually, I have been troubles with ETW in Win7. It happens that the same .NET 3.5 code I developed works seamlessly in WS2008 but not in Win7. The Beta I gues? Anyway, still trying...

# March 6, 2009 12:30 PM

Daniel Vasquez Lopez said:

Thank you dixi for your comments, I haven't test it in Windows 7, but I will give it a try as soon as I can.

WalkerC, unfortunately this code won't work for XP, I'm using the field ProcessTraceMode and callback EventRecordCallback http://msdn.microsoft.com/en-us/library/aa363780(VS.85).aspx that are not available prior Windows Vista.

Thank you.

# March 14, 2009 1:26 AM

Eok's Blog said:

Event Tracing for Windows (ETW) is wonderful mechanism to monitor, log and trouble shoot of your application

# May 15, 2009 12:00 PM

jamlou2 said:

really great tool, much appreciated.

i wanted to go further than that, what should be done so that this library would also consume WPP messages sent through DoTraceMessage()

considering the event session is already created, and there is an application running and sending WPP messages, what should be changed in the implementation so that it would successfully consume those messages?

# February 9, 2010 5:27 PM
Anonymous comments are disabled
Page view tracker