Nefarius.Utilities.ETW
2.9.0
Prefix Reserved
See the version list below for details.
dotnet add package Nefarius.Utilities.ETW --version 2.9.0
NuGet\Install-Package Nefarius.Utilities.ETW -Version 2.9.0
<PackageReference Include="Nefarius.Utilities.ETW" Version="2.9.0" />
<PackageVersion Include="Nefarius.Utilities.ETW" Version="2.9.0" />
<PackageReference Include="Nefarius.Utilities.ETW" />
paket add Nefarius.Utilities.ETW --version 2.9.0
#r "nuget: Nefarius.Utilities.ETW, 2.9.0"
#:package Nefarius.Utilities.ETW@2.9.0
#addin nuget:?package=Nefarius.Utilities.ETW&version=2.9.0
#tool nuget:?package=Nefarius.Utilities.ETW&version=2.9.0
Nefarius.Utilities.ETW
ETW Log Files (.ETL) to JSON parser/converter library.
This is a fork of the fantastic
ETW2JSONproject by Microsoft and contributors.
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 |