<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds a new doc (`doc/devdocs/Events.md`) that walks developers through how to add telemetry events to PowerToys with next steps of reaching out to Carlos or Jessica. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #xxx <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
6.9 KiB
Telemetry Events
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.
Developer Effort Overview (What to Expect)
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:
- Within one PR:
- Add a new telemetry event(s) to module
- Add the new event(s) DATA_AND_PRIVACY.md
- Reach out to @carlos-zamora or @chatasweetie so internal scripts can process new event(s)
Privacy Guidelines
NEVER log:
- User data (text, files, emails, etc.)
- File paths or filenames
- Personal information
- Sensitive system information
- Anything that could identify a specific user
DO log:
- Feature usage (which features, how often)
- Success/failure status
- Timing/performance metrics
- Error types (not error messages with user data)
- Aggregate counts
Event Naming Convention
Follow this pattern: UtilityName_EventDescription
Examples:
ColorPicker_SessionFancyZones_LayoutAppliedPowerRename_RenameAdvancedPaste_FormatClickedCmdPal_ExtensionInvoked
Adding Telemetry Events to PowerToys
PowerToys uses ETW (Event Tracing for Windows) for telemetry in both C++ and C# modules. The telemetry system is:
- Opt-in by default (disabled since v0.86)
- Privacy-focused - never logs personal info, file paths, or user-generated content
- Controlled by registry - HKEY_CURRENT_USER\Software\Classes\PowerToys\AllowDataDiagnostics
C++ Telemetry Implementation
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 |
Pattern for C++ Modules
-
Create a
Traceclass inheriting fromtelemetry::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 |
C# Telemetry Implementation
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 |
Pattern for C# Modules
-
Create an event class inheriting from
EventBaseand implementingIEvent: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 |
Update DATA_AND_PRIVACY.md file
Add your new event(s) to DATA_AND_PRIVACY.md.
Launch Product Version Containing the new events
Events do not become active until they ship in a released PowerToys version. After your PRs are merged:
- The event will begin firing once users install the version that includes it
- In order for PowerToys to process these events, you must complete the next section
Next Steps
Reach out to @carlos-zamora or @chatasweetie so internal scripts can process new event(s).
Summary
Required steps:
- In one PR:
- Add the event(s) in code
- Document event(s) in DATA_AND_PRIVACY.md
- Ship the change in a PowerToys release
- Reach out for next steps