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:

  1. Event Definition – You create a class deriving from EventBase and implementing IEvent. The [EventData] attribute ensures the ETW serializer recognizes the class, while PartA_PrivTags properties indicate privacy classifications.

  2. 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 to TelemetryBase.Write<T>(), which emits the actual ETW event.

  3. 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 ManagedTelemetry project, using the Microsoft.PowerToys provider.
  • Event classes must inherit from EventBase, implement IEvent, use the [EventData] attribute, and specify PartA_PrivTags for 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →