diff --git a/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/EventSimulatorService.cs b/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/EventSimulatorService.cs index 1baebe7..baddebe 100644 --- a/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/EventSimulatorService.cs +++ b/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/EventSimulatorService.cs @@ -1,9 +1,10 @@ using System; using System.Collections.Generic; using System.Threading; -using Serilog; +using Microsoft.Extensions.Logging; using SharpHook; using SharpHook.Native; +using LogLevel = Microsoft.Extensions.Logging.LogLevel; namespace YMouseButtonControl.Core.Services.KeyboardAndMouse.Implementations; @@ -34,10 +35,11 @@ public interface IEventSimulatorService void TapKeys(string? keys, int delay, CancellationToken cancellationToken); } -public class EventSimulatorService(IEventSimulator eventSimulator) : IEventSimulatorService +public partial class EventSimulatorService( + ILogger logger, + IEventSimulator eventSimulator +) : IEventSimulatorService { - private readonly ILogger _logger = Log.Logger.ForContext(); - public void SimulateMousePress(MouseButton mb) { var t = new Thread(() => eventSimulator.SimulateMousePress(mb)); @@ -52,13 +54,13 @@ public void SimulateMouseRelease(MouseButton mb) public void SimulateKeyPress(string? key) { - _logger.Information("Simulate press {Key}", key); + LogSimulateKeyPress(logger, key); eventSimulator.SimulateKeyPress(KeyCodes[key ?? throw new NullReferenceException(key)]); } public void SimulateKeyRelease(string? key) { - _logger.Information("Simulate release {Key}", key); + LogSimulateKeyRelease(logger, key); eventSimulator.SimulateKeyRelease(KeyCodes[key ?? throw new NullReferenceException(key)]); } @@ -69,7 +71,7 @@ public void SimulateKeyRelease(string? key) /// public void SimulateKeyTap(string? key) { - _logger.Information("Simulate key tap {Key}", key); + LogSimulateKeyTap(logger, key); var keyCode = KeyCodes[key ?? throw new NullReferenceException(key)]; eventSimulator.SimulateKeyPress(keyCode); eventSimulator.SimulateKeyRelease(keyCode); @@ -198,7 +200,7 @@ public void TapKeys(string? keys, int delay, CancellationToken cancellationToken { if (cancellationToken.IsCancellationRequested) { - _logger.Information("========STOPPING TAP KEYS==========="); + LogStopTappingKeys(logger); return; } if (delay > -1) @@ -244,7 +246,7 @@ public void TapKeys(string? keys, int delay, CancellationToken cancellationToken { if (cancellationToken.IsCancellationRequested) { - _logger.Information("========STOPPING TAP KEYS==========="); + LogStopTappingKeys(logger); return; } switch (poppedPk.Value) @@ -520,6 +522,18 @@ private static List ParseKeys(string? keys) { "mb4", MouseButton.Button4 }, { "mb5", MouseButton.Button5 }, }; + + [LoggerMessage(LogLevel.Information, "========STOPPING TAP KEYS===========")] + private static partial void LogStopTappingKeys(ILogger logger); + + [LoggerMessage(LogLevel.Information, "Simulate key tap {Key}")] + private static partial void LogSimulateKeyTap(ILogger logger, string? key); + + [LoggerMessage(LogLevel.Information, "Simulate press {Key}")] + private static partial void LogSimulateKeyPress(ILogger logger, string? key); + + [LoggerMessage(LogLevel.Information, "Simulate release {Key}")] + private static partial void LogSimulateKeyRelease(ILogger logger, string? key); } internal class ParsedKey diff --git a/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/MouseListenerService.cs b/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/MouseListenerService.cs index 37911c7..fa71e1f 100644 --- a/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/MouseListenerService.cs +++ b/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/MouseListenerService.cs @@ -3,7 +3,7 @@ using System.Reactive.Linq; using System.Reactive.Subjects; using System.Threading; -using Serilog; +using Microsoft.Extensions.Logging; using SharpHook; using SharpHook.Native; using SharpHook.Reactive; @@ -11,6 +11,7 @@ using YMouseButtonControl.Core.Services.KeyboardAndMouse.EventArgs; using YMouseButtonControl.Core.Services.Processes; using YMouseButtonControl.Core.Services.Profiles; +using LogLevel = Microsoft.Extensions.Logging.LogLevel; namespace YMouseButtonControl.Core.Services.KeyboardAndMouse.Implementations; @@ -27,12 +28,12 @@ public interface IMouseListener : IDisposable /// Wrapper around sharphook for listening to mouse events /// Converts mouse events to NewMouseHookEventArgs /// -public class MouseListener : IMouseListener +public partial class MouseListener : IMouseListener { + private readonly ILogger _logger; private readonly IReactiveGlobalHook _hook; private readonly IProfilesService _profilesService; private readonly ICurrentWindowService _currentWindowService; - private readonly ILogger _log = Log.Logger.ForContext(); private Thread? _thread; private readonly IDisposable? _mouseMovedDisposable; private readonly IDisposable? _mousePressedDisposable; @@ -44,11 +45,13 @@ public class MouseListener : IMouseListener private readonly Subject _mouseWheelSubject; public MouseListener( + ILogger logger, IReactiveGlobalHook hook, IProfilesService profilesService, ICurrentWindowService currentWindowService ) { + _logger = logger; _hook = hook; _profilesService = profilesService; _currentWindowService = currentWindowService; @@ -78,7 +81,7 @@ public void Run() { _thread = new Thread(() => { - _log.Information("Starting mouse listener"); + LogStartup(_logger); _hook.Run(); }); _thread.Start(); @@ -175,8 +178,9 @@ private void ConvertMouseReleasedEvent(MouseHookEventArgs e) { return; } - _log.Information("Translate release {Button}", e.Data.Button); - _log.Information("ACTIVE WINDOW {Foreground}", _currentWindowService.ForegroundWindow); + + LogTranslateRelease(_logger, e.Data.Button); + LogActiveWindow(_logger, _currentWindowService.ForegroundWindow); var args = new NewMouseHookEventArgs( (YMouseButton)e.Data.Button, e.Data.X, @@ -185,12 +189,12 @@ private void ConvertMouseReleasedEvent(MouseHookEventArgs e) ); if (ShouldSuppressEvent(args)) { - _log.Information("Suppressing {Button}: Release", e.Data.Button); + LogSuppressingButtonRelease(_logger, e.Data.Button); e.SuppressEvent = true; } else { - _log.Information("Not suppressing {Button}: Release", e.Data.Button); + LogNotSuppressingButtonRelease(_logger, e.Data.Button); } _mouseReleasedSubject.OnNext(args); } @@ -201,8 +205,8 @@ private void ConvertMousePressedEvent(MouseHookEventArgs e) { return; } - _log.Information("Translate press {Button}", e.Data.Button); - _log.Information("ACTIVE WINDOW {Foreground}", _currentWindowService.ForegroundWindow); + LogTranslateButton(_logger, e.Data.Button); + LogActiveWindow(_logger, _currentWindowService.ForegroundWindow); var args = new NewMouseHookEventArgs( (YMouseButton)e.Data.Button, @@ -212,12 +216,12 @@ private void ConvertMousePressedEvent(MouseHookEventArgs e) ); if (ShouldSuppressEvent(args)) { - _log.Information("Suppressing {Button}: Press", e.Data.Button); + LogSuppressingButtonRelease(_logger, e.Data.Button); e.SuppressEvent = true; } else { - _log.Information("Not suppressing {Button}: Press", e.Data.Button); + LogNotSuppressingButtonRelease(_logger, e.Data.Button); } _mousePressedSubject.OnNext(args); } @@ -242,4 +246,28 @@ public void Dispose() _thread?.Join(); } + + [LoggerMessage(LogLevel.Information, "Translate press {Button}")] + private static partial void LogTranslateButton(ILogger logger, MouseButton button); + + [LoggerMessage(LogLevel.Information, "Suppressing {Button}: Press")] + private static partial void LogSuppressingButtonPress(ILogger logger, MouseButton button); + + [LoggerMessage(LogLevel.Information, "Not suppressing {Button}: Press")] + private static partial void LogNotSuppressingButtonPress(ILogger logger, MouseButton button); + + [LoggerMessage(LogLevel.Information, "Not suppressing {Button}: Release")] + public static partial void LogNotSuppressingButtonRelease(ILogger logger, MouseButton button); + + [LoggerMessage(LogLevel.Information, "Suppressing {Button}: Release")] + public static partial void LogSuppressingButtonRelease(ILogger logger, MouseButton button); + + [LoggerMessage(LogLevel.Information, "ACTIVE WINDOW {Foreground}")] + private static partial void LogActiveWindow(ILogger logger, string foreground); + + [LoggerMessage(LogLevel.Information, "Translate release {Button}")] + private static partial void LogTranslateRelease(ILogger logger, MouseButton button); + + [LoggerMessage(LogLevel.Information, "Starting mouse listener")] + private static partial void LogStartup(ILogger logger); } diff --git a/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/SimulatedKeystrokesTypes/StickyRepeatService.cs b/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/SimulatedKeystrokesTypes/StickyRepeatService.cs index 07eaa59..d053506 100644 --- a/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/SimulatedKeystrokesTypes/StickyRepeatService.cs +++ b/YMouseButtonControl.Core/Services/KeyboardAndMouse/Implementations/SimulatedKeystrokesTypes/StickyRepeatService.cs @@ -1,7 +1,6 @@ using System.Threading; -using Serilog; +using Microsoft.Extensions.Logging; using YMouseButtonControl.Core.Services.KeyboardAndMouse.Enums; -using YMouseButtonControl.Core.Services.KeyboardAndMouse.Interfaces; using YMouseButtonControl.Core.ViewModels.Models; namespace YMouseButtonControl.Core.Services.KeyboardAndMouse.Implementations.SimulatedKeystrokesTypes; @@ -11,15 +10,16 @@ public interface IStickyRepeatService void StickyRepeat(BaseButtonMappingVm mapping, MouseButtonState state); } -public class StickyRepeatService(IEventSimulatorService eventSimulatorService) - : IStickyRepeatService +public partial class StickyRepeatService( + ILogger logger, + IEventSimulatorService eventSimulatorService +) : IStickyRepeatService { private Thread? _thread; private bool _shouldStop; private readonly object _lock = new(); private const int RepeatRateMs = 33; private CancellationTokenSource? _cts; - private readonly ILogger _log = Log.Logger.ForContext(); public void StickyRepeat(BaseButtonMappingVm mapping, MouseButtonState state) { @@ -36,7 +36,7 @@ public void StickyRepeat(BaseButtonMappingVm mapping, MouseButtonState state) { lock (_lock) { - _log.Information("=====CANCELLATION REQUESTED======="); + LogCancellationRequested(logger); _cts?.Cancel(); _shouldStop = true; } @@ -63,7 +63,7 @@ private void StartThread(BaseButtonMappingVm mapping) { if (_shouldStop) { - _log.Information("=====CANCELLATION REQUESTED======="); + LogCancellationRequested(logger); _cts.Cancel(); break; } @@ -75,4 +75,7 @@ private void StartThread(BaseButtonMappingVm mapping) _thread.Start(); } + + [LoggerMessage(LogLevel.Information, "=====CANCELLATION REQUESTED=======")] + private static partial void LogCancellationRequested(ILogger logger); } diff --git a/YMouseButtonControl.Core/Services/KeyboardAndMouse/KeyboardSimulatorWorker.cs b/YMouseButtonControl.Core/Services/KeyboardAndMouse/KeyboardSimulatorWorker.cs index aa5d93c..e383383 100644 --- a/YMouseButtonControl.Core/Services/KeyboardAndMouse/KeyboardSimulatorWorker.cs +++ b/YMouseButtonControl.Core/Services/KeyboardAndMouse/KeyboardSimulatorWorker.cs @@ -1,5 +1,5 @@ using System; -using Serilog; +using Microsoft.Extensions.Logging; using YMouseButtonControl.Core.Services.KeyboardAndMouse.Enums; using YMouseButtonControl.Core.Services.KeyboardAndMouse.EventArgs; using YMouseButtonControl.Core.Services.KeyboardAndMouse.Implementations; @@ -11,7 +11,8 @@ namespace YMouseButtonControl.Core.Services.KeyboardAndMouse; -public class KeyboardSimulatorWorker( +public partial class KeyboardSimulatorWorker( + ILogger logger, IProfilesService profilesService, IMouseListener mouseListener, ISkipProfileService skipProfileService, @@ -24,7 +25,6 @@ public class KeyboardSimulatorWorker( IRightClick rightClick ) : IDisposable { - private readonly ILogger _log = Log.Logger.ForContext(); private IDisposable? _onMousePressedDisposable; private IDisposable? _onMouseReleasedDisposable; private IDisposable? _onMouseWheelDisposable; @@ -51,11 +51,10 @@ private void OnMousePressed(NewMouseHookEventArgs e) { if (skipProfileService.ShouldSkipProfile(p, e)) { - _log.Information("Skipped {Profile}", p.Name); + LogSkippedProfile(logger, p.Name); continue; } - - _log.Information("{Profile}, Route {Button}", p.Name, e.Button); + LogMousePressedRoute(logger, p.Name, e.Button); RouteMouseButton(e.Button, p, MouseButtonState.Pressed); } } @@ -151,4 +150,14 @@ MouseButtonState state } private void OnMouseWheel(NewMouseWheelEventArgs e) { } + + [LoggerMessage(LogLevel.Information, "Skipped {Profile}")] + private static partial void LogSkippedProfile(ILogger logger, string profile); + + [LoggerMessage(LogLevel.Information, "{Profile}, Route {Button}")] + private static partial void LogMousePressedRoute( + ILogger logger, + string profile, + YMouseButton button + ); } diff --git a/YMouseButtonControl.Core/Services/Logging/EnableLoggingService.cs b/YMouseButtonControl.Core/Services/Logging/EnableLoggingService.cs new file mode 100644 index 0000000..46d2b0b --- /dev/null +++ b/YMouseButtonControl.Core/Services/Logging/EnableLoggingService.cs @@ -0,0 +1,102 @@ +using System; +using System.IO; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace YMouseButtonControl.Core.Services.Logging; + +public interface IEnableLoggingService +{ + void EnableLogging(); + void DisableLogging(); + + /// + /// True = enabled + /// False = disabled + /// + /// + /// + bool GetLoggingState(); +} + +public class EnableLoggingService : IEnableLoggingService +{ + private readonly string _pathToAppSettings = Path.Join( + AppContext.BaseDirectory, + "appsettings.json" + ); + + /// + /// True = enabled + /// False = disabled + /// + /// + /// + public bool GetLoggingState() + { + if (!File.Exists(_pathToAppSettings)) + { + throw new Exception($"Appsettings file not found: {_pathToAppSettings}"); + } + var json = + JsonConvert.DeserializeObject(File.ReadAllText(_pathToAppSettings)) + ?? throw new Exception($"Error deserializing {_pathToAppSettings}"); + return json.GetValue("Logging") != null; + } + + public void EnableLogging() + { + if (!File.Exists(_pathToAppSettings)) + { + throw new Exception($"Appsettings file not found: {_pathToAppSettings}"); + } + var json = + JsonConvert.DeserializeObject(File.ReadAllText(_pathToAppSettings)) + ?? throw new Exception($"Error deserializing {_pathToAppSettings}"); + var toAdd = new JProperty( + "Logging", + new JObject( + new JProperty( + "LogLevel", + new JObject( + new JProperty("Default", "Debug"), + new JProperty("System", "Information"), + new JProperty("Microsoft", "Error") + ) + ), + new JProperty( + "File", + new JObject( + new JProperty("Path", "YMouseButtonControl.log"), + new JProperty("Append", true), + new JProperty("MinLevel", "Information"), + new JProperty("FileSizeLimitBytes", 0), + new JProperty("MaxRollingFiles", 0) + ) + ) + ) + ); + json.Add(toAdd); + File.WriteAllText( + _pathToAppSettings, + JsonConvert.SerializeObject(json, Formatting.Indented) + ); + } + + public void DisableLogging() + { + if (!File.Exists(_pathToAppSettings)) + { + throw new Exception($"Appsettings file not found: {_pathToAppSettings}"); + } + + var json = + JsonConvert.DeserializeObject(File.ReadAllText(_pathToAppSettings)) + ?? throw new Exception($"Error deserializing {_pathToAppSettings}"); + json.Remove("Logging"); + File.WriteAllText( + _pathToAppSettings, + JsonConvert.SerializeObject(json, Formatting.Indented) + ); + } +} diff --git a/YMouseButtonControl.Core/ViewModels/MainWindow/GlobalSettingsDialogViewModel.cs b/YMouseButtonControl.Core/ViewModels/MainWindow/GlobalSettingsDialogViewModel.cs index 9e7b94b..863a55c 100644 --- a/YMouseButtonControl.Core/ViewModels/MainWindow/GlobalSettingsDialogViewModel.cs +++ b/YMouseButtonControl.Core/ViewModels/MainWindow/GlobalSettingsDialogViewModel.cs @@ -5,9 +5,11 @@ using System.Reactive.Linq; using System.Transactions; using ReactiveUI; +using YMouseButtonControl.Core.Services.Logging; using YMouseButtonControl.Core.Services.Settings; using YMouseButtonControl.Core.Services.Theme; using YMouseButtonControl.Core.ViewModels.Models; +using YMouseButtonControl.DataAccess.Models; namespace YMouseButtonControl.Core.ViewModels.MainWindow; @@ -16,12 +18,14 @@ public interface IGlobalSettingsDialogViewModel; public class GlobalSettingsDialogViewModel : DialogBase, IGlobalSettingsDialogViewModel { private SettingBoolVm _startMinimizedSetting; + private bool _loggingEnabled; private SettingIntVm _themeSetting; private ObservableCollection _themeCollection; private ThemeVm _selectedTheme; private readonly ObservableAsPropertyHelper? _applyIsExec; public GlobalSettingsDialogViewModel( + IEnableLoggingService enableLoggingService, ISettingsService settingsService, IThemeService themeService ) @@ -30,6 +34,7 @@ IThemeService themeService _startMinimizedSetting = settingsService.GetSetting("StartMinimized") as SettingBoolVm ?? throw new Exception("Error retrieving StartMinimized setting"); + _loggingEnabled = enableLoggingService.GetLoggingState(); _themeSetting = settingsService.GetSetting("Theme") as SettingIntVm ?? throw new Exception("Error retrieving Theme setting"); @@ -45,6 +50,10 @@ IThemeService themeService settingsService.GetSetting("StartMinimized") is not SettingBoolVm curVal || curVal.BoolValue != val ); + var loggingChanged = this.WhenAnyValue( + x => x.LoggingEnabled, + selector: val => val != enableLoggingService.GetLoggingState() + ); var themeChanged = this.WhenAnyValue( x => x.ThemeSetting.IntValue, selector: val => @@ -53,10 +62,24 @@ IThemeService themeService ); var applyIsExecObs = this.WhenAnyValue(x => x.AppIsExec); - var canSave = startMinimizedChanged.Merge(applyIsExecObs).Merge(themeChanged); + var canSave = startMinimizedChanged + .Merge(loggingChanged) + .Merge(applyIsExecObs) + .Merge(themeChanged); ApplyCommand = ReactiveCommand.Create( () => { + if (LoggingEnabled != enableLoggingService.GetLoggingState()) + { + if (LoggingEnabled) + { + enableLoggingService.EnableLogging(); + } + else + { + enableLoggingService.DisableLogging(); + } + } using var trn = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled); settingsService.UpdateSetting(StartMinimized); settingsService.UpdateSetting(ThemeSetting); @@ -75,6 +98,12 @@ public SettingBoolVm StartMinimized set => this.RaiseAndSetIfChanged(ref _startMinimizedSetting, value); } + public bool LoggingEnabled + { + get => _loggingEnabled; + set => this.RaiseAndSetIfChanged(ref _loggingEnabled, value); + } + public ThemeVm SelectedTheme { get => _selectedTheme; diff --git a/YMouseButtonControl.Core/YMouseButtonControl.Core.csproj b/YMouseButtonControl.Core/YMouseButtonControl.Core.csproj index a376bfc..156814f 100644 --- a/YMouseButtonControl.Core/YMouseButtonControl.Core.csproj +++ b/YMouseButtonControl.Core/YMouseButtonControl.Core.csproj @@ -20,10 +20,10 @@ + - diff --git a/YMouseButtonControl.Linux/Services/SkipProfileService.cs b/YMouseButtonControl.Linux/Services/SkipProfileService.cs index b87ccd3..30dee4d 100644 --- a/YMouseButtonControl.Linux/Services/SkipProfileService.cs +++ b/YMouseButtonControl.Linux/Services/SkipProfileService.cs @@ -1,4 +1,4 @@ -using Serilog; +using Microsoft.Extensions.Logging; using YMouseButtonControl.Core.Services.KeyboardAndMouse.EventArgs; using YMouseButtonControl.Core.Services.KeyboardAndMouse.Interfaces; using YMouseButtonControl.Core.Services.Processes; @@ -6,17 +6,18 @@ namespace YMouseButtonControl.Linux.Services; -public class SkipProfileService(ICurrentWindowService currentWindowService) : ISkipProfileService +public partial class SkipProfileService( + ILogger logger, + ICurrentWindowService currentWindowService +) : ISkipProfileService { - private readonly ILogger _myLog = Log.Logger.ForContext(); - // Returns whether this profile should be skipped on mouse events public bool ShouldSkipProfile(ProfileVm p, NewMouseHookEventArgs e) { // If the profile's checkbox is checked in the profiles list if (!p.Checked) { - _myLog.Information("Not checked"); + LogNotChecked(logger); return true; } @@ -35,11 +36,17 @@ public bool ShouldSkipProfile(ProfileVm p, NewMouseHookEventArgs e) return false; } - _myLog.Information( - "Foreground window: {ForegroundWindow}", - currentWindowService.ForegroundWindow - ); - _myLog.Information("Couldn't find foreground window {Process}", p.Process); + LogForegroundWindow(logger, currentWindowService.ForegroundWindow); + LogCouldNotFindForegroundWindow(logger, p.Process); return true; } + + [LoggerMessage(LogLevel.Information, "Couldn't find foreground window {Process}")] + private static partial void LogCouldNotFindForegroundWindow(ILogger logger, string process); + + [LoggerMessage(LogLevel.Information, "Foreground window: {ForegroundWindow}")] + private static partial void LogForegroundWindow(ILogger logger, string foregroundWindow); + + [LoggerMessage(LogLevel.Information, "Not checked")] + private static partial void LogNotChecked(ILogger logger); } diff --git a/YMouseButtonControl.MacOS/Services/SkipProfileService.cs b/YMouseButtonControl.MacOS/Services/SkipProfileService.cs index 0edf7be..4240d45 100644 --- a/YMouseButtonControl.MacOS/Services/SkipProfileService.cs +++ b/YMouseButtonControl.MacOS/Services/SkipProfileService.cs @@ -1,4 +1,4 @@ -using Serilog; +using Microsoft.Extensions.Logging; using YMouseButtonControl.Core.Services.KeyboardAndMouse.EventArgs; using YMouseButtonControl.Core.Services.KeyboardAndMouse.Interfaces; using YMouseButtonControl.Core.Services.Processes; @@ -6,17 +6,18 @@ namespace YMouseButtonControl.MacOS.Services; -public class SkipProfileService(ICurrentWindowService currentWindowService) : ISkipProfileService +public partial class SkipProfileService( + ILogger logger, + ICurrentWindowService currentWindowService +) : ISkipProfileService { - private readonly ILogger _myLog = Log.Logger.ForContext(); - // Returns whether this profile should be skipped on mouse events public bool ShouldSkipProfile(ProfileVm p, NewMouseHookEventArgs e) { // If the profile's checkbox is checked in the profiles list if (!p.Checked) { - _myLog.Information("Not checked"); + LogNotChecked(logger); return true; } @@ -30,11 +31,17 @@ public bool ShouldSkipProfile(ProfileVm p, NewMouseHookEventArgs e) return false; } - _myLog.Information( - "Foreground window: {ForegroundWindow}", - currentWindowService.ForegroundWindow - ); - _myLog.Information("Couldn't find foreground window {Process}", p.Process); + LogForegroundWindow(logger, currentWindowService.ForegroundWindow); + LogCouldNotFindForegroundWindow(logger, p.Process); return true; } + + [LoggerMessage(LogLevel.Information, "Couldn't find foreground window {Process}")] + private static partial void LogCouldNotFindForegroundWindow(ILogger logger, string process); + + [LoggerMessage(LogLevel.Information, "Foreground window: {ForegroundWindow}")] + private static partial void LogForegroundWindow(ILogger logger, string foregroundWindow); + + [LoggerMessage(LogLevel.Information, "Not checked")] + private static partial void LogNotChecked(ILogger logger); } diff --git a/YMouseButtonControl.Windows/Services/CurrentWindowService.cs b/YMouseButtonControl.Windows/Services/CurrentWindowService.cs index 9b3aafb..817d373 100644 --- a/YMouseButtonControl.Windows/Services/CurrentWindowService.cs +++ b/YMouseButtonControl.Windows/Services/CurrentWindowService.cs @@ -1,7 +1,7 @@ using System.ComponentModel; using System.Runtime.InteropServices; using System.Runtime.Versioning; -using Serilog; +using Microsoft.Extensions.Logging; using Windows.Win32; using Windows.Win32.System.Threading; using YMouseButtonControl.Core.Services.Processes; @@ -9,10 +9,9 @@ namespace YMouseButtonControl.Windows.Services; [SupportedOSPlatform("windows5.1.2600")] -public class CurrentWindowService : ICurrentWindowService +public partial class CurrentWindowService(ILogger logger) + : ICurrentWindowService { - private readonly ILogger _log = Log.Logger.ForContext(); - public string ForegroundWindow => GetWindowTitleFromHWnd(); private unsafe string GetWindowTitleFromHWnd() @@ -20,7 +19,7 @@ private unsafe string GetWindowTitleFromHWnd() var hWnd = PInvoke.GetForegroundWindow(); if (hWnd.IsNull) { - _log.Information("HWND is null"); + LogHwndNull(logger); return ""; } @@ -40,10 +39,10 @@ private unsafe string GetWindowTitleFromHWnd() { var lastWin32Err = Marshal.GetLastWin32Error(); if (lastWin32Err != 5) + { throw new Win32Exception(lastWin32Err); - _log.Warning( - "ERROR_ACCESS_DENIED, likely tried to open an admin process without admin permissions. Try opening YMouseButtonControl as admin." - ); + } + LogErrorAccessDenied(logger); return ""; } @@ -58,4 +57,13 @@ private unsafe string GetWindowTitleFromHWnd() return new string(pText); } } + + [LoggerMessage( + LogLevel.Information, + "ERROR_ACCESS_DENIED, likely tried to open an admin process without admin permissions. Try opening YMouseButtonControl as admin." + )] + private static partial void LogErrorAccessDenied(ILogger logger); + + [LoggerMessage(LogLevel.Information, "HWND is null")] + private static partial void LogHwndNull(ILogger logger); } diff --git a/YMouseButtonControl.Windows/Services/SkipProfileService.cs b/YMouseButtonControl.Windows/Services/SkipProfileService.cs index 18f22f7..c7572e7 100644 --- a/YMouseButtonControl.Windows/Services/SkipProfileService.cs +++ b/YMouseButtonControl.Windows/Services/SkipProfileService.cs @@ -1,5 +1,5 @@ using System.Runtime.Versioning; -using Serilog; +using Microsoft.Extensions.Logging; using YMouseButtonControl.Core.Services.KeyboardAndMouse.EventArgs; using YMouseButtonControl.Core.Services.KeyboardAndMouse.Interfaces; using YMouseButtonControl.Core.ViewModels.Models; @@ -7,16 +7,14 @@ namespace YMouseButtonControl.Windows.Services; [SupportedOSPlatform("windows5.1.2600")] -public class SkipProfileService : ISkipProfileService +public partial class SkipProfileService(ILogger logger) : ISkipProfileService { - private readonly ILogger _log = Log.Logger.ForContext(); - public bool ShouldSkipProfile(ProfileVm p, NewMouseHookEventArgs e) { // If the profile's checkbox is checked in the profiles list if (!p.Checked) { - _log.Information("Not checked"); + LogNotChecked(logger); return true; } @@ -27,4 +25,7 @@ public bool ShouldSkipProfile(ProfileVm p, NewMouseHookEventArgs e) return !(e.ActiveWindow?.Contains(p.Process) ?? false); } + + [LoggerMessage(LogLevel.Information, "Not checked")] + private static partial void LogNotChecked(ILogger logger); } diff --git a/YMouseButtonControl.Windows/YMouseButtonControl.Windows.csproj b/YMouseButtonControl.Windows/YMouseButtonControl.Windows.csproj index e44ead5..a67ba60 100644 --- a/YMouseButtonControl.Windows/YMouseButtonControl.Windows.csproj +++ b/YMouseButtonControl.Windows/YMouseButtonControl.Windows.csproj @@ -23,7 +23,6 @@ all - diff --git a/YMouseButtonControl/App.axaml.cs b/YMouseButtonControl/App.axaml.cs index f1b8ddc..946bfe7 100644 --- a/YMouseButtonControl/App.axaml.cs +++ b/YMouseButtonControl/App.axaml.cs @@ -7,6 +7,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using NReco.Logging.File; using ReactiveUI; using Splat; using Splat.Microsoft.Extensions.DependencyInjection; @@ -18,10 +20,12 @@ using YMouseButtonControl.Core.Views; using YMouseButtonControl.DataAccess.Context; using YMouseButtonControl.DependencyInjection; +using ILogger = Microsoft.Extensions.Logging.ILogger; +using LogLevel = Microsoft.Extensions.Logging.LogLevel; namespace YMouseButtonControl; -public class App : Application +public partial class App : Application { public IServiceProvider? Container { get; private set; } private IBackgroundTasksRunner? _backgroundTasksRunner; @@ -50,12 +54,23 @@ private void Init() Bootstrapper.Register(services); + services.AddLogging(lb => lb.AddFile(configuration.GetSection("Logging"))); + services.AddSingleton< IActivationForViewFetcher, AvaloniaActivationForViewFetcher >(); services.AddSingleton(); }) + .ConfigureLogging(x => + { +#if !DEBUG + if (!configuration.GetSection("Logging").Exists()) + { + x.ClearProviders(); + } +#endif + }) .Build(); Container = host.Services; Container.UseMicrosoftDependencyResolver(); @@ -68,32 +83,52 @@ private void Init() public override void OnFrameworkInitializationCompleted() { Init(); - DataContext = Container?.GetRequiredService(); - _backgroundTasksRunner = Container?.GetRequiredService(); - var settingsService = - Container?.GetRequiredService() - ?? throw new Exception($"Error retrieving {nameof(ISettingsService)}"); - var startMinimized = - settingsService.GetSetting("StartMinimized") as SettingBoolVm - ?? throw new Exception($"Error retrieving setting StartMinimized"); - - if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + var logger = + Container?.GetRequiredService>() + ?? throw new Exception("Error activating logger"); + + try { - if (!startMinimized.BoolValue) + DataContext = Container?.GetRequiredService(); + _backgroundTasksRunner = Container?.GetRequiredService(); + var settingsService = + Container?.GetRequiredService() + ?? throw new Exception($"Error retrieving {nameof(ISettingsService)}"); + var startMinimized = + settingsService.GetSetting("StartMinimized") as SettingBoolVm + ?? throw new Exception("Error retrieving setting StartMinimized"); + + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - var mainWindow = (Window)Container.GetRequiredService(); - mainWindow.DataContext = Container.GetRequiredService(); - desktop.MainWindow = mainWindow; - } + if (!startMinimized.BoolValue) + { + var mainWindow = (Window)Container.GetRequiredService(); + mainWindow.DataContext = Container.GetRequiredService(); + desktop.MainWindow = mainWindow; + } - desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown; + desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown; - desktop.Exit += (sender, args) => - { - _backgroundTasksRunner?.Dispose(); - }; - } + desktop.Exit += (sender, args) => + { + _backgroundTasksRunner?.Dispose(); + }; + } - base.OnFrameworkInitializationCompleted(); + base.OnFrameworkInitializationCompleted(); + } + catch (Exception e) + { + LogError(logger, e.Message, e.InnerException?.Message, e.StackTrace); + throw; + } } + + [LoggerMessage(LogLevel.Error, "{Message}\r{InnerException}\r{StackTrace}")] + private static partial void LogError( + ILogger logger, + string message, + string? innerException, + string? stackTrace + ); } diff --git a/YMouseButtonControl/DependencyInjection/ServicesBootstrapper.cs b/YMouseButtonControl/DependencyInjection/ServicesBootstrapper.cs index cad166b..5447342 100644 --- a/YMouseButtonControl/DependencyInjection/ServicesBootstrapper.cs +++ b/YMouseButtonControl/DependencyInjection/ServicesBootstrapper.cs @@ -3,6 +3,7 @@ using System.Runtime.Versioning; using Microsoft.Extensions.DependencyInjection; using YMouseButtonControl.Core.Services.BackgroundTasks; +using YMouseButtonControl.Core.Services.Logging; using YMouseButtonControl.Core.Services.Processes; using YMouseButtonControl.Core.Services.Profiles; using YMouseButtonControl.Core.Services.Settings; @@ -22,6 +23,7 @@ public static void RegisterServices(IServiceCollection services) private static void RegisterCommonServices(IServiceCollection services) { services + .AddScoped() .AddScoped() .AddScoped() .AddScoped(); diff --git a/YMouseButtonControl/Program.cs b/YMouseButtonControl/Program.cs index 9e4663c..b43a82d 100644 --- a/YMouseButtonControl/Program.cs +++ b/YMouseButtonControl/Program.cs @@ -1,7 +1,5 @@ -using System; -using Avalonia; +using Avalonia; using Avalonia.ReactiveUI; -using Serilog; namespace YMouseButtonControl; @@ -9,23 +7,7 @@ internal static class Program { public static void Main(string[] args) { - using var log = new LoggerConfiguration() - .WriteTo.Console( - outputTemplate: "[{Timestamp:HH:mm:ss} {SourceContext} {Level:u3}] {Message:lj}{NewLine}{Exception}" - ) - .WriteTo.File("YMouseButtonControl.log") - .CreateLogger(); - Log.Logger = log; - - try - { - BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); - } - catch (Exception e) - { - Log.Error(e.Message); - throw; - } + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); } private static AppBuilder BuildAvaloniaApp() => diff --git a/YMouseButtonControl/Views/Dialogs/GlobalSettingsDialog.axaml b/YMouseButtonControl/Views/Dialogs/GlobalSettingsDialog.axaml index 11c8962..e0b653a 100644 --- a/YMouseButtonControl/Views/Dialogs/GlobalSettingsDialog.axaml +++ b/YMouseButtonControl/Views/Dialogs/GlobalSettingsDialog.axaml @@ -14,10 +14,18 @@ - + - + + + + Whether or not logging to file YMouseButtonControl.log is performed. Requires a restart. + + + + - + diff --git a/YMouseButtonControl/YMouseButtonControl.csproj b/YMouseButtonControl/YMouseButtonControl.csproj index ba685b4..1e0b871 100644 --- a/YMouseButtonControl/YMouseButtonControl.csproj +++ b/YMouseButtonControl/YMouseButtonControl.csproj @@ -67,10 +67,7 @@ - - - - + diff --git a/YMouseButtonControl/appsettings.json b/YMouseButtonControl/appsettings.json index 1a8df0f..0e39df5 100644 --- a/YMouseButtonControl/appsettings.json +++ b/YMouseButtonControl/appsettings.json @@ -3,7 +3,14 @@ "LogLevel": { "Default": "Debug", "System": "Information", - "Microsoft": "Information" + "Microsoft": "Error" + }, + "File": { + "Path": "YMouseButtonControl.log", + "Append": true, + "MinLevel": "Information", + "FileSizeLimitBytes": 0, + "MaxRollingFiles": 0 } }, "ConnectionStrings": {