This document delves into the eventing mechanisms within the .NET Runtime (CoreCLR). Understanding how the runtime emits and consumes events is crucial for debugging, performance analysis, and building sophisticated diagnostics tools.
The .NET Runtime exposes various types of events, broadly categorized into:
Runtime events are primarily surfaced through distinct providers. The most common and powerful mechanism is the EventSource API, which is built upon the Event Tracing for Windows (ETW) on Windows and similar tracing facilities on other operating systems.
EventSource
is the .NET abstraction for creating custom event providers. The runtime itself extensively uses this for its internal diagnostics. You can enable these events using various tools and APIs.
You can capture these events using:
EventListener
.Note: Enabling verbose eventing can have a performance impact. Use it judiciously for debugging and profiling.
dotnet-trace
To collect GC events for a running .NET process, you can use the dotnet-trace
tool:
# Find the Process ID (PID) of your .NET application
dotnet-trace ps
# Collect GC events for a specific PID (e.g., 12345)
dotnet-trace collect --process-id 12345 --providers Microsoft-Windows-DotNETRuntime:0x10:4
In the command above:
Microsoft-Windows-DotNETRuntime
is the provider name.0x10
is the keyword mask (GC events are often associated with this).4
is the level (Informational
).You can create a custom EventListener
in your .NET application to receive runtime events:
using System;
using System.Diagnostics.Tracing;
public class RuntimeEventListener : EventListener
{
protected override void OnEventSourceCreated(EventSource eventSource)
{
// Subscribe to the .NET Runtime event source
if (eventSource.Name == "Microsoft-Windows-DotNETRuntime")
{
// Enable GC, JIT, and other relevant events.
// The exact keywords and level depend on what you want to capture.
// For example, to get GC events (keyword 0x10) at Informational level (4):
EnableEvents(eventSource, EventLevel.Informational, (EventKeywords)0x10);
// To get JIT events (keyword 0x20) at Informational level (4):
// EnableEvents(eventSource, EventLevel.Informational, (EventKeywords)0x20);
}
}
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
Console.WriteLine($"Event Name: {eventData.EventName}");
Console.WriteLine($"Event ID: {eventData.EventId}");
Console.WriteLine($"Keywords: {eventData.Keywords}");
Console.WriteLine($"Level: {eventData.Level}");
Console.WriteLine("Payload:");
if (eventData.Payload != null)
{
for (int i = 0; i < eventData.Payload.Count; i++)
{
Console.WriteLine($" {eventData.PayloadNames[i]}: {eventData.Payload[i]}");
}
}
Console.WriteLine(new string('-', 20));
}
}
public class Program
{
public static void Main(string[] args)
{
var listener = new RuntimeEventListener();
Console.WriteLine("Runtime event listener started. Press Enter to exit.");
Console.ReadLine();
listener.Dispose();
}
}
Understanding keywords and levels is key to filtering events effectively. While specific values can vary, here are some common ones:
LogAlways
(0)Critical
(1)Error
(2)Warning
(3)Informational
(4)Verbose
(5)Microsoft-Windows-DotNETRuntime
):
GC (0x10)
: Garbage Collection events.JIT (0x20)
: Just-In-Time compilation events.Threading (0x40)
: Threading-related events.Exception (0x80)
: Exception handling events.TypeLoad (0x100)
: Type loading events.Loader (0x200)
: Assembly loading/unloading events.Interop (0x400)
: P/Invoke and COM interop events.GCHeapSnapshot (0x1000)
: Indicates a GC heap snapshot was taken.GCHeapAndTypes (0x2000)
: Includes type information in GC events.You can find a more exhaustive list of keywords and their meanings in the .NET runtime's source code or documentation for specific tracing tools.
Runtime events provide a window into the intricate workings of the .NET CoreCLR. By mastering the EventSource API and utilizing powerful tracing tools, developers can gain deep insights into application behavior, diagnose performance bottlenecks, and build robust diagnostic solutions.