mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-15 19:27:56 +01:00
refactor Command Palette telemetry to use telemetry-specific messages. Core layer now sends TelemetryBeginInvokeMessage, TelemetryInvokeResultMessage, and TelemetryExtensionInvokedMessage, which TelemetryForwarder receives and forwards to PowerToys telemetry. Update DATA_AND_PRIVACY for the CmdPal_ExtensionInvoked and CmdPal_SessionDuration
This commit is contained in:
@@ -257,6 +257,23 @@ _If you want to find diagnostic data events in the source code, these two links
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Command Palette
|
||||
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
<th>Event Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPal_ExtensionInvoked</td>
|
||||
<td>Tracks extension usage including extension ID, command details, success status, and execution time.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Microsoft.PowerToys.CmdPal_SessionDuration</td>
|
||||
<td>Logs session metrics from launch to dismissal including duration, commands executed, pages visited, search queries, navigation depth, and errors.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Crop And Lock
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Telemetry message sent when command invocation begins.
|
||||
/// </summary>
|
||||
public record TelemetryBeginInvokeMessage;
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Telemetry message sent when an extension command or page is invoked.
|
||||
/// Captures extension usage metrics for telemetry tracking.
|
||||
/// </summary>
|
||||
public record TelemetryExtensionInvokedMessage(string ExtensionId, string CommandId, string CommandName, bool Success, ulong ExecutionTimeMs);
|
||||
@@ -0,0 +1,10 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
|
||||
/// <summary>
|
||||
/// Telemetry message sent when command invocation completes with a result.
|
||||
/// </summary>
|
||||
public record TelemetryInvokeResultMessage(Microsoft.CommandPalette.Extensions.CommandResultKind Kind);
|
||||
@@ -275,7 +275,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
string extensionId = host.GetExtensionDisplayName() ?? "builtin";
|
||||
string commandId = command?.Id ?? "unknown";
|
||||
string commandName = command?.Name ?? "unknown";
|
||||
WeakReferenceMessenger.Default.Send<ExtensionInvokedMessage>(
|
||||
WeakReferenceMessenger.Default.Send<TelemetryExtensionInvokedMessage>(
|
||||
new(extensionId, commandId, commandName, true, 0));
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
{
|
||||
CoreLogger.LogDebug($"Invoking command");
|
||||
|
||||
WeakReferenceMessenger.Default.Send<BeginInvokeMessage>();
|
||||
WeakReferenceMessenger.Default.Send<TelemetryBeginInvokeMessage>();
|
||||
StartInvoke(message, invokable, host);
|
||||
}
|
||||
}
|
||||
@@ -385,7 +385,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
{
|
||||
// Telemetry: Send extension invocation metrics (always sent, even on failure)
|
||||
stopwatch.Stop();
|
||||
WeakReferenceMessenger.Default.Send<ExtensionInvokedMessage>(
|
||||
WeakReferenceMessenger.Default.Send<TelemetryExtensionInvokedMessage>(
|
||||
new(extensionId, commandId, commandName, success, (ulong)stopwatch.ElapsedMilliseconds));
|
||||
}
|
||||
}
|
||||
@@ -401,7 +401,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
var kind = result.Kind;
|
||||
CoreLogger.LogDebug($"handling {kind.ToString()}");
|
||||
|
||||
WeakReferenceMessenger.Default.Send<CmdPalInvokeResultMessage>(new(kind));
|
||||
WeakReferenceMessenger.Default.Send<TelemetryInvokeResultMessage>(new(kind));
|
||||
switch (kind)
|
||||
{
|
||||
case CommandResultKind.Dismiss:
|
||||
|
||||
@@ -18,6 +18,7 @@ public class CmdPalInvokeResult : EventBase, IEvent
|
||||
|
||||
public CmdPalInvokeResult(CommandResultKind resultKind)
|
||||
{
|
||||
EventName = "CmdPal_InvokeResult";
|
||||
ResultKind = resultKind.ToString();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,45 +6,42 @@ using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.CmdPal.Core.Common.Services;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Messages;
|
||||
using Microsoft.CmdPal.UI.Events;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
|
||||
namespace Microsoft.CmdPal.UI;
|
||||
|
||||
/// <summary>
|
||||
/// TelemetryForwarder is responsible for forwarding telemetry events from the
|
||||
/// command palette core to PowerToys Telemetry.
|
||||
/// This allows us to emit telemetry events as messages from the core,
|
||||
/// and then handle them by logging to our PT telemetry provider.
|
||||
///
|
||||
/// We may in the future want to replace this with a more generic "ITelemetryService"
|
||||
/// or something similar, but this works for now.
|
||||
/// command palette to PowerToys Telemetry.
|
||||
/// Listens to telemetry-specific messages from the core layer and logs them to PowerToys telemetry.
|
||||
/// Also implements ITelemetryService for dependency injection in extensions.
|
||||
/// </summary>
|
||||
internal sealed class TelemetryForwarder :
|
||||
ITelemetryService,
|
||||
IRecipient<BeginInvokeMessage>,
|
||||
IRecipient<CmdPalInvokeResultMessage>,
|
||||
IRecipient<ExtensionInvokedMessage>,
|
||||
IRecipient<SessionDurationMessage>
|
||||
IRecipient<TelemetryBeginInvokeMessage>,
|
||||
IRecipient<TelemetryInvokeResultMessage>,
|
||||
IRecipient<TelemetryExtensionInvokedMessage>
|
||||
{
|
||||
public TelemetryForwarder()
|
||||
{
|
||||
WeakReferenceMessenger.Default.Register<BeginInvokeMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<CmdPalInvokeResultMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<ExtensionInvokedMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<SessionDurationMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<TelemetryBeginInvokeMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<TelemetryInvokeResultMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<TelemetryExtensionInvokedMessage>(this);
|
||||
}
|
||||
|
||||
public void Receive(CmdPalInvokeResultMessage message)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalInvokeResult(message.Kind));
|
||||
}
|
||||
|
||||
public void Receive(BeginInvokeMessage message)
|
||||
// Message handlers for telemetry events from core layer
|
||||
public void Receive(TelemetryBeginInvokeMessage message)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new BeginInvoke());
|
||||
}
|
||||
|
||||
public void Receive(ExtensionInvokedMessage message)
|
||||
public void Receive(TelemetryInvokeResultMessage message)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalInvokeResult(message.Kind));
|
||||
}
|
||||
|
||||
public void Receive(TelemetryExtensionInvokedMessage message)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalExtensionInvoked(
|
||||
message.ExtensionId,
|
||||
@@ -52,20 +49,35 @@ internal sealed class TelemetryForwarder :
|
||||
message.CommandName,
|
||||
message.Success,
|
||||
message.ExecutionTimeMs));
|
||||
|
||||
// Increment session counter for commands executed
|
||||
if (App.Current.AppWindow is MainWindow mainWindow)
|
||||
{
|
||||
mainWindow.IncrementCommandsExecuted();
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(SessionDurationMessage message)
|
||||
// Static method for logging session duration from UI layer
|
||||
public static void LogSessionDuration(
|
||||
ulong durationMs,
|
||||
int commandsExecuted,
|
||||
int pagesVisited,
|
||||
string dismissalReason,
|
||||
int searchQueriesCount,
|
||||
int maxNavigationDepth,
|
||||
int errorCount)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalSessionDuration(
|
||||
message.DurationMs,
|
||||
message.CommandsExecuted,
|
||||
message.PagesVisited,
|
||||
message.DismissalReason,
|
||||
message.SearchQueriesCount,
|
||||
message.MaxNavigationDepth,
|
||||
message.ErrorCount));
|
||||
durationMs,
|
||||
commandsExecuted,
|
||||
pagesVisited,
|
||||
dismissalReason,
|
||||
searchQueriesCount,
|
||||
maxNavigationDepth,
|
||||
errorCount));
|
||||
}
|
||||
|
||||
// ITelemetryService implementation for dependency injection in extensions
|
||||
public void LogRunQuery(string query, int resultCount, ulong durationMs)
|
||||
{
|
||||
PowerToysTelemetry.Log.WriteEvent(new CmdPalRunQuery(query, resultCount, durationMs));
|
||||
|
||||
@@ -49,7 +49,6 @@ public sealed partial class MainWindow : WindowEx,
|
||||
IRecipient<ShowWindowMessage>,
|
||||
IRecipient<HideWindowMessage>,
|
||||
IRecipient<QuitMessage>,
|
||||
IRecipient<ExtensionInvokedMessage>,
|
||||
IRecipient<NavigateToPageMessage>,
|
||||
IRecipient<NavigationDepthMessage>,
|
||||
IRecipient<SearchQueryMessage>,
|
||||
@@ -113,7 +112,6 @@ public sealed partial class MainWindow : WindowEx,
|
||||
WeakReferenceMessenger.Default.Register<QuitMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<ShowWindowMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<HideWindowMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<ExtensionInvokedMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigateToPageMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<NavigationDepthMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<SearchQueryMessage>(this);
|
||||
@@ -537,12 +535,6 @@ public sealed partial class MainWindow : WindowEx,
|
||||
|
||||
// Session telemetry: Track metrics during the Command Palette session
|
||||
// These receivers increment counters that are sent when EndSession is called
|
||||
|
||||
public void Receive(ExtensionInvokedMessage message)
|
||||
{
|
||||
_sessionCommandsExecuted++;
|
||||
}
|
||||
|
||||
public void Receive(NavigateToPageMessage message)
|
||||
{
|
||||
_sessionPagesVisited++;
|
||||
@@ -576,18 +568,27 @@ public sealed partial class MainWindow : WindowEx,
|
||||
if (_sessionStopwatch is not null)
|
||||
{
|
||||
_sessionStopwatch.Stop();
|
||||
WeakReferenceMessenger.Default.Send<SessionDurationMessage>(new(
|
||||
TelemetryForwarder.LogSessionDuration(
|
||||
(ulong)_sessionStopwatch.ElapsedMilliseconds,
|
||||
_sessionCommandsExecuted,
|
||||
_sessionPagesVisited,
|
||||
dismissalReason,
|
||||
_sessionSearchQueriesCount,
|
||||
_sessionMaxNavigationDepth,
|
||||
_sessionErrorCount));
|
||||
_sessionErrorCount);
|
||||
_sessionStopwatch = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Increments the session commands executed counter for telemetry.
|
||||
/// Called by TelemetryForwarder when an extension command is invoked.
|
||||
/// </summary>
|
||||
internal void IncrementCommandsExecuted()
|
||||
{
|
||||
_sessionCommandsExecuted++;
|
||||
}
|
||||
|
||||
private void HideWindow()
|
||||
{
|
||||
// Cloak our HWND to avoid all animations.
|
||||
|
||||
Reference in New Issue
Block a user