mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-07 19:57:07 +02:00
CmdPal: GEH per partes; part 1: error report builder, sanitizer and internals tools setting page (#44140)
<!-- 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 This PR adds three parts of the original big bad global error handler (error report builder, sanitization and internal tools UI). ### Error Report Generation - `ErrorReportBuilder`: Produces a detailed, technical report with system context. - Comprehensive data: OS version, architecture, culture, app version, elevation status, etc. - Exception analysis: Coalesces nested exception messages and HRESULT details for clearer diagnostics. <details><summary>Example</summary> <pre> This is an error report generated by Windows Command Palette. If you are seeing this, it means something went a little sideways in the app. You can help us fix it by filing a report at https://aka.ms/powerToysReportBug. (While you’re at it, give the details below a quick skim — just to make sure there’s nothing personal you’d prefer not to share. It’s rare, but sometimes little surprises sneak in.) ============================================================ Summary: Message: Test exception; thrown from the UI thread Type: System.NotImplementedException Source: Microsoft.CmdPal.UI Time: 2025-08-25 18:54:44.3854569 HRESULT: 0x80004001 (-2147467263) Context: MainThreadException Application: App version: 0.0.1.0 Is elevated: no Environment: OS version: Microsoft Windows 10.0.26120 OS architecture: X64 Runtime identifier: win-x64 Framework: .NET 9.0.8 Process architecture: X64 Culture: cs-CZ UI culture: en-US Stack Trace: at Microsoft.CmdPal.UI.Settings.InternalPage.ThrowPlainMainThreadException_Click(Object sender, RoutedEventArgs e) at WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.<GetEventInvoke>b__1_0(Object sender, RoutedEventArgs e) at ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e) ------------------ Full Exception Details ------------------ System.NotImplementedException: Test exception; thrown from the UI thread at Microsoft.CmdPal.UI.Settings.InternalPage.ThrowPlainMainThreadException_Click(Object sender, RoutedEventArgs e) at WinRT._EventSource_global__Microsoft_UI_Xaml_RoutedEventHandler.EventState.<GetEventInvoke>b__1_0(Object sender, RoutedEventArgs e) at ABI.Microsoft.UI.Xaml.RoutedEventHandler.Do_Abi_Invoke(IntPtr thisPtr, IntPtr sender, IntPtr e) ============================================================ </pre> </details> Real-world example: #41362 ### PII Sanitization Framework - `ErrorReportSanitizer`: Multi-layer sanitization pipeline for sensitive data. - Nine specialized rule providers: - `PiiRuleProvider`: Personally identifiable information (emails, phone numbers, SSNs). - `ProfilePathAndUsernameRuleProvider`: Windows user profiles and usernames. - `NetworkRuleProvider`: IP addresses, MAC addresses, network identifiers. - `SecretKeyValueRulesProvider`: API keys, tokens, passwords in key/value formats. - `FilenameMaskRuleProvider`: Sensitive file paths and extensions. - `UrlRuleProvider`: URLs and web addresses. - `TokenRuleProvider`: JWT and other auth tokens. - `ConnectionStringRuleProvider`: Database connection strings. - `EnvironmentPropertiesRuleProvider`: Environment variables and system properties. ### Internals Tools Page A page in settings available in non-CI-builds: <img width="1305" height="745" alt="image" src="https://github.com/user-attachments/assets/3145ecfd-997f-491d-8c8a-6096634b6045" /> <!-- 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
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Core.Common.Helpers;
|
||||
using Microsoft.CmdPal.Core.Common.Services.Reports;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.UI.WindowsAndMessaging;
|
||||
@@ -15,14 +15,22 @@ namespace Microsoft.CmdPal.UI.Helpers;
|
||||
/// <summary>
|
||||
/// Global error handler for Command Palette.
|
||||
/// </summary>
|
||||
internal sealed partial class GlobalErrorHandler
|
||||
internal sealed partial class GlobalErrorHandler : IDisposable
|
||||
{
|
||||
private readonly ErrorReportBuilder _errorReportBuilder = new();
|
||||
private Options? _options;
|
||||
private App? _app;
|
||||
|
||||
// GlobalErrorHandler is designed to be self-contained; it can be registered and invoked before a service provider is available.
|
||||
internal void Register(App app)
|
||||
internal void Register(App app, Options options)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(app);
|
||||
ArgumentNullException.ThrowIfNull(options);
|
||||
|
||||
app.UnhandledException += App_UnhandledException;
|
||||
_options = options;
|
||||
|
||||
_app = app;
|
||||
_app.UnhandledException += App_UnhandledException;
|
||||
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
}
|
||||
@@ -54,21 +62,15 @@ internal sealed partial class GlobalErrorHandler
|
||||
HandleException(e.Exception, Context.UnobservedTaskException);
|
||||
}
|
||||
|
||||
private static void HandleException(Exception ex, Context context)
|
||||
private void HandleException(Exception ex, Context context)
|
||||
{
|
||||
Logger.LogError($"Unhandled exception detected ({context})", ex);
|
||||
|
||||
if (context == Context.MainThreadException)
|
||||
{
|
||||
var error = DiagnosticsHelper.BuildExceptionMessage(ex, null);
|
||||
var report = $"""
|
||||
This is an error report generated by Windows Command Palette.
|
||||
If you are seeing this message, it means the application has encountered an unexpected issue.
|
||||
You can help us fix it by filing a report at https://aka.ms/powerToysReportBug.
|
||||
{error}
|
||||
""";
|
||||
var report = _errorReportBuilder.BuildReport(ex, context.ToString(), _options?.RedactPii ?? true);
|
||||
|
||||
StoreReport(report, storeOnDesktop: false);
|
||||
StoreReport(report, storeOnDesktop: _options?.StoreReportOnUserDesktop == true);
|
||||
|
||||
string message;
|
||||
string caption;
|
||||
@@ -138,6 +140,13 @@ internal sealed partial class GlobalErrorHandler
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_app?.UnhandledException -= App_UnhandledException;
|
||||
TaskScheduler.UnobservedTaskException -= TaskScheduler_UnobservedTaskException;
|
||||
AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
|
||||
}
|
||||
|
||||
private enum Context
|
||||
{
|
||||
Unknown = 0,
|
||||
@@ -146,4 +155,26 @@ internal sealed partial class GlobalErrorHandler
|
||||
UnobservedTaskException,
|
||||
AppDomainUnhandledException,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration options controlling how <see cref="GlobalErrorHandler"/> reacts to exceptions
|
||||
/// (what to log, what to show to the user, and where to store reports).
|
||||
/// </summary>
|
||||
internal sealed record Options
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the default configuration.
|
||||
/// </summary>
|
||||
public static Options Default { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether Personally Identifiable Information (PII) should be redacted in error reports.
|
||||
/// </summary>
|
||||
public bool RedactPii { get; init; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to store the error report on the user's desktop in addition to the log directory.
|
||||
/// </summary>
|
||||
public bool StoreReportOnUserDesktop { get; init; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ internal sealed partial class TrayIconService
|
||||
{
|
||||
if (wParam == PInvoke.WM_USER + 1)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<OpenSettingsMessage>();
|
||||
WeakReferenceMessenger.Default.Send(new OpenSettingsMessage());
|
||||
}
|
||||
else if (wParam == PInvoke.WM_USER + 2)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user