mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-23 19:49:43 +01:00
<!-- 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
198 lines
6.9 KiB
Markdown
198 lines
6.9 KiB
Markdown
# 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:
|
||
|
||
1. Within one PR:
|
||
1. Add a new telemetry event(s) to module
|
||
1. Add the new event(s) DATA_AND_PRIVACY.md
|
||
1. 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_Session`
|
||
- `FancyZones_LayoutApplied`
|
||
- `PowerRename_Rename`
|
||
- `AdvancedPaste_FormatClicked`
|
||
- `CmdPal_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](../../src/common/Telemetry/ProjectTelemetry.h) | Declares the global ETW provider g_hProvider |
|
||
| [TraceBase.h](../../src/common/Telemetry/TraceBase.h) | Base class with RegisterProvider(), UnregisterProvider(), and IsDataDiagnosticsEnabled() check |
|
||
| [TraceLoggingDefines.h](../../src/common/Telemetry/TraceLoggingDefines.h) | Privacy tags and telemetry option group macros
|
||
|
||
|
||
#### Pattern for C++ Modules
|
||
|
||
1. Create a `Trace` class inheriting from `telemetry::TraceBase` (src/common/Telemetry/TraceBase.h):
|
||
|
||
```c
|
||
// trace.h
|
||
#pragma once
|
||
#include <common/Telemetry/TraceBase.h>
|
||
|
||
class Trace : public telemetry::TraceBase
|
||
{
|
||
public:
|
||
static void MyEvent(/* parameters */);
|
||
};
|
||
```
|
||
|
||
2. Implement events using `TraceLoggingWriteWrapper`:
|
||
|
||
```cpp
|
||
// 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](../../installer/PowerToysSetupCustomActionsVNext/CustomAction.cpp) | Wraps `TraceLoggingWrite` with `IsDataDiagnosticsEnabled()` check |
|
||
| `ProjectTelemetryPrivacyDataTag(tag)` [TraceLoggingDefines.h](../../src/common/Telemetry/TraceLoggingDefines.h) | Sets privacy classification |
|
||
|
||
### C# Telemetry Implementation
|
||
|
||
**Core Components**
|
||
|
||
| File | Purpose |
|
||
| ------------- |:-------------:|
|
||
| [PowerToysTelemetry.cs](../../src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs) | Singleton `Log` instance with `WriteEvent<T>()` method |
|
||
| [EventBase.cs](../../src/common/ManagedTelemetry/Telemetry/Events/EventBase.cs) | Base class for all events (provides `EventName`, `Version`) |
|
||
| [IEvent.cs](../../src/common/ManagedTelemetry/Telemetry/Events/IEvent.cs) | Interface requiring `PartA_PrivTags` property |
|
||
| [TelemetryBase.cs](../../src/common/Telemetry/TelemetryBase.cs) | Inherits from `EventSource`, defines ETW constants |
|
||
| [DataDiagnosticsSettings.cs](../../src/common/ManagedTelemetry/Telemetry/DataDiagnosticsSettings.cs) | Registry-based enable/disable check
|
||
|
||
#### Pattern for C# Modules
|
||
|
||
1. Create an event class inheriting from `EventBase` and implementing `IEvent`:
|
||
|
||
```csharp
|
||
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;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
2. Log the event:
|
||
|
||
```csharp
|
||
PowerToysTelemetry.Log.WriteEvent(new MyModuleEvent("value", 42));
|
||
```
|
||
|
||
**Privacy Tags (C#)**
|
||
|
||
| Tag | Use Case |
|
||
| ------------- |:-------------:|
|
||
| `PartA_PrivTags.ProductAndServiceUsage` [TelemetryBase.cs](../../src/common/Telemetry/TelemetryBase.cs) | Feature usage events
|
||
| `PartA_PrivTags.ProductAndServicePerformance` [TelemetryBase.cs](../../src/common/Telemetry/TelemetryBase.cs) | Performance/timing events
|
||
|
||
### Update DATA_AND_PRIVACY.md file
|
||
|
||
Add your new event(s) to [DATA_AND_PRIVACY.md](../../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:
|
||
|
||
1. In one PR:
|
||
- Add the event(s) in code
|
||
- Document event(s) in DATA_AND_PRIVACY.md
|
||
1. Ship the change in a PowerToys release
|
||
1. Reach out for next steps
|