In this post we are going to discuss one rather unexpected feature of EventSource. As we have been discussing that the type is introduced in .net framework 4.5 for generating ETW [Event Tracing for Windows]events. It makes it easier to generate these events by providing simple inherited type for EventSource providing definitions of logging methods. The compiler and run-time would make sure that the necessary manifest is generated and used at compile and run-time.
The unexpected behavior is seen when our custom EventSource implements an interface. In order to understand the problem, let's create a sample console application EventSourceMembers.
Now let's introduce a simple custom Event source. It just has one method decorated with Event attribute. Let's add the following code to the project just created.
For simplicity, we can simply use the event source as follows:
Now we build the project. Now we can use PerfView to verify the generated events by the application.
And we do see the logs written out. As you can see PerfView registered the event.
Now let's use our amazing refactoring skills using Visual Studio to extract an interface from our CustomEventSource type. It just has one method Login.
Here ICustomEventSource interface is extracted as follows:
Now we again run the application using PerfView using the same command as used before. We see the following ETL data. You should notice that it is missing Login method, which is unlike before.
As you have been following, we have just implemented an interface for the type. In order to find out what could have gone wrong, let's see the PerfView log. You might see the log button flashing on the bottom right to draw our attention when the tool started running because of unexpected failure.
We can also see PerfView log here:
How to explain this?
Now we know what have caused this exception. It is implementing an interface for the EventSource sub-type. But is there an explanation for this or this is just a weird bug? Actually EventSource members implementing an interface members are not candidate for ETW manifest. Only direct methods in the sub-type qualify for this. So for the Login method, there is no ETW manifest generated. So calling WriteEvent expects and [EventId = 1], which is not the case in the manifest.
In order to further prove our point, let us add another method to the custom event source type. So DirectLogin is not an implementation of the method from the interface. Let's use the same method in Main method as well. We are updating the type as follows:
If we use PerfView again with the same command, we don't see the exception anymore. We do see the event for the new method, which proves our point.
Is there an alternative?
Actually there is. We don't have to implement [Event] methods from the interface. There can be [NonEvent] methods implementing the interface methods which can use those [Event] methods. The runtime doesn't even require the [Event] methods to be public. Here we are keeping the implementation as singleton. I think if you change it and register it with as a singleton with your DI container, it should still be fine. For unity, we can use ContainerControlledLifeTimeManager It definitely doesn't have any issue with EventSourceAnalyzer. Still need to see the performance implication. [See the Discussion]