Nefarius.Utilities.ETW
2.11.0
Prefix Reserved
See the version list below for details.
dotnet add package Nefarius.Utilities.ETW --version 2.11.0
NuGet\Install-Package Nefarius.Utilities.ETW -Version 2.11.0
<PackageReference Include="Nefarius.Utilities.ETW" Version="2.11.0" />
<PackageVersion Include="Nefarius.Utilities.ETW" Version="2.11.0" />
<PackageReference Include="Nefarius.Utilities.ETW" />
paket add Nefarius.Utilities.ETW --version 2.11.0
#r "nuget: Nefarius.Utilities.ETW, 2.11.0"
#:package Nefarius.Utilities.ETW@2.11.0
#addin nuget:?package=Nefarius.Utilities.ETW&version=2.11.0
#tool nuget:?package=Nefarius.Utilities.ETW&version=2.11.0
Nefarius.Utilities.ETW
ETW Log Files (.ETL) to JSON parser/converter library.
This is a fork of the fantastic ETW2JSON project by Microsoft and
contributors.
While this library is designed to support universal ETW trace sources, the primary personal goal and highest development priority has been making it work reliably with WPP Software Tracing in particular. Other trace source types may work but receive less focused attention and testing.
Changes of this fork
- Converted console tool into a reusable class library
- Replaced P/Invoke code with source generators
- Changed namespace to
Nefarius.Utilities.ETWto avoid conflicts with the origin library - Added support for WPP Software Tracing decoding
- Supports
.PDBfiles as a decoding source — WPP provider GUIDs (ETW trace control GUIDs) are automatically extracted fromTMC:annotations in the PDB symbol stream so no manual GUID lookup is required - Supports
.TMFfiles as a decoding source - Full support for all WPP extended format specification strings
(
%!FUNC!,%!LEVEL!,%!FLAGS!,%!IPADDR!,%!TIMESTAMP!,%!delta!,%!due!,%!GUID!,%!CLSID!/%!LIBID!/%!IID!,%!PORT!,%!STATUS!,%!WINERROR!,%!HRESULT!,%!NDIS_STATUS!,%!NDIS_OID!,%!sid!, bitset/list enumerations, and more) USEPREFIX/USESUFFIXtrace message prefixes are automatically expanded — the%0standard-prefix sentinel and%!FUNC!/%!LEVEL!context markers are resolved from the TMF metadata at decode time
- Supports
- Added
EtwUtil.EnumeratePdbReferencesfor lightweight pre-scanning of ETL files to collect all PDB metadata (symbol GUIDs, ages and file names) referenced in the trace before performing a full decode — enabling proper multi-PDB symbol resolution via symbol servers or local paths - Added
EtwUtil.EnumerateEventsAsync— a streamingIAsyncEnumerable<ReadOnlyMemory<byte>>API that yields each decoded ETW event as a self-contained UTF-8 JSON buffer as it is produced, rather than waiting for the full trace to finish; a dedicated background thread runs the blockingProcessTracecall and feeds a bounded channel so the consumer is naturally backpressured and can process events concurrently with parsing; works well as a data source for real-time delivery scenarios such as FastEndpoints Server Sent Events:
public override async Task HandleAsync(CancellationToken ct)
{
await Send.EventStreamAsync("etw-event", GetEtwStream(ct), ct);
}
private async IAsyncEnumerable<object> GetEtwStream([EnumeratorCancellation] CancellationToken ct)
{
await foreach (ReadOnlyMemory<byte> eventJson in EtwUtil.EnumerateEventsAsync(
[@"C:\traces\capture.etl"],
opts => opts.WppDecodingContext = myDecodingContext,
ct))
{
yield return JsonSerializer.Deserialize<object>(eventJson.Span)!;
}
}
- Added realtime ETW session support via
EtwRealtimeSessionandEtwUtil.EnumerateRealtimeEventsAsync:EtwRealtimeSession.Create(name)starts a user-mode ETW session (StartTraceW)EnableProvider/DisableProvidertoggle providers at runtime viaEnableTraceEx2EtwUtil.EnumerateRealtimeEventsAsyncattaches to any externally-managed session and streams decoded events as UTF-8 JSON using the same bounded-channel / background-thread architecture as the file-basedEnumerateEventsAsyncEtwUtil.ConvertRealtimeToJsonblocks and writes events to aUtf8JsonWriteruntil cancelledEtwUtil.StopOrphanSessioncleanly stops a session left behind by a previous crash
Realtime decoding
The library ships two independent layers for realtime ETW consumption.
Layer 1 — attach to any existing session (consumer-only)
If the session is already running (started by logman, xperf, another process, or your own code), attach directly with a session name:
using CancellationTokenSource cts = new();
// Cancel after Ctrl+C or when your app shuts down.
Console.CancelKeyPress += (_, e) => { e.Cancel = true; cts.Cancel(); };
await foreach (ReadOnlyMemory<byte> eventJson in EtwUtil.EnumerateRealtimeEventsAsync(
"MySession",
cancellationToken: cts.Token))
{
Console.WriteLine(System.Text.Encoding.UTF8.GetString(eventJson.Span));
}
Layer 2 — full session management (start + enable + stop)
Use EtwRealtimeSession when your application owns the session lifetime.
Requires administrator / SeSystemProfilePrivilege.
// Clean up any orphan from a previous crash.
EtwUtil.StopOrphanSession("MyApp-Live");
using EtwRealtimeSession session = EtwRealtimeSession.Create("MyApp-Live",
opts =>
{
opts.BufferSizeKb = 64;
opts.FlushTimerSeconds = 1;
opts.ClockResolution = EtwClockResolution.QueryPerformanceCounter;
});
// Enable one or more providers at the desired verbosity level.
Guid microsoftWindowsKernelProcess = new("22FB2CD6-0E7B-422B-A0C7-2FAD1FD0E716");
session.EnableProvider(microsoftWindowsKernelProcess, TraceEventLevel.Information);
using CancellationTokenSource cts = new();
Console.CancelKeyPress += (_, e) => { e.Cancel = true; cts.Cancel(); };
await foreach (ReadOnlyMemory<byte> eventJson in EtwUtil.EnumerateRealtimeEventsAsync(
session.SessionName,
cancellationToken: cts.Token))
{
Console.WriteLine(System.Text.Encoding.UTF8.GetString(eventJson.Span));
}
// Disposing session calls ControlTraceW(STOP) — no orphan left behind.
Realtime caveats
- Admin required to start a session.
EtwRealtimeSession.CreatethrowsEtwStartTraceExceptionwithERROR_ACCESS_DENIEDwhen the process is not elevated. - Sessions persist after process exit. Always dispose
EtwRealtimeSession, and callEtwUtil.StopOrphanSession("name")at startup as a safety net. - WPP decoding in realtime mode requires a pre-built
DecodingContext. The file-basedEnumeratePdbReferencespre-scan only works on.etlfiles, not on live sessions. Build theDecodingContextfrom known.pdbor.tmfpaths before starting the session. - Kernel-mode providers / NT Kernel Logger are not supported in this release.
CLI (etwutils)
The tools/Nefarius.Utilities.ETW.CLI project builds a .NET global tool (etwutils) that wraps the realtime API and writes decoded events as NDJSON or plain tab-separated text to stdout.
dotnet tool install -g Nefarius.Utilities.ETW.CLI
See tools/Nefarius.Utilities.ETW.CLI/README.md for full installation instructions, command reference, and examples.
Known limitations
- Currently relies on Windows-only APIs so no support for other platforms
%!ItemEnum!/%!ItemFlagsEnum!types display raw numeric values; PDB-based enum name resolution is not yet implemented- Kernel-mode ETW providers and the NT Kernel Logger session are not yet supported for realtime mode
Documentation
Sources & 3rd party credits
- Microsoft/ETW2JSON
- Microsoft/ETW
- WPP Software Tracing
- microsoftarchive/bcl/Tools/ETW/traceEvent/SymbolEventParser.cs
enum _TDH_CONTEXT_TYPE- Learn / Windows / Windows Drivers / How do I add a prefix and suffix to a trace message?
- Learn / Windows / Windows Drivers / What are the WPP extended format specification strings
- kaitai-pdb
- MinVer
- Fast access to .net fields/properties
- Nefarius.Shared.PdbUtils
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows8.0 is compatible. net9.0-windows was computed. net9.0-windows8.0 is compatible. net10.0-windows was computed. net10.0-windows8.0 is compatible. |
-
net10.0-windows8.0
- FastMember (>= 1.5.0)
- KaitaiStruct.Runtime.CSharp (>= 0.11.0)
- Nefarius.Shared.PdbUtils (>= 1.0.0)
-
net8.0-windows8.0
- FastMember (>= 1.5.0)
- KaitaiStruct.Runtime.CSharp (>= 0.11.0)
- Nefarius.Shared.PdbUtils (>= 1.0.0)
-
net9.0-windows8.0
- FastMember (>= 1.5.0)
- KaitaiStruct.Runtime.CSharp (>= 0.11.0)
- Nefarius.Shared.PdbUtils (>= 1.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.18.0 | 100 | 8/5/2026 |
| 2.17.1 | 106 | 7/21/2026 |
| 2.17.0 | 137 | 6/16/2026 |
| 2.16.0 | 117 | 6/16/2026 |
| 2.15.1 | 112 | 6/1/2026 |
| 2.15.0 | 114 | 6/1/2026 |
| 2.14.2 | 106 | 5/31/2026 |
| 2.14.1 | 110 | 5/31/2026 |
| 2.14.0 | 107 | 5/30/2026 |
| 2.13.0 | 108 | 5/30/2026 |
| 2.12.0 | 122 | 5/29/2026 |
| 2.11.0 | 120 | 5/28/2026 |
| 2.10.2 | 127 | 5/28/2026 |
| 2.10.1 | 117 | 5/28/2026 |
| 2.10.0 | 127 | 5/28/2026 |
| 2.9.0 | 132 | 5/28/2026 |
| 2.8.0 | 142 | 5/27/2026 |
| 2.7.0 | 132 | 5/26/2026 |
| 2.6.0 | 125 | 5/26/2026 |
| 2.5.0 | 126 | 5/26/2026 |