Listing all available ETW events in a .NET application

 
 
  • Gérald Barré

When tracing an application, knowing which ETW events are available is valuable. .NET exposes many events for tracing, as shown in previous posts (Getting telemetry data from inside or outside a .NET application and Avoid DNS issues with HttpClient in .NET). However, discovering which events exist and which ones are actually emitted can be challenging. This post explains how to list all available events in a .NET application by registering a custom EventListener.

The approach is to register an EventListener within the application and log all emitted events. Since the code runs inside the application, it has access to all event sources and can enable every EventSource. The following snippet demonstrates this:

C#
using System.Collections.Concurrent;
using System.Diagnostics.Tracing;

internal sealed class EventSourceEnumerator : EventListener
{
    public ConcurrentDictionary<string, ConcurrentDictionary<int, EventInfo>> Events { get; } = new();

    public EventSourceEnumerator()
    {
        EventSourceCreated += OnEventSourceCreated;
        EventWritten += OnEventWritten;
    }

    private void OnEventWritten(object? sender, EventWrittenEventArgs e)
    {
        var events = Events[e.EventSource.Name];
        if (events != null)
        {
            if (!events.ContainsKey(e.EventId))
            {
                events.TryAdd(e.EventId, new EventInfo(e.EventId, e.EventName, e.Level, e.PayloadNames?.ToArray() ?? Array.Empty<string>()));
            }
        }
    }

    private void OnEventSourceCreated(object? sender, EventSourceCreatedEventArgs e)
    {
        if (e.EventSource is null)
            return;

        if (!Events.ContainsKey(e.EventSource.Name))
        {
            EnableEvents(e.EventSource, EventLevel.LogAlways);
            Events.TryAdd(e.EventSource.Name, new ConcurrentDictionary<int, EventInfo>());
        }
    }
}

internal sealed record EventInfo(int Id, string? Name, EventLevel Level, string[] PayloadNames);

You can then use the EventSourceEnumerator to list all available events:

C#
using var eventSourceEnumerator = new EventSourceEnumerator();

Console.WriteLine("Hello, World!");
using var httpClient = new HttpClient();
await httpClient.GetStringAsync("https://www.meziantou.net");

foreach (var ev in eventSourceEnumerator.Events)
{
    Console.WriteLine(ev.Key); // Event Source name
    foreach (var e in ev.Value)
    {
        // All events for the event source
        Console.WriteLine($"  Id: {e.Key}, Name: {e.Value.Name}, Level: {e.Value.Level}, Payload: {string.Join(",", e.Value.PayloadNames)}");
    }
}

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?