ETW in C#: Controlling which events get logged in an System.Diagnostics.Tracing.EventSource

In my EventSource demo blog entry we defined an EventSource and turned on the logging with the command

PerfView /OnlyProviders=*MinimalEventSource run eventSourceDemo.exe

Which turned on all the events defined in the 'MinimalEventSource' we defined.    As you add more events to your EventSource, it becomes more and more likely that you will want more control over which events get logged.   In this blog, I will show you how to do this.  

Event Tracing for Windows (ETW) defines two mechanisms for controlling which events actually log their content.   Each event is tagged with two quantities:

  1. A small integer (enumeration) called a 'Level' which defines how verbose the event is.  Levels go from 0 to 5:   0 (Always) 1 (Critical) 2 (Error) 3 (Warning) 4 (Information) 5 (Verbose).  The default is 4 (Informational).   When the provider is turned on a level is specified Only those events that are less than or equal to the specified level will log messages. 
  2. A 64 bit, bit-vector called the events 'Keywords' which define 64 groups that an event can belong to.   When the provider is turned on a a set of keywords is passed in.  Only those events whose keywords overlap with the passed in keywords will log messages. 

 To see how to use these characteristics in your own eventSource consider the EventSource Example below.  

                [EventSource(Name = "MyCompany-WebServices")]
                internal sealed class MyCompanyEventSource : EventSource
                    [Event(1, Keywords = Keywords.Requests)]
                    public void RequestStarted(string Url, int RequestID) { WriteEvent(1, Url, RequestID); }
                    [Event(2, Keywords = Keywords.Requests, Level = EventLevel.Verbose)]
                    public void RequestPhase(int RequestID, string PhaseName) { WriteEvent(2, RequestID, PhaseName); }
                    [Event(3, Keywords = Keywords.Requests)]
                    public void RequestCompleted(int RequestID) { WriteEvent(3, RequestID); }
                    [Event(4, Keywords = Keywords.Debug)]
                    public void DebugTrace(string Message) { WriteEvent(4, Message); }
                    public class Keywords   // This is a bitvector
                        public const EventKeywords Requests = (EventKeywords)0x0001;
                        public const EventKeywords Debug = (EventKeywords)0x0002;
                    static public MyCompanyEventSource Logger = new MyCompanyEventSource();

 In this example, we define a 'MyComanyEventSource' and define a static instance of it (in brown at the bottom).   This EventSource has 4 events defined, and you can see that each of these events is 'Decorated' with an 'Event' Attribute which tells the EventSource base class more about the particular event.   These Event Attributes contain

  1. The Event Number.  Each event is given a unique number.  This is the same number that is passed to the first parameter of the 'WriteEvent' method in the event's body.  
  2. A set of additional ETW 'decorations' (Properties) for that event.   In this case we use two additional properties
    1. The 'Keywords' property indicates the keywords bitvector for the event (in blue).  You can see that we define two keywords: Requests, and Debug. 
    2. The 'Level' property indicates the level (verbosity) for the event.  By default is is 'Informational' but in the example above we made 'RequestPhase' a verbose event.

In addition to the event definitions themselves, there is also a nested class called 'Keywords' (you MUST use this name and it MUST be nested) which defined the numeric values for the keywords used in the event definitions.   Each of these should be a binary bit in the 64 bit long value.  

This example assumes that we have two event groups.  The first group (the 'Request' group) tracks a request as it journeys through the system.  Notice only the RequestStart event has the URL associated with the request.  The other events use a small integer value that is faster to write to indicate which exact events is being logged.   There is one verbose method (RequestPhase) which is meant mean for verbose diagnostic purposes and is often not needed.    The other group (the 'Debug') group has only one event DebugTrace that is meant for ad-hoc 'printf-sytle' diagnosis. 

Finally, the EventSource above follows a 'best practice' of naming its ETW provider a good name FROM THE U SER's POINT OF VIEW.   Names should at least start with your company name.  If you expect more than one EventSource for your company it is best to give them categories separated by '-'.   This is the convention that Microsoft has been following for the last several years.  (e.g. Microsoft-Windows-DotNetRuntime).  In the example above we named the provider 'MyCompany-WebServices'.   Please carefully consider this name as if you change it, it will break any users of your EventSource. 

The 'PerfView tool' supports using  levels and keywords with the following syntax.  

  • provider:keywords:level

You can add these at the command line or in the 'Additional Providers' textbox in the 'Advanced Options' section of the collection dialog.  By default PerfView turns on ALL keywords and the VERBOSE level, so the command

PerfView /OnlyProviders=*MyCompany-WebServices collect

Turns on all the events.   You can use '*' for the keyword to represent 'all' keywords so the command

PerfView /OnlyProviders=*MyCompany-WebServices:*:Information collect

Turns on all keywords (the :*:) that are a verbosity of Informational or below.  Thus this turns off the Verbose 'RequestPhase' event.   Currently PerfView does not support using the names of keywords, so you have to specify the keywords as a (hex) number.  Thus the command

PerfView /OnlyProviders=*MyCompany-WebServices:2 collect

Collects only the 'Debug' keyword events (at a Verbose level). 

Best Practices:  Keep it Simple from the users point of view!!

Now that you have the ability to finely control which events are emitted, I am going to do something very surprising: I am going to tell you to NOT use it most of the time.  The reason is simple:  Users of your events are FAR more concerned about ease of use than they are about optimizing the size of data collected.    It is FAR more frustrating to not have the events you need than to have too many.  Really the ONLY time people will care is when the events are VERY verbose.   This leads to the following strategy

  • Events that fire less than 100 times a second on average are 'too small to care about'  Don't bother making special keywords for them, but make a catch all 'Default' keyword.
  • Events that fire more than 1K times a second on average need keywords to turn them off if they are not needed.
  • Events in between 100 and 1K are a judgement call
  • Define keywords from a USERS (or scenario) point of view.   Users don't like to set more than one keyword (too error prone) so define the keywords that all common scenarios can be done by setting a single keyword.   Most users will use simply use the default (turn everything on).  
  • Levels less than Informational are meant for relatively rare warnings or errors.   When in doubt stick with the default of Informational, and use verbose for events that can happen more than 1K events / second.    Typically users use Keywords much more than Level, so don't worry about it too much. 

For more best practices and features of EventSources, see the EventSource specification.  

 Again it is your turn, time to try it out!

If you have not already gone to my EventSource demo blog entry and built the VS 2010 demo, you can do that now.   You can try out the example above if you like or simply take a look at the 'MyCompanyEventSource' class in the  'AdvancedUsageDemo.cs' file.    As mentioned this demo works today (because it comes with EventSource.dll which defined EventSource), but will be even easier in a few months when V4.5 of the .NET Runtime ships and EventSource is available in the framework)


Here are some other useful blog entries on EventSource:

  1. Introduction to EventSource 
  2. EventSource specification
  3. When you should be using EventSource
Comments (23)

  1. tracstarr says:

    I've been trying to work with ETW in 4.5 RC and have been following your posts closely (as there isn't much else out there). EventSource'ing is very easy and much better than having to create manifests etc as previous.

    My one big question is can/how to create a second custom application that can be the ETW controller and consumer of real time events. I would love to be able to write my own custom viewer for my custom events so that they can be displayed in a visually friendly manner (graphs, charts, etc). I've not found anything anywhere. Is this even possible with 4.5 or would this have to be c++? I was originally hoping that EventListner would do this, but it seems that only provides an outlet within the same assembly.


  2. You are looking for the TraceEvent library.   It is my intent to talk aIo twtiil lu  b eave nut ghtseb toIih de .o

    This library is availble on the web at      This library is what PerfVIew itself uses.  There is a sample application of an XML dumper call PerfMonitor at  

    PerfMonitor has inside a codeing example for a real time controller / consumer (See the 'MonitorProcs' routine in PerfMonitor.cs).  As you will see it only takes a few lines of code to be parsing ETW events.  

    Note that the code on CodePlex will be refreshed in the next month or so (it has not been updated reciently).   However it should still be fine for your purposes (the version of the library used by PerfView is much newer).   Until that update, you may wish to simply use the TraceEvent.dll from PerfView (in the AppDataRoamingPerfView directory).

    To parse your own EventSource events there are two options only one one of which you can do immediately.

    Option 1: Use the DynamicTraceEventParser.  In this case you use the 'PayloadByName(fieldName) to look up the fields of your object dynamically (you get back an object that you have to cast to the right type).   The events are parsed into fields, but because the field are only known at run time (not compile time), you had to use strings (not properties) to refernece them, and all fields return 'object' (so you need to cast).  

    Option 2: Generate static accessors from your manifest.   This is what a tool called 'TraceParserGen' does.  It takes a manifest (or an EventSource), and generates what is called a "TraceEventParser' which is the thing that the TraceEventLibrary needs to access the data.   Now all of your events are known at compile time and you get Intellisense and strong typing (and great efficiency).   However I have not published hte TraceParserGen tool (first things first, I will get to it…).  

    In short, there is a nice path here, but not all of it is public yet.   There is enough for enthusiasts to play with, but it will require some learning on your part.   If you are really serious let me know and I can help you more.    If not, just wait and I will get there…

    But your scenario (build custom events and then use them in a custom visualization) is definately the design point.

    Finally, I note that PerfView does have extensibility features (in particular it lets you get at ALL of its TraceEvent library.   Thus Building a PerfView extension (see help->Extending PerView) would be a useful way of proceeding (if only to 'play around').   This has the advantage that you get to use the latest version of the TraceEvent library.  

  3. tracstarr says:

    Thank you so much for the reply. I will look into the TraceEvent library and see what I can do right now. Using ETW with a custom viewer is a definite need for us. It's not critical right now to have the viewer, but will be sooner rather than later. I'll let you know if i have any questions.

  4. tracstarr says:

    So I've been playing around with extending PerfView with some success using Kernel events. However, I'm a bit stuck with trying to watch only my custom ETW eventsources. You suggest using DynamicTraceEventParser and some functions on that class. However, the PayloadByName is defined in the TraceEvent class. I'm kind of at a loss as to how to correctly instantiate the DynamicTraceEventParser with a TraceSource for my custom events. Do I need to define my own TraceSource and/or TraceEventDispatcher /TraceEvent?

    Thanks again.

  5. The quick answer is that you need register your callback just like for the Kernel ones you did

        var dynamicParser = yourTraceSource.Dynamic;

        dynamciParser.All += delegate(TraceEvent data) {

              // your code,  now data.PayloadByName will work….


    This fits the general model: TraceEventDispatcher act as a 'push model' list of events.  It does not know how to parse events.   Instead you register TraceEventParsers with them each of which handle some SUBSET of hthe event stream.   In your case you want to regsiter the DynamicParser (which knows how to parse EventSources) and you can achive this registration as a side effect of calling the Dynamic Property).   Your code subscribes to C# events  that represent individual PARSED events.   Normally these C# events  are strongly typed and there is one per event, but the DynamicTraceEventParser can't do this.  It only has the 'All' event, which represent any event this parser knows about (all event soruces).    By the time this callback is fired, the event has been parsed, and thus properties like EventName, TaskName, OPcodeName, and the PayloadByName functions work (assuming is is an eventSource, It has to get the schema SOMEHOW).  

    Note that while TraceEventDispatcher has an EveryEvent C# event, normally you don't use this because it will NOT be parsed (since there is no parser, dispatcher don't know how to parse, that is the parser's job).  


  6. Sean Hanna says:

    I'm implementing a logging component in a large scale system with ETW. We generate a unique token ID for each class at runtime and i'd like to somehow include this runtime generated ID in the ETW message to allow things like filtering and sorting.

    We are using a manifest based provider (and EventProvider class) and not the new EventSource api but i wonder how you might suggest populating a payload with a runtime generated id like this. If it can be applied to EventSource i'm sure i could come up with a way to adapt it to EventProvider.

    Of course it would be easy to put the ID in the the custom payload, however as soon as you do that the user interface support in the tooling is more restricted / lost.

    I think really the best case solution would be to populate the provider name with the unique token id. And then the full filtering rules of ETW can be applied. As far as i can tell, this would require each provider to be defined at compile time however, and really these provider names are only known at runtime which makes this a challenging proposition.

    I've also tried populating the Task Category field with a hash value derived from the unique ID. This also seems to have some caveats like (the id is not human readable unless defined in the manifest separately), and the task field has the undesirable and undocumented restriction that it must be 0 <= value <= 65535 (even though it is defined as an int in System.Diagnostics.Eventing.EventDescriptor) so there is an even greater chance of collisions if the id's are not properly hashable.

    What would you suggest?

  7. It is not clear to me why the straightforward approach of putting your class ID in the event Payload is problematic.    You talk about 'user interface support in the tooling' but I don't really know what you are refering to.  

    My best guess about your problem is that you would like to FILTER bases on the class ID.   The 'obvious' filtering that ETW provides is based on Provider and Keyword, which would not work for your case.   However ETW (and EventSource, but not EventProvider) support 'Provider define' filtering.  You will see an example of this in the EventSourcDemo source code.  The basic idea is that controllers (like PerfVIew) can send a arbitrary blob of data to the provider, which can then frankly do anything with it, but typically you want to use it to set filtering.  For example the provider (e.g. PerfView) could send the ID to filter (or a range, or regular expression), which the provider (your EventSource) can remember, and then use to determine whether to log any particular event (it the event methods of your EventSource).    

    The support in PerfView and EventSource for this consists of passing key value pairs which providers are free to define.  Thus you coudl define a key called 'ClassID'  which you then pass to the provider.  The provider (EventSource, defines a 'OnEventCommand' which looks for this.   You can specify this when you turn on the provider (PROVIDER:*:Verbose::CLASSID=xxxx) with PerfView (XPERF does not have this support).    

  8. Sean Hanna says:

    Hello and thanks for the feedback

    In terms of tooling i'm primarily working with the the Event Viewer control panel. The default view you get is at least 90% of what my coworkers will look at. Event viewer has user interface for filtering on all of the pre-defined etw fields (and you can even write xpath queries over the custom payload, though most people are unlikely to do this). Maybe teaching people how to use perfview would be a rationale step here.

    As it stands i still haven't found a way to use any of the existing ETW fields though. The rigid message structure requires a lot of up-front cost to add diversity to the log messages. Adding to the custom payload is easy, and adds to the diversity, but seems to be the naiive approach when ETW already provides places to put 'similar' information.

    I imagine separate providers for different classes / namespaces would really be the appropriate way to solve my problem. With a manifest based provider, setting up the manifests can be really cumbersome though. I am still thinking on whether this would be much easier with an EventSource, and you haven't covered how inheritance of EventSource classes works yet 🙂

  9. The OS provided EventViewer was really designed for a much simpler scenario (logging diagnostic messages) where total data volume is low and filtering after logging is fine.    You are strying using it outside its design point, which is why your experience is bad.    I don't really understand your scenario, but using a different tool is certainly something to consider.    

    Simmiarly, ETW defined a way of doing 'simple' filtering (keywords and level), and some predefined groups (tasks and opcodes), which can handle many common cases adaquately, however it was also known from the begining that it only handled the simple cases.   You are trying to do a more advanced case.  That is possible, but it is not the 'easy' case.

    I really don't understand your scenario yet.  It is not clear what you mean by 'class'.  If you mean every C# class, making a provider for each is definately NOT how the system was deigned to be used (the system does not  expect that many).   If it is something else (a logical component) and there are < 100 of them than that can be OK.   Fundamentally, you want providers to be things that users consuming the events 'understand' as 'big' things that make sense to be logically separate.  

    I would also strongly discourage 'really fine grained logging'.   This is what profilers are for and they do a great job already (the OS already has a built-in sample-based profiler which you can gate at with PerfView).   Trying to replicate this with hand logging has low benefit and high cost.  

    Finally as to your question on inheritance and EventSource: it is not supported.   It is not clear what the expected meaning woudl be of inherited EventSources woudl be, but most interpretations have versioning problems.   .  

  10. Sean Hanna says:

    We're writing a fairly large production system spread out across a couple dozen machines. We are completely in control of the environments we are working in (nobody but us is installing this software and we are largely in control of what runs on each machine). We also are working from a background in log4net, and there is a certain amount of paradigm shift between it and ETW that i'm still trying to overcome.

    We've made the leap to ETW on a model nearly identical to the log4net API. We provide a couple events (error / warning / audit / info / debug / ) through a really simple interface. With the number of components we have in the system, using a single provider for the entire event stream generates too much data to reasonably sift through. This is exacerbated in our development environment where all the components run simultaneously, as opposed to our live environment where we have dozens of systems serving the different roles.

    During deployments we disable the debug and info event streams, and retain a certain amount of error / warning / auditing event streams so that we can go back and troubleshoot any issues that might have come up in the past day / week / etc.. We have actually been discussing extending this policy with daily backups too. The log rotating features provided by the ETW / eventing infratsructure works really nicely for that, event forwarding and alert scheduling sound pretty cool, though i haven't figured out how to set them up yet. PerfView hasn't really come into play yet, though it is a logical step as we find ourselves needing to sift through information. We've tested and verified that enabling / disabling the channels in event viewer enables / disables the provider based filtering on those event types in the provider, so any logging messages we write to disabled event streams are skipped. ETW really does provide a lot of nice things for us for minimal effort.

    Most of the components are cleanly separated into namespaces, with the classes in that namespace defining the components behavior. We have our class id tokens which are generated into static variables at startup. Each class id is actually a clever call to new StackFrame(1, false).GetMethod().DeclaringType so we have the fully qualified name of each class in these tokens. As a simple way to improve the diversity in our events we can use these tokens (but not much else without trying to parse the log text). In some key classes i think we may want to still reserve the right to use a provider for a single class name, but these namespace level providers seem to fit the bill pretty well.

    There is actually a good deal of documentation saying 'dont define tons of providers', and ETW makes it prohibitive to try and do this in a manifest anyway. Perhaps you could expand on what technically would happen if i defined a billion of them? The windows operating system must define 100-200 among all the different components, and so i have (at this point casually) assumed that the scale of the system justifies the number of providers you define, instead of the number needing to be strictly limited at an executable / thread / etc.. level.

    (As an aside we are also using performance counters to capture timing and usage statistics at a similar scale).

    At this point i've identified 36 significant components. In production none of our components will actually run on a single machine. Aside from the few critical ones, the majority of our providers should be inactive most of the time. However, each component is using our simplified logging API and defining providers seems to match the ETW paradigm pretty accurately.

    Components as i've defined them fall under a few definitions, but the only non-obvious definition i've used for component is: a single webservice method of critical importance to our system. Even for individual webservice methods, we still use a distinct namespace for the real implementation details. Outside of this definition our providers largely fit the scope of a single executable, or a large subsystem shared by several executables.

    We've also found reasons to define custom payloads / events for things like a security warning and in those cases we have taken the time to carefully craft a template. In general we just want to record important stuff casually like (some exception was generated or some edge case we didn't worry about too much was hit). And this casual approach is somewhat contrary to the ETW paradigm (e.g. you still need to put a ton of effort into setting up the casual message templates).

    In the case of inheritance, we use a really simple set of events. (error / warning / info) with a simple string payload. In these cases we would like to inherit the provider definition and it's templates. There may be some reason why we want to attach a keyword or some customized localizable text to an individual provider after we inherited it from a base, but so far we just want to copy the provider and change the name 🙂 I wrote a pre-build script to generate the 36 provider manifests from a template, so that only the GUID / name of each provider needs to be declared to setup a new one.

  11. Sreeni says:

    I recently started following your blog and each article is short, precise and explaining one concept. Your samples are very helpful. I could create a sample solution based on your samples with the exception of custom parser. Do you have any article that explains how to create a custom parser? I saw some sample parsers in TraceEvent project. Any step by step article by taking a custom EventSource would be beneficial.

    Is the tool mentioned in this article "traceParserGen" available in any form?

  12. Indeed custom parsers have not been discussed yet for a reason.    The reason is that custom parsers should not be created by hand, but rather generated from manifest (that is once you have the type information in the manifest you can make the parser automatically).    We have an internal tool called 'traceParserGen' that does this.   I have not blogged about it because it is not externally available (yet).    It is not available mostly because it is not user friendly enough (if your manifest is not just they way it likes it, errors with unfriendly diagnostics result).    At some point soon I will fix the most problematic of this unfriendliness and publish something, but until that time I don't want to blog about it.    It turns out that almost all of the TraceEventParsers in the TraceEvent library were generated with this tool, so you can get a good feel for what the tool would do simply by looking at some of the TraceEventParsers in TraceEvent.dll.  

    If this is really blocking you I can send you it 'as is' but you will have to live minimal docs and no demo.  

  13. Sreeni says:

    I apprecaite you sharing the information. My need is, to create application specific parsers that parse Error, Warning events and log to a common database. Towards this, custom parser really helps me. You can share the tool to my email OR

  14. Martin says:

    This is good information. I have this question: can I use negative values in my Keywords enum ?

           public class Keywords


               public const EventKeywords Page = (EventKeywords)1;

               public const EventKeywords Database = (EventKeywords)2;

               public const EventKeywords Neg = (EventKeywords)(-1);


  15. Keywords are interpreted as a bit-vector.   Thus as you add single keywords they should be a power of 2.   There already is EventKeywords.All which is defined to be -1 (all 1s).   I can't imagine it being useful to specify a negative number besides -1.  

  16. BillH says:

    I have a problem with using custom keywords.

    So I have a nested class called Keywords, and Intellisense shows the enumerations when I add the attributes.  Everything compiles, and using EventSourceAnalyzer.InspectAll generates no exceptions.  As a test, I have put in an If statement with (IsEnabled(EventLevel.Informational, Keywords.Login).  When I step to this line of code, and hover over the Keywords.Login, instead of seeing the enumeration value, I am seeing 'None' as the value.  IsEnabled is false in this case.  I think this is a clue as to something wrong.

    Without custom keywords, equals seeing events.

    Custom keywords equals no events.

    Any tips on what else to check would be most appreciated.  Source code below:

    [EventSource(Name = "XYZWebLog")]

       public class XYZWebLog : EventSource


           public class Keywords


               public const EventKeywords Login = (EventKeywords) 1;

               public const EventKeywords Billing = (EventKeywords) 2;


           [Event(1, Level = EventLevel.Informational, Keywords = XYZWebLog.Keywords.Login)]

           public void SuccessfulLogin(string loginId)


               if (IsEnabled(EventLevel.Informational, Keywords.Login)) //<<Login shows as 'None' at runtime


                   WriteEvent(1, loginId);




  17. @BillH   Keep in mind that the Keywords class does not modify the 'EvenKeywords' type, it only adds contants (that the type does not know about).  Thus you can't expect intellisense or the debugger to know about your new Login value.    To confirm that the value is being passed correctly, create a local variable that you assign Keywords.Login to and then check it in the debugger (or send to Trace.WriteLine), to see its value.   .  

  18. BillH says:

    I just set a test variable, and it says the value for the Keywords is 'None'.  The attribute has the Keywords set to 'Login'.  It seems the attribute is not setting the Keywords value somehow??

  19. BillH says:

    So the code problem that I posted works now, with one change.

    I moved the 'Keywords' class to still be nested, but at the bottom of the containing class.

    Should I always put the 'Keywords' class last??

  20. I am glad you got it working.   I can't explain your result however.   Order should not have mattered.  

  21. Vidhi says:


    I have created the EventSource ( inheriting from EventSource) . In the constructor I am passing providerName.

    Events are also defined as below.

    But when I do WriteEvent in the consumer call back I receive the data (TraceEvent). The payload information does not contain the values which I have logged. It contains the junk characters. Also the first value Id which is string is concatenated with second string character. Please let me know in case anyone has faced this issue.

    ANy help is appreciated .

    public sealed class MyEventSource:EventSource, ITraceProvider


           private static readonly Lazy<MyEventSource> Instance = new Lazy<MyEventSource>(() => new MyEventSource("provider1"));

           public static ETWTraceProvider Log


               get { return Instance.Value; }


           private ETWTraceProvider(String strProviderName)

               : base(strProviderName)



           [Event(1, Level = EventLevel.LogAlways)]

           public void TraceLog(string id, string strMessage)


               WriteEvent(1, ids, strMessage,ids);



  22. stej says:


    Every method that I've seen so far follows the rule that the WriteEvent contains the same parameters (+ id at the beginning) as the method signature.

    Yours should look like WriteEvent(1, id, strMessage).

  23. I see that I missed this comment back in December (I was out of the office).   As @stej indicates however, it is an error not to pass exactly the same arguments through to WriteEvent as are declared in the method (The serializer determines what to serialize by reflection on the signature.

    If you wish to pass additional information then you need to make a private method that has ALL the information you want to pass, and then a [NonEvent] method that you actually call from your instrumentation site that then calls the private method with  the extra information.  

Skip to main content