From 54753561897a7626c130834862f7b10c0bca1576 Mon Sep 17 00:00:00 2001 From: Stefan Markovic Date: Mon, 12 Aug 2024 10:56:44 +0200 Subject: [PATCH] WIP5 - services --- Directory.Packages.props | 1 + .../Telemetry/DataDiagnosticsSettings.cs} | 18 +-- .../ManagedTelemetry/Telemetry/EtwTrace.cs | 131 ++++++++++++++++++ .../Telemetry/ManagedTelemetry.csproj | 4 + .../Telemetry/PowerToysTelemetry.cs | 27 +--- .../Settings.UI/SettingsXAML/App.xaml.cs | 1 + .../SettingsXAML/MainWindow.xaml.cs | 4 + .../OOBE/Views/OobeOverview.xaml.cs | 7 +- .../OOBE/Views/OobeWhatsNew.xaml.cs | 15 +- .../ViewModels/GeneralViewModel.cs | 12 +- 10 files changed, 165 insertions(+), 55 deletions(-) rename src/{settings-ui/Settings.UI/Helpers/DataDiagnostics.cs => common/ManagedTelemetry/Telemetry/DataDiagnosticsSettings.cs} (82%) create mode 100644 src/common/ManagedTelemetry/Telemetry/EtwTrace.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index bbf98c9616cd..d62727f57833 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -26,6 +26,7 @@ + diff --git a/src/settings-ui/Settings.UI/Helpers/DataDiagnostics.cs b/src/common/ManagedTelemetry/Telemetry/DataDiagnosticsSettings.cs similarity index 82% rename from src/settings-ui/Settings.UI/Helpers/DataDiagnostics.cs rename to src/common/ManagedTelemetry/Telemetry/DataDiagnosticsSettings.cs index 6e6314757c0b..0a9aa7c89175 100644 --- a/src/settings-ui/Settings.UI/Helpers/DataDiagnostics.cs +++ b/src/common/ManagedTelemetry/Telemetry/DataDiagnosticsSettings.cs @@ -3,19 +3,18 @@ // See the LICENSE file in the project root for more information. using System; -using ManagedCommon; using Microsoft.Win32; -namespace Microsoft.PowerToys.Settings.Helpers +namespace Microsoft.PowerToys.Telemetry { - public static class DataDiagnostics + public static class DataDiagnosticsSettings { private static readonly string DataDiagnosticsRegistryKey = @"HKEY_CURRENT_USER\Software\Classes\PowerToys\"; private static readonly string DataDiagnosticsRegistryValueName = @"AllowDataDiagnostics"; private static readonly string DataDiagnosticsDataDiagnosticsUserActionRegistryValueName = @"DataDiagnosticsUserAction"; private static readonly string DataDiagnosticsDataDiagnosticsViewDataRegistryValueName = @"DataDiagnosticsViewEnabled"; - public static bool GetValue() + public static bool GetEnabledValue() { object registryValue = null; try @@ -34,15 +33,14 @@ public static bool GetValue() return false; } - public static void SetValue(bool value) + public static void SetEnabledValue(bool value) { try { Registry.SetValue(DataDiagnosticsRegistryKey, DataDiagnosticsRegistryValueName, value ? 1 : 0); } - catch (Exception ex) + catch (Exception) { - Logger.LogError($"Failed to set the Data Diagnostics value in the registry: {ex.Message}"); } } @@ -71,9 +69,8 @@ public static void SetUserActionValue(bool value) { Registry.SetValue(DataDiagnosticsRegistryKey, DataDiagnosticsDataDiagnosticsUserActionRegistryValueName, value ? 1 : 0); } - catch (Exception ex) + catch (Exception) { - Logger.LogError($"Failed to set the Data Diagnostics user action value in the registry: {ex.Message}"); } } @@ -102,9 +99,8 @@ public static void SetViewEnabledValue(bool value) { Registry.SetValue(DataDiagnosticsRegistryKey, DataDiagnosticsDataDiagnosticsViewDataRegistryValueName, value ? 1 : 0); } - catch (Exception ex) + catch (Exception) { - Logger.LogError($"Failed to set the Data Diagnostics view enabled value in the registry: {ex.Message}"); } } } diff --git a/src/common/ManagedTelemetry/Telemetry/EtwTrace.cs b/src/common/ManagedTelemetry/Telemetry/EtwTrace.cs new file mode 100644 index 000000000000..320c937bf809 --- /dev/null +++ b/src/common/ManagedTelemetry/Telemetry/EtwTrace.cs @@ -0,0 +1,131 @@ +// 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; +using System.Diagnostics; +using System.Diagnostics.Tracing; +using System.Globalization; +using System.IO; +using Microsoft.Diagnostics.Tracing.Session; +using Microsoft.PowerToys.Telemetry; + +namespace WSACrashHelper +{ + /// + /// This class is based loosely on the C++ ETWTrace class in Win32client/Framework project. + /// It is intended to record telemetry events generated by the WSACrashUploader so that end users + /// can view them if they want. + /// + public class ETWTrace : IDisposable + { + internal const EventKeywords TelemetryKeyword = (EventKeywords)0x0000200000000000; + internal const EventKeywords MeasuresKeyword = (EventKeywords)0x0000400000000000; + internal const EventKeywords CriticalDataKeyword = (EventKeywords)0x0000800000000000; + + private readonly bool telemetryEnabled = DataDiagnosticsSettings.GetEnabledValue(); // This is the global telemetry setting on whether to log events + private readonly bool telemetryRecordingEnabled = DataDiagnosticsSettings.GetViewEnabledValue(); // This is the setting for recording telemetry events to disk for vewng + private readonly string etwFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"Microsoft\PowerToys\", "etw"); + private bool disposedValue; + private string sessionName; + private string etwFilePath; + private bool started; +#nullable enable + private TraceEventSession? traceSession; +#nullable disable + + /// + /// Initializes a new instance of the class. + /// + public ETWTrace() + { + if (File.Exists(etwFolderPath)) + { + File.Delete(etwFolderPath); + } + + if (!Directory.Exists(etwFolderPath)) + { + Directory.CreateDirectory(etwFolderPath); + } + + if (this.telemetryEnabled && this.telemetryRecordingEnabled) + { + this.Start(); + } + } + + /// + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + this.Dispose(disposing: true); + GC.SuppressFinalize(this); + } + + /// + /// Starts the trace session. + /// + public void Start() + { + lock (this) + { + if (this.started) + { + return; + } + + string executable = Process.GetCurrentProcess().ProcessName; + string dateTimeNow = DateTime.Now.ToString("MM-d-yyy__H_mm_ss", CultureInfo.InvariantCulture); + this.sessionName = string.Format(CultureInfo.InvariantCulture, "{0}-{1}-{2}", executable, Environment.ProcessId, dateTimeNow); + this.etwFilePath = Path.Combine(etwFolderPath, $"{this.sessionName}.etl"); + this.traceSession = new TraceEventSession( + this.sessionName, this.etwFilePath, (TraceEventSessionOptions)(1 | 0x10 | 0x20)); + this.traceSession.EnableProvider( + PowerToysTelemetry.Log.Guid, + matchAnyKeywords: (ulong)TelemetryKeyword | (ulong)MeasuresKeyword | (ulong)CriticalDataKeyword); + + this.started = true; + } + } + + /// + /// Stops the trace session. + /// + public void Stop() + { + lock (this) + { + if (!this.started) + { + return; + } + + if (this.traceSession != null) + { + Trace.TraceInformation("Disposing EventTraceSession"); + this.traceSession.Dispose(); + this.traceSession = null; + this.started = false; + } + } + } + + /// + /// Disposes the object. + /// + /// boolean for disposing. + protected virtual void Dispose(bool disposing) + { + if (!this.disposedValue) + { + if (disposing) + { + this.Stop(); + } + + this.disposedValue = true; + } + } + } +} diff --git a/src/common/ManagedTelemetry/Telemetry/ManagedTelemetry.csproj b/src/common/ManagedTelemetry/Telemetry/ManagedTelemetry.csproj index 81d658b4e194..0cae3fe2e6cc 100644 --- a/src/common/ManagedTelemetry/Telemetry/ManagedTelemetry.csproj +++ b/src/common/ManagedTelemetry/Telemetry/ManagedTelemetry.csproj @@ -10,4 +10,8 @@ + + + + \ No newline at end of file diff --git a/src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs b/src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs index 0be07c60938a..efdc82198cc7 100644 --- a/src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs +++ b/src/common/ManagedTelemetry/Telemetry/PowerToysTelemetry.cs @@ -2,21 +2,17 @@ // 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; using System.Diagnostics.Tracing; using Microsoft.PowerToys.Telemetry.Events; -using Microsoft.Win32; namespace Microsoft.PowerToys.Telemetry { /// /// Telemetry helper class for PowerToys. /// + [EventSource(Name = "Microsoft.PowerToys")] public class PowerToysTelemetry : TelemetryBase { - private static readonly string DataDiagnosticsRegistryKey = @"HKEY_CURRENT_USER\Software\Classes\PowerToys\"; - private static readonly string DataDiagnosticsRegistryValueName = @"AllowDataDiagnostics"; - /// /// Name for ETW event. /// @@ -35,32 +31,13 @@ public PowerToysTelemetry() /// public static PowerToysTelemetry Log { get; } = new PowerToysTelemetry(); - private static bool IsDataDiagnosticsEnabled() - { - object registryValue = null; - try - { - registryValue = Registry.GetValue(DataDiagnosticsRegistryKey, DataDiagnosticsRegistryValueName, 0); - } - catch - { - } - - if (registryValue is not null) - { - return (int)registryValue == 1 ? true : false; - } - - return false; - } - /// /// Publishes ETW event when an action is triggered on /// public void WriteEvent(T telemetryEvent) where T : EventBase, IEvent { - if (IsDataDiagnosticsEnabled()) + if (DataDiagnosticsSettings.GetEnabledValue()) { this.Write( telemetryEvent.EventName, diff --git a/src/settings-ui/Settings.UI/SettingsXAML/App.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/App.xaml.cs index 8d367853b925..775c84523cfa 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/App.xaml.cs +++ b/src/settings-ui/Settings.UI/SettingsXAML/App.xaml.cs @@ -21,6 +21,7 @@ using Windows.UI.Popups; using WinRT.Interop; using WinUIEx; +using WSACrashHelper; namespace Microsoft.PowerToys.Settings.UI { diff --git a/src/settings-ui/Settings.UI/SettingsXAML/MainWindow.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/MainWindow.xaml.cs index c665e3a21ad6..a27e43378060 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/MainWindow.xaml.cs +++ b/src/settings-ui/Settings.UI/SettingsXAML/MainWindow.xaml.cs @@ -14,6 +14,7 @@ using Microsoft.UI.Xaml; using Windows.Data.Json; using WinUIEx; +using WSACrashHelper; namespace Microsoft.PowerToys.Settings.UI { @@ -22,6 +23,8 @@ namespace Microsoft.PowerToys.Settings.UI /// public sealed partial class MainWindow : WindowEx { + private static ETWTrace etwTrace = new ETWTrace(); + public MainWindow(bool createHidden = false) { var bootTime = new System.Diagnostics.Stopwatch(); @@ -217,6 +220,7 @@ private void Window_Closed(object sender, WindowEventArgs args) NativeMethods.ShowWindow(hWnd, NativeMethods.SW_HIDE); } + etwTrace.Dispose(); App.ThemeService.ThemeChanged -= OnThemeChanged; } diff --git a/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeOverview.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeOverview.xaml.cs index d6e0fed10262..bf0197418572 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeOverview.xaml.cs +++ b/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeOverview.xaml.cs @@ -3,11 +3,10 @@ // See the LICENSE file in the project root for more information. using global::PowerToys.GPOWrapper; -using Microsoft.PowerToys.Settings.Helpers; -using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.OOBE.Enums; using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; using Microsoft.PowerToys.Settings.UI.Views; +using Microsoft.PowerToys.Telemetry; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Navigation; @@ -32,7 +31,7 @@ public bool EnableDataDiagnostics { _enableDataDiagnostics = value; - DataDiagnostics.SetValue(_enableDataDiagnostics); + DataDiagnosticsSettings.SetEnabledValue(_enableDataDiagnostics); this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => { @@ -55,7 +54,7 @@ public OobeOverview() { this.InitializeComponent(); - _enableDataDiagnostics = DataDiagnostics.GetValue(); + _enableDataDiagnostics = DataDiagnosticsSettings.GetEnabledValue(); ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.Overview]); DataContext = ViewModel; diff --git a/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeWhatsNew.xaml.cs b/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeWhatsNew.xaml.cs index 622385041ca2..eeabe349477c 100644 --- a/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeWhatsNew.xaml.cs +++ b/src/settings-ui/Settings.UI/SettingsXAML/OOBE/Views/OobeWhatsNew.xaml.cs @@ -16,16 +16,13 @@ using CommunityToolkit.WinUI.UI.Controls; using global::PowerToys.GPOWrapper; using ManagedCommon; -using Microsoft.PowerToys.Settings.Helpers; using Microsoft.PowerToys.Settings.UI.Helpers; -using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.OOBE.Enums; using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel; using Microsoft.PowerToys.Settings.UI.Views; +using Microsoft.PowerToys.Telemetry; using Microsoft.UI.Xaml.Controls; -using Microsoft.UI.Xaml.Documents; using Microsoft.UI.Xaml.Navigation; -using Microsoft.Win32; namespace Microsoft.PowerToys.Settings.UI.OOBE.Views { @@ -70,14 +67,14 @@ private bool GetShowDataDiagnosticsInfoBar() return false; } - bool userActed = DataDiagnostics.GetUserActionValue(); + bool userActed = DataDiagnosticsSettings.GetUserActionValue(); if (userActed) { return false; } - bool registryValue = DataDiagnostics.GetValue(); + bool registryValue = DataDiagnosticsSettings.GetEnabledValue(); bool isFirstRunAfterUpdate = (App.Current as Microsoft.PowerToys.Settings.UI.App).ShowScoobe; if (isFirstRunAfterUpdate && registryValue == false) @@ -237,14 +234,14 @@ private void DataDiagnostics_InfoBar_YesNo_Click(object sender, Microsoft.UI.Xam // Set Data Diagnostics registry values if (commandArg == "Yes") { - DataDiagnostics.SetValue(true); + DataDiagnosticsSettings.SetEnabledValue(true); } else { - DataDiagnostics.SetValue(false); + DataDiagnosticsSettings.SetEnabledValue(false); } - DataDiagnostics.SetUserActionValue(true); + DataDiagnosticsSettings.SetUserActionValue(true); this.DispatcherQueue.TryEnqueue(Microsoft.UI.Dispatching.DispatcherQueuePriority.Normal, () => { diff --git a/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs index df9b8a44a806..aa361805b7a0 100644 --- a/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs +++ b/src/settings-ui/Settings.UI/ViewModels/GeneralViewModel.cs @@ -13,12 +13,12 @@ using System.Threading.Tasks; using global::PowerToys.GPOWrapper; using ManagedCommon; -using Microsoft.PowerToys.Settings.Helpers; using Microsoft.PowerToys.Settings.UI.Library; using Microsoft.PowerToys.Settings.UI.Library.Helpers; using Microsoft.PowerToys.Settings.UI.Library.Interfaces; using Microsoft.PowerToys.Settings.UI.Library.Utilities; using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands; +using Microsoft.PowerToys.Telemetry; namespace Microsoft.PowerToys.Settings.UI.ViewModels { @@ -149,10 +149,10 @@ public GeneralViewModel(ISettingsRepository settingsRepository, } else { - _enableDataDiagnostics = DataDiagnostics.GetValue(); + _enableDataDiagnostics = DataDiagnosticsSettings.GetEnabledValue(); } - _enableViewDataDiagnostics = DataDiagnostics.GetViewEnabledValue(); + _enableViewDataDiagnostics = DataDiagnosticsSettings.GetViewEnabledValue(); if (dispatcherAction != null) { @@ -421,7 +421,7 @@ public bool EnableDataDiagnostics { _enableDataDiagnostics = value; - DataDiagnostics.SetValue(_enableDataDiagnostics); + DataDiagnosticsSettings.SetEnabledValue(_enableDataDiagnostics); } } } @@ -439,7 +439,7 @@ public bool EnableViewDataDiagnostics { _enableViewDataDiagnostics = value; - DataDiagnostics.SetViewEnabledValue(_enableViewDataDiagnostics); + DataDiagnosticsSettings.SetViewEnabledValue(_enableViewDataDiagnostics); OnPropertyChanged(nameof(EnableViewDataDiagnostics)); } } @@ -1057,7 +1057,7 @@ public void RefreshUpdatingState() internal void RefreshSettingsOnExternalChange() { - EnableDataDiagnostics = DataDiagnostics.GetValue(); + EnableDataDiagnostics = DataDiagnosticsSettings.GetEnabledValue(); NotifyPropertyChanged(nameof(EnableDataDiagnostics)); }