etw.net-traceprocessing

Parse CLR Event with TraceProcessor


I have followed the guidance at https://learn.microsoft.com/en-us/windows/apps/trace-processing/extensibility to get my hands on the .NET Runtime events. When I get a EventContext instance with the unparsed data I have no convenient way to parse things further?

Ideally there should be a parser generator for manifest based events like it is the case with TraceEvent. Something like

TraceProcessorGen -generateEvents c:\Windows\Microsoft.NET\Framework\v4.0.30319\CLR-ETW.man

would be a big help. I am not inclinded to manually write the parsing code with hundreds of hard coded offsets for dozens of events.

class ClrDataSource : IFilteredEventConsumer
{
    public IReadOnlyList<Guid> ProviderIds { get; } = new Guid[] { new Guid("e13c0d23-ccbc-4e12-931b-d9cc2eee27e4") };

    public int Count { get; private set; }

    public void Process(EventContext eventContext)
    {
        ReadOnlySpan<byte> data = eventContext.Event.Data;
        // What do do next? 
    }
}

TraceEvent from Vance Morrison has an easy way to explore manifest based events where the Payload and PayloadNames are already preparsed based on their manifest. This is not very performant but for many cases and explorative research very helpful.


Solution

  • (I am a developer at Microsoft who works on the TraceProcessor project.)

    IFilteredEventConsumer is a way to get at the unparsed events in the trace, and it's true that we have not added support for using a manifest file to simplify that parsing.

    However, parsed events for that provider should be available in the IGenericEventDataSource like this:

    using (ITraceProcessor trace = TraceProcessor.Create(tracePath))
    {
        Guid[] providerIds = new[] { Guid.Parse("e13c0d23-ccbc-4e12-931b-d9cc2eee27e4") };
    
        IPendingResult<IGenericEventDataSource> pendingEventsData = trace.UseGenericEvents(providerIds);
    
        trace.Process();
    
        IGenericEventDataSource eventData = pendingEventsData.Result;
    
        foreach (IGenericEvent genericEvent in eventData.Events)
        {
            // Process event here
        }
    }
    

    Within each IGenericEvent, there is a property called Fields, which should let you access events either by integer index or by name.