mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-20 01:59:50 +01:00
Compare commits
4 Commits
async-cpp-
...
add-event-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7438d2b98 | ||
|
|
6c05e3966c | ||
|
|
2fb7d92e36 | ||
|
|
1963f3820c |
3
.github/actions/spell-check/expect.txt
vendored
3
.github/actions/spell-check/expect.txt
vendored
@@ -187,6 +187,7 @@ Canvascustomlayout
|
|||||||
CAPTUREBLT
|
CAPTUREBLT
|
||||||
CAPTURECHANGED
|
CAPTURECHANGED
|
||||||
CARETBLINKING
|
CARETBLINKING
|
||||||
|
carlos
|
||||||
Carlseibert
|
Carlseibert
|
||||||
CAtl
|
CAtl
|
||||||
caub
|
caub
|
||||||
@@ -206,6 +207,7 @@ certmgr
|
|||||||
cfp
|
cfp
|
||||||
CHANGECBCHAIN
|
CHANGECBCHAIN
|
||||||
changecursor
|
changecursor
|
||||||
|
chatasweetie
|
||||||
checkmarks
|
checkmarks
|
||||||
CHILDACTIVATE
|
CHILDACTIVATE
|
||||||
CHILDWINDOW
|
CHILDWINDOW
|
||||||
@@ -2146,6 +2148,7 @@ YSpeed
|
|||||||
YStr
|
YStr
|
||||||
YTimer
|
YTimer
|
||||||
YVIRTUALSCREEN
|
YVIRTUALSCREEN
|
||||||
|
zamora
|
||||||
ZEROINIT
|
ZEROINIT
|
||||||
zonability
|
zonability
|
||||||
zonable
|
zonable
|
||||||
|
|||||||
197
doc/devdocs/events.md
Normal file
197
doc/devdocs/events.md
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
# 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
|
||||||
Reference in New Issue
Block a user