Adding Telemetry Events Using the PowerToys Telemetry Framework: A Developer’s Guide
To add telemetry events using the PowerToys telemetry framework, create a class inheriting from EventBase and implementing IEvent, decorate it with [EventData], then emit it via PowerToysTelemetry.Log.WriteEvent().
The PowerToys telemetry framework provides a lightweight, ETW-based system for tracking feature usage and diagnostic data within the Microsoft PowerToys repository. This guide explains how to instrument your code by defining custom event classes and publishing them through the singleton telemetry helper.
Understanding the PowerToys Telemetry Architecture
The telemetry system resides primarily in the ManagedTelemetry project and relies on Event Tracing for Windows (ETW) to emit structured data. Understanding the core components ensures you implement events that integrate seamlessly with the existing pipeline.
Core Components
| Component | Role | Source Location |
|---|---|---|
PowerToysTelemetry |
Singleton helper that writes events to the Microsoft.PowerToys ETW provider. | src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs |
EventBase |
Base class supplying common properties (EventName, Version, etc.) for every payload. |
src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs |
IEvent + [EventData] |
Marker interface and attribute telling the serializer how to process the payload. | src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs |
| Concrete Event classes | One per logical action (e.g., CmdNotFoundInstallEvent). They inherit EventBase, implement IEvent, and typically live in src/settings-ui/Settings.UI.Library/Telemetry/Events. |
src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundInstallEvent.cs |
How Telemetry Flows Through the System
The framework follows a three-stage pipeline:
-
Event Definition – You create a class deriving from
EventBaseand implementingIEvent. The[EventData]attribute ensures the ETW serializer recognizes the class, whilePartA_PrivTagsproperties indicate privacy classifications. -
Publishing – Your UI or module logic calls
PowerToysTelemetry.Log.WriteEvent<T>(), passing an instance of your event class. The method checks the global diagnostic flag (DataDiagnosticsSettings.GetEnabledValue()) before forwarding the payload toTelemetryBase.Write<T>(), which emits the actual ETW event. -
Consumption – The ETW provider captures the event locally. When users opt into diagnostic data collection, the pipeline aggregates these events and transmits them to Microsoft for analysis.
Step-by-Step Guide to Adding Telemetry Events
Implementing new telemetry requires defining the payload structure and instrumenting your code to fire the event at the appropriate moment.
Step 1: Define Your Event Class
Create a new class file in the appropriate Telemetry/Events folder (e.g., src/settings-ui/Settings.UI.Library/Telemetry/Events/ for settings UI features). The class must inherit EventBase, implement IEvent, and include the [EventData] attribute.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events
{
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class MyFeatureUsedEvent : EventBase, IEvent
{
// Required privacy tag indicating this is product usage data
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
// Custom payload properties
public string FeatureName { get; set; }
public bool WasSuccessful { get; set; }
public MyFeatureUsedEvent()
{
EventName = nameof(MyFeatureUsedEvent);
}
}
}
The PartA_PrivTags property is mandatory for privacy compliance, categorizing the event as either ProductAndServiceUsage or ProductAndServicePerformance. The [DynamicallyAccessedMembers] attribute ensures the trimmer preserves the public properties required for ETW serialization.
Step 2: Emit the Event from Your Code
In your ViewModel, command handler, or module logic, instantiate the event class and pass it to the singleton PowerToysTelemetry.Log.WriteEvent() method.
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Settings.UI.Library.Telemetry.Events;
public void OnUserClickedMyFeature()
{
var telemetryEvent = new MyFeatureUsedEvent
{
FeatureName = "SuperCoolTool",
WasSuccessful = true
};
PowerToysTelemetry.Log.WriteEvent(telemetryEvent);
}
The WriteEvent<T> method automatically checks whether the user has enabled diagnostic data collection via DataDiagnosticsSettings.GetEnabledValue() before writing to the ETW provider, ensuring compliance with user privacy preferences.
Real-World Example from the PowerToys Codebase
The Command Not Found module demonstrates this pattern in production. When a user installs the module, the ViewModel fires a CmdNotFoundInstallEvent:
// Located in src/settings-ui/Settings.UI/ViewModels/CmdNotFoundViewModel.cs
PowerToysTelemetry.Log.WriteEvent(new CmdNotFoundInstallEvent());
The corresponding event definition in src/settings-ui/Settings.UI.Library/Telemetry/Events/CmdNotFoundInstallEvent.cs inherits from EventBase, implements the required privacy tags, and requires no additional payload properties for this specific action.
Key Files and Locations in the Repository
When implementing telemetry, reference these specific files to understand the underlying implementation and existing patterns:
| Path | Purpose |
|---|---|
src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs |
Singleton entry point containing the Log property and WriteEvent<T> method. |
src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs |
Abstract base class providing EventName, versioning, and IEvent implementation. |
src/common/ManagedTelemetry/Telemetry/Events/DebugEvent.cs |
Reference implementation showing basic event structure with privacy tags. |
src/settings-ui/Settings.UI.Library/Telemetry/Events/ |
Directory containing UI-specific events like CmdNotFoundInstallEvent.cs. |
src/settings-ui/Settings.UI/ViewModels/ |
Location of ViewModel call sites (e.g., CmdNotFoundViewModel.cs) demonstrating event emission. |
src/common/ManagedTelemetry/Telemetry/TelemetryBase.cs |
Low-level ETW write mechanics and diagnostic flag checking. |
Summary
- PowerToys telemetry relies on an ETW-based framework located in the
ManagedTelemetryproject, using theMicrosoft.PowerToysprovider. - Event classes must inherit from
EventBase, implementIEvent, use the[EventData]attribute, and specifyPartA_PrivTagsfor privacy compliance. - Emission occurs through the singleton
PowerToysTelemetry.Log.WriteEvent<T>()method, which automatically respects user diagnostic preferences. - UI events typically reside in
src/settings-ui/Settings.UI.Library/Telemetry/Events/, while module-specific events follow similar patterns in their respective directories.
Frequently Asked Questions
What is ETW and why does PowerToys use it for telemetry?
Event Tracing for Windows (ETW) is a high-performance logging mechanism built into Windows that allows applications to emit structured events with minimal overhead. PowerToys uses ETW through the Microsoft.PowerToys provider because it provides reliable, low-latency telemetry collection that integrates with standard Windows diagnostic tools and respects user privacy controls through the system's data diagnostic settings.
How do I ensure my telemetry events comply with privacy requirements?
Every event class must implement the PartA_PrivTags property, returning either PartA_PrivTags.ProductAndServiceUsage for feature interaction data or PartA_PrivTags.ProductAndServicePerformance for diagnostic data. Additionally, the PowerToysTelemetry.Log.WriteEvent() method automatically checks DataDiagnosticsSettings.GetEnabledValue() before writing to ETW, ensuring events are only captured when users have explicitly opted into diagnostic data collection.
Can I add telemetry to C++ modules, or is this framework C# only?
The ManagedTelemetry project and the PowerToysTelemetry class are specifically designed for managed (.NET) code. C++ modules in the PowerToys repository typically use different telemetry mechanisms or call into separate native ETW providers. If you are working with a C++ module, you should look for existing native telemetry patterns in that specific project's source code rather than using the C# EventBase framework described here.
Where can I view the telemetry events locally for debugging?
Since PowerToys uses ETW, you can capture and view telemetry events locally using tools like PerfView or the Windows Event Viewer (under Applications and Services Logs > Microsoft > PowerToys). During development, you can also set breakpoints in PowerToysTelemetry.Log.WriteEvent() located in src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs to verify that your events are being constructed and emitted correctly before they reach the ETW provider.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →