doc/devdocs/events.md
PowerToys collects limited telemetry to understand feature usage, reliability, and product quality. When adding a new telemetry event, follow the steps below to ensure the event is properly declared, documented, and available after release.
⚠️ Important: Telemetry must never include personal information, file paths, or user‑generated content.
Adding a telemetry event is a multi-step process that typically spans several areas of the codebase and documentation.
At a high level, developers should expect to:
NEVER log:
DO log:
Follow this pattern: UtilityName_EventDescription
Examples:
ColorPicker_SessionFancyZones_LayoutAppliedPowerRename_RenameAdvancedPaste_FormatClickedCmdPal_ExtensionInvokedPowerToys uses ETW (Event Tracing for Windows) for telemetry in both C++ and C# modules. The telemetry system is:
Core Components
| File | Purpose |
|---|---|
| ProjectTelemetry.h | Declares the global ETW provider g_hProvider |
| TraceBase.h | Base class with RegisterProvider(), UnregisterProvider(), and IsDataDiagnosticsEnabled() check |
| TraceLoggingDefines.h | Privacy tags and telemetry option group macros |
Create a Trace class inheriting from telemetry::TraceBase (src/common/Telemetry/TraceBase.h):
// trace.h
#pragma once
#include <common/Telemetry/TraceBase.h>
class Trace : public telemetry::TraceBase
{
public:
static void MyEvent(/* parameters */);
};
Implement events using TraceLoggingWriteWrapper:
// trace.cpp
#include "trace.h"
#include <common/Telemetry/TraceBase.h>
TRACELOGGING_DEFINE_PROVIDER(
g_hProvider,
"Microsoft.PowerToys",
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
TraceLoggingOptionProjectTelemetry());
void Trace::MyEvent(bool enabled)
{
TraceLoggingWriteWrapper(
g_hProvider,
"ModuleName_EventName", // Event name
TraceLoggingBoolean(enabled, "Enabled"), // Event data
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
}
Key C++ Telemetry Macros
| Macro | Purpose |
|---|---|
TraceLoggingWriteWrapper CustomAction.cpp | Wraps TraceLoggingWrite with IsDataDiagnosticsEnabled() check |
ProjectTelemetryPrivacyDataTag(tag) TraceLoggingDefines.h | Sets privacy classification |
Core Components
| File | Purpose |
|---|---|
| PowerToysTelemetry.cs | Singleton Log instance with WriteEvent<T>() method |
| EventBase.cs | Base class for all events (provides EventName, Version) |
| IEvent.cs | Interface requiring PartA_PrivTags property |
| TelemetryBase.cs | Inherits from EventSource, defines ETW constants |
| DataDiagnosticsSettings.cs | Registry-based enable/disable check |
Create an event class inheriting from EventBase and implementing IEvent:
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace MyModule.Telemetry
{
[EventData]
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
public class MyModuleEvent : EventBase, IEvent
{
// Event properties (logged as telemetry data)
public string SomeProperty { get; set; }
public int SomeValue { get; set; }
// Required: Privacy tag
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
// Optional: Set EventName in constructor (defaults to class name)
public MyModuleEvent(string prop, int val)
{
EventName = "MyModule_EventName";
SomeProperty = prop;
SomeValue = val;
}
}
}
Log the event:
PowerToysTelemetry.Log.WriteEvent(new MyModuleEvent("value", 42));
Privacy Tags (C#)
| Tag | Use Case |
|---|---|
PartA_PrivTags.ProductAndServiceUsage TelemetryBase.cs | Feature usage events |
PartA_PrivTags.ProductAndServicePerformance TelemetryBase.cs | Performance/timing events |
Add your new event(s) to DATA_AND_PRIVACY.md.
Events do not become active until they ship in a released PowerToys version. After your PRs are merged:
Reach out to @carlos-zamora or @chatasweetie so internal scripts can process new event(s).
Required steps: