/ src / modules / cmdpal / Microsoft.CmdPal.UI / Helpers / TelemetryForwarder.cs
TelemetryForwarder.cs
 1  // Copyright (c) Microsoft Corporation
 2  // The Microsoft Corporation licenses this file to you under the MIT license.
 3  // See the LICENSE file in the project root for more information.
 4  
 5  using CommunityToolkit.Mvvm.Messaging;
 6  using Microsoft.CmdPal.Core.Common.Services;
 7  using Microsoft.CmdPal.Core.ViewModels.Messages;
 8  using Microsoft.CmdPal.UI.Events;
 9  using Microsoft.CommandPalette.Extensions;
10  using Microsoft.PowerToys.Telemetry;
11  
12  namespace Microsoft.CmdPal.UI;
13  
14  /// <summary>
15  /// TelemetryForwarder is responsible for forwarding telemetry events from the
16  /// command palette to PowerToys Telemetry.
17  /// Listens to telemetry-specific messages from the core layer and logs them to PowerToys telemetry.
18  /// Also implements ITelemetryService for dependency injection in extensions.
19  /// </summary>
20  internal sealed class TelemetryForwarder :
21      ITelemetryService,
22      IRecipient<TelemetryBeginInvokeMessage>,
23      IRecipient<TelemetryInvokeResultMessage>,
24      IRecipient<TelemetryExtensionInvokedMessage>
25  {
26      public TelemetryForwarder()
27      {
28          WeakReferenceMessenger.Default.Register<TelemetryBeginInvokeMessage>(this);
29          WeakReferenceMessenger.Default.Register<TelemetryInvokeResultMessage>(this);
30          WeakReferenceMessenger.Default.Register<TelemetryExtensionInvokedMessage>(this);
31      }
32  
33      // Message handlers for telemetry events from core layer
34      public void Receive(TelemetryBeginInvokeMessage message)
35      {
36          PowerToysTelemetry.Log.WriteEvent(new BeginInvoke());
37      }
38  
39      public void Receive(TelemetryInvokeResultMessage message)
40      {
41          PowerToysTelemetry.Log.WriteEvent(new CmdPalInvokeResult(message.Kind));
42      }
43  
44      public void Receive(TelemetryExtensionInvokedMessage message)
45      {
46          PowerToysTelemetry.Log.WriteEvent(new CmdPalExtensionInvoked(
47              message.ExtensionId,
48              message.CommandId,
49              message.CommandName,
50              message.Success,
51              message.ExecutionTimeMs));
52  
53          // Increment session counter for commands executed
54          if (App.Current.AppWindow is MainWindow mainWindow)
55          {
56              mainWindow.IncrementCommandsExecuted();
57          }
58      }
59  
60      // Static method for logging session duration from UI layer
61      public static void LogSessionDuration(
62          ulong durationMs,
63          int commandsExecuted,
64          int pagesVisited,
65          string dismissalReason,
66          int searchQueriesCount,
67          int maxNavigationDepth,
68          int errorCount)
69      {
70          PowerToysTelemetry.Log.WriteEvent(new CmdPalSessionDuration(
71              durationMs,
72              commandsExecuted,
73              pagesVisited,
74              dismissalReason,
75              searchQueriesCount,
76              maxNavigationDepth,
77              errorCount));
78      }
79  
80      // ITelemetryService implementation for dependency injection in extensions
81      public void LogRunQuery(string query, int resultCount, ulong durationMs)
82      {
83          PowerToysTelemetry.Log.WriteEvent(new CmdPalRunQuery(query, resultCount, durationMs));
84      }
85  
86      public void LogRunCommand(string command, bool asAdmin, bool success)
87      {
88          PowerToysTelemetry.Log.WriteEvent(new CmdPalRunCommand(command, asAdmin, success));
89      }
90  
91      public void LogOpenUri(string uri, bool isWeb, bool success)
92      {
93          PowerToysTelemetry.Log.WriteEvent(new CmdPalOpenUri(uri, isWeb, success));
94      }
95  }