[cmdpal] WIP add telemetry (#38032)

Related to https://github.com/microsoft/PowerToys/pull/37908

Closes https://github.com/zadjii-msft/PowerToys/issues/520
---------

Co-authored-by: Mike Griese <migrie@microsoft.com>
This commit is contained in:
Stefan Markovic
2025-03-20 21:36:58 +01:00
committed by GitHub
parent 14919dff10
commit 3e9a6a1e64
16 changed files with 210 additions and 5 deletions

View File

@@ -130,6 +130,7 @@ namespace CommonSharedConstants
// used from quick access window // used from quick access window
const wchar_t CMDPAL_SHOW_EVENT[] = L"Local\\PowerToysCmdPal-ShowEvent-62336fcd-8611-4023-9b30-091a6af4cc5a"; const wchar_t CMDPAL_SHOW_EVENT[] = L"Local\\PowerToysCmdPal-ShowEvent-62336fcd-8611-4023-9b30-091a6af4cc5a";
const wchar_t CMDPAL_EXIT_EVENT[] = L"Local\\PowerToysCmdPal-ExitEvent-eb73f6be-3f22-4b36-aee3-62924ba40bfd";
// Max DWORD for key code to disable keys. // Max DWORD for key code to disable keys.
const DWORD VK_DISABLED = 0x100; const DWORD VK_DISABLED = 0x100;

View File

@@ -10,6 +10,7 @@
#include <common/utils/resources.h> #include <common/utils/resources.h>
#include <common/utils/package.h> #include <common/utils/package.h>
#include <common/utils/process_path.h> #include <common/utils/process_path.h>
#include <common/interop/shared_constants.h>
#include <Psapi.h> #include <Psapi.h>
#include <TlHelp32.h> #include <TlHelp32.h>
#include <common/utils/winapi_error.h> #include <common/utils/winapi_error.h>
@@ -43,6 +44,8 @@ private:
//contains the non localized key of the powertoy //contains the non localized key of the powertoy
std::wstring app_key; std::wstring app_key;
HANDLE m_hTerminateEvent;
void LaunchApp(const std::wstring& appPath, const std::wstring& commandLineArgs, bool elevated) void LaunchApp(const std::wstring& appPath, const std::wstring& commandLineArgs, bool elevated)
{ {
std::wstring dir = std::filesystem::path(appPath).parent_path(); std::wstring dir = std::filesystem::path(appPath).parent_path();
@@ -107,6 +110,11 @@ private:
if (hProcess != NULL) if (hProcess != NULL)
{ {
SetEvent(m_hTerminateEvent);
// Wait for 1.5 seconds for the process to end correctly and stop etw tracer
WaitForSingleObject(hProcess, 1500);
TerminateProcess(hProcess, 0); TerminateProcess(hProcess, 0);
CloseHandle(hProcess); CloseHandle(hProcess);
} }
@@ -119,6 +127,8 @@ public:
app_name = L"CmdPal"; app_name = L"CmdPal";
app_key = L"CmdPal"; app_key = L"CmdPal";
LoggerHelpers::init_logger(app_key, L"ModuleInterface", "CmdPal"); LoggerHelpers::init_logger(app_key, L"ModuleInterface", "CmdPal");
m_hTerminateEvent = CreateDefaultEvent(CommonSharedConstants::CMDPAL_EXIT_EVENT);
} }
~CmdPal() ~CmdPal()

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license. // The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using Microsoft.CmdPal.Common.Helpers;
using Microsoft.CmdPal.Common.Services; using Microsoft.CmdPal.Common.Services;
using Microsoft.CmdPal.Ext.Apps; using Microsoft.CmdPal.Ext.Apps;
using Microsoft.CmdPal.Ext.Bookmarks; using Microsoft.CmdPal.Ext.Bookmarks;
@@ -22,6 +23,7 @@ using Microsoft.CmdPal.UI.ViewModels.BuiltinCommands;
using Microsoft.CmdPal.UI.ViewModels.Models; using Microsoft.CmdPal.UI.ViewModels.Models;
using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
// To learn more about WinUI, the WinUI project structure, // To learn more about WinUI, the WinUI project structure,
@@ -40,6 +42,8 @@ public partial class App : Application
public Window? AppWindow { get; private set; } public Window? AppWindow { get; private set; }
public ETWTrace EtwTrace { get; private set; } = new ETWTrace();
/// <summary> /// <summary>
/// Gets the <see cref="IServiceProvider"/> instance to resolve application services. /// Gets the <see cref="IServiceProvider"/> instance to resolve application services.
/// </summary> /// </summary>
@@ -55,6 +59,13 @@ public partial class App : Application
Services = ConfigureServices(); Services = ConfigureServices();
this.InitializeComponent(); this.InitializeComponent();
NativeEventWaiter.WaitForEventLoop(
"Local\\PowerToysCmdPal-ExitEvent-eb73f6be-3f22-4b36-aee3-62924ba40bfd", () =>
{
EtwTrace?.Dispose();
Environment.Exit(0);
});
} }
/// <summary> /// <summary>

View File

@@ -0,0 +1,16 @@
// 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.
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
public class BeginInvoke : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -0,0 +1,16 @@
// 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.
using System.Diagnostics.Tracing;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
public class CmdPalDismissedOnEsc : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -0,0 +1,16 @@
// 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.
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
public class CmdPalDismissedOnLostFocus : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -0,0 +1,23 @@
// 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.
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
public class CmdPalHotkeySummoned : EventBase, IEvent
{
public bool Global { get; set; }
public CmdPalHotkeySummoned(bool global)
{
Global = global;
}
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -0,0 +1,23 @@
// 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.
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
public class CmdPalInvokeResult : EventBase, IEvent
{
public string ResultKind { get; set; }
public CmdPalInvokeResult(CommandResultKind resultKind)
{
ResultKind = resultKind.ToString();
}
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -0,0 +1,16 @@
// 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.
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
public class CmdPalProcessStarted : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -0,0 +1,16 @@
// 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.
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
public class ColdLaunch : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -0,0 +1,23 @@
// 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.
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
public class OpenPage : EventBase, IEvent
{
public int PageDepth { get; set; }
public OpenPage(int pageDepth)
{
PageDepth = pageDepth;
}
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -0,0 +1,16 @@
// 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.
using System.Diagnostics.Tracing;
using Microsoft.CommandPalette.Extensions;
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.UI.Events;
[EventData]
public class ReactivateInstance : EventBase, IEvent
{
public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
}

View File

@@ -7,9 +7,11 @@ using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Common.Helpers; using Microsoft.CmdPal.Common.Helpers;
using Microsoft.CmdPal.Common.Messages; using Microsoft.CmdPal.Common.Messages;
using Microsoft.CmdPal.Common.Services; using Microsoft.CmdPal.Common.Services;
using Microsoft.CmdPal.UI.Events;
using Microsoft.CmdPal.UI.ViewModels; using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.CmdPal.UI.ViewModels.Messages; using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Composition; using Microsoft.UI.Composition;
using Microsoft.UI.Composition.SystemBackdrops; using Microsoft.UI.Composition.SystemBackdrops;
using Microsoft.UI.Input; using Microsoft.UI.Input;
@@ -368,6 +370,8 @@ public sealed partial class MainWindow : Window,
else else
{ {
PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE); PInvoke.ShowWindow(_hwnd, SHOW_WINDOW_CMD.SW_HIDE);
PowerToysTelemetry.Log.WriteEvent(new CmdPalDismissedOnLostFocus());
} }
} }
@@ -460,6 +464,7 @@ public sealed partial class MainWindow : Window,
{ {
var hotkey = _hotkeys[hotkeyIndex]; var hotkey = _hotkeys[hotkeyIndex];
var isRootHotkey = string.IsNullOrEmpty(hotkey.CommandId); var isRootHotkey = string.IsNullOrEmpty(hotkey.CommandId);
PowerToysTelemetry.Log.WriteEvent(new CmdPalHotkeySummoned(isRootHotkey));
// Note to future us: the wParam will have the index of the hotkey we registered. // Note to future us: the wParam will have the index of the hotkey we registered.
// We can use that in the future to differentiate the hotkeys we've pressed // We can use that in the future to differentiate the hotkeys we've pressed

View File

@@ -90,6 +90,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj" /> <ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.System\Microsoft.CmdPal.Ext.System.csproj" />
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.WebSearch\Microsoft.CmdPal.Ext.WebSearch.csproj" /> <ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.WebSearch\Microsoft.CmdPal.Ext.WebSearch.csproj" />
<ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj" /> <ProjectReference Include="..\Exts\Microsoft.CmdPal.Ext.Indexer\Microsoft.CmdPal.Ext.Indexer.csproj" />

View File

@@ -7,12 +7,14 @@ using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.WinUI; using CommunityToolkit.WinUI;
using ManagedCommon; using ManagedCommon;
using Microsoft.CmdPal.Common.Services; using Microsoft.CmdPal.Common.Services;
using Microsoft.CmdPal.UI.Events;
using Microsoft.CmdPal.UI.Settings; using Microsoft.CmdPal.UI.Settings;
using Microsoft.CmdPal.UI.ViewModels; using Microsoft.CmdPal.UI.ViewModels;
using Microsoft.CmdPal.UI.ViewModels.MainPage; using Microsoft.CmdPal.UI.ViewModels.MainPage;
using Microsoft.CmdPal.UI.ViewModels.Messages; using Microsoft.CmdPal.UI.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Dispatching; using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Animation; using Microsoft.UI.Xaml.Media.Animation;
@@ -91,6 +93,8 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
{ {
// If we can't go back then we must be at the top and thus escape again should quit. // If we can't go back then we must be at the top and thus escape again should quit.
WeakReferenceMessenger.Default.Send<DismissMessage>(); WeakReferenceMessenger.Default.Send<DismissMessage>();
PowerToysTelemetry.Log.WriteEvent(new CmdPalDismissedOnEsc());
} }
} }
} }
@@ -185,6 +189,8 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
pageViewModel, pageViewModel,
message.WithAnimation ? _slideRightTransition : _noAnimation); message.WithAnimation ? _slideRightTransition : _noAnimation);
PowerToysTelemetry.Log.WriteEvent(new OpenPage(RootFrame.BackStackDepth));
// Refocus on the Search for continual typing on the next search request // Refocus on the Search for continual typing on the next search request
SearchBox.Focus(Microsoft.UI.Xaml.FocusState.Programmatic); SearchBox.Focus(Microsoft.UI.Xaml.FocusState.Programmatic);
@@ -201,6 +207,7 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
else if (command is IInvokableCommand invokable) else if (command is IInvokableCommand invokable)
{ {
Logger.LogDebug($"Invoking command"); Logger.LogDebug($"Invoking command");
PowerToysTelemetry.Log.WriteEvent(new BeginInvoke());
HandleInvokeCommand(message, invokable); HandleInvokeCommand(message, invokable);
} }
} }
@@ -317,6 +324,7 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
{ {
var kind = result.Kind; var kind = result.Kind;
Logger.LogDebug($"handling {kind.ToString()}"); Logger.LogDebug($"handling {kind.ToString()}");
PowerToysTelemetry.Log.WriteEvent(new CmdPalInvokeResult(kind));
switch (kind) switch (kind)
{ {
case CommandResultKind.Dismiss: case CommandResultKind.Dismiss:
@@ -344,7 +352,6 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
{ {
// Keep this page open, but hide the palette. // Keep this page open, but hide the palette.
WeakReferenceMessenger.Default.Send<DismissMessage>(); WeakReferenceMessenger.Default.Send<DismissMessage>();
break; break;
} }

View File

@@ -3,6 +3,8 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using ManagedCommon; using ManagedCommon;
using Microsoft.CmdPal.UI.Events;
using Microsoft.PowerToys.Telemetry;
using Microsoft.Windows.AppLifecycle; using Microsoft.Windows.AppLifecycle;
namespace Microsoft.CmdPal.UI; namespace Microsoft.CmdPal.UI;
@@ -30,9 +32,10 @@ internal sealed class Program
Logger.InitializeLogger("\\CmdPal\\Logs\\"); Logger.InitializeLogger("\\CmdPal\\Logs\\");
Logger.LogDebug($"Starting at {DateTime.UtcNow}"); Logger.LogDebug($"Starting at {DateTime.UtcNow}");
PowerToysTelemetry.Log.WriteEvent(new CmdPalProcessStarted());
WinRT.ComWrappersSupport.InitializeComWrappers(); WinRT.ComWrappersSupport.InitializeComWrappers();
bool isRedirect = DecideRedirection(); var isRedirect = DecideRedirection();
if (!isRedirect) if (!isRedirect)
{ {
Microsoft.UI.Xaml.Application.Start((p) => Microsoft.UI.Xaml.Application.Start((p) =>
@@ -48,17 +51,19 @@ internal sealed class Program
private static bool DecideRedirection() private static bool DecideRedirection()
{ {
bool isRedirect = false; var isRedirect = false;
AppActivationArguments args = AppInstance.GetCurrent().GetActivatedEventArgs(); var args = AppInstance.GetCurrent().GetActivatedEventArgs();
AppInstance keyInstance = AppInstance.FindOrRegisterForKey("randomKey"); var keyInstance = AppInstance.FindOrRegisterForKey("randomKey");
if (keyInstance.IsCurrent) if (keyInstance.IsCurrent)
{ {
PowerToysTelemetry.Log.WriteEvent(new ColdLaunch());
keyInstance.Activated += OnActivated; keyInstance.Activated += OnActivated;
} }
else else
{ {
isRedirect = true; isRedirect = true;
PowerToysTelemetry.Log.WriteEvent(new ReactivateInstance());
keyInstance.RedirectActivationToAsync(args).AsTask().ConfigureAwait(false); keyInstance.RedirectActivationToAsync(args).AsTask().ConfigureAwait(false);
} }