From 08f8f4502680d920dce7d9e763cc5bccc0bda96c Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Fri, 16 Dec 2016 20:30:25 +0100 Subject: [PATCH 1/6] Added button to open logs folder to settings Render exceptions are logged instead of thrown Fixed layer condition crash Logs are now archived and kept for 7 days --- Artemis/Artemis/Managers/LoopManager.cs | 11 +-- Artemis/Artemis/Models/EffectModel.cs | 97 ++++++++++--------- .../Layers/Models/LayerConditionModel.cs | 61 ++++++------ Artemis/Artemis/Utilities/Logging.cs | 15 ++- .../Flyouts/FlyoutSettingsViewModel.cs | 8 ++ .../Views/Flyouts/FlyoutSettingsView.xaml | 9 +- 6 files changed, 107 insertions(+), 94 deletions(-) diff --git a/Artemis/Artemis/Managers/LoopManager.cs b/Artemis/Artemis/Managers/LoopManager.cs index 4892d203e..a7c8e3ccc 100644 --- a/Artemis/Artemis/Managers/LoopManager.cs +++ b/Artemis/Artemis/Managers/LoopManager.cs @@ -62,16 +62,7 @@ namespace Artemis.Managers } catch (Exception e) { - if (_canShowException) - { - Execute.OnUIThread(delegate - { - _canShowException = false; - _loopTimer.Stop(); - App.GetArtemisExceptionViewer(e).ShowDialog(); - Environment.Exit(0); - }); - } + _logger.Warn(e, "Exception in render loop"); } } diff --git a/Artemis/Artemis/Models/EffectModel.cs b/Artemis/Artemis/Models/EffectModel.cs index ff2f3e409..eb1552d00 100644 --- a/Artemis/Artemis/Models/EffectModel.cs +++ b/Artemis/Artemis/Models/EffectModel.cs @@ -75,59 +75,62 @@ namespace Artemis.Models { if ((Profile == null) || (DataModel == null) || (DeviceManager.ActiveKeyboard == null)) return; - + lock (DataModel) { - // Get all enabled layers who's conditions are met - var renderLayers = GetRenderLayers(keyboardOnly); + lock (Profile) + { + // Get all enabled layers who's conditions are met + var renderLayers = GetRenderLayers(keyboardOnly); - // If the profile has no active LUA wrapper, create one - if (!string.IsNullOrEmpty(Profile.LuaScript)) - Profile.Activate(DeviceManager.ActiveKeyboard); + // If the profile has no active LUA wrapper, create one + if (!string.IsNullOrEmpty(Profile.LuaScript)) + Profile.Activate(DeviceManager.ActiveKeyboard); - // Render the keyboard layer-by-layer - var keyboardRect = DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale); - using (var g = Graphics.FromImage(frame.KeyboardBitmap)) - { - Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Keyboard), - DataModel, keyboardRect, false, true, "keyboard"); - } - // Render mice layer-by-layer - var devRec = new Rect(0, 0, 40, 40); - using (var g = Graphics.FromImage(frame.MouseBitmap)) - { - Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Mouse), - DataModel, devRec, false, true, "mouse"); - } - // Render headsets layer-by-layer - using (var g = Graphics.FromImage(frame.HeadsetBitmap)) - { - Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Headset), - DataModel, devRec, false, true, "headset"); - } - // Render generic devices layer-by-layer - using (var g = Graphics.FromImage(frame.GenericBitmap)) - { - Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Generic), - DataModel, devRec, false, true, "generic"); - } - // Render mousemats layer-by-layer - using (var g = Graphics.FromImage(frame.MousematBitmap)) - { - Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Mousemat), - DataModel, devRec, false, true, "mousemat"); - } + // Render the keyboard layer-by-layer + var keyboardRect = DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale); + using (var g = Graphics.FromImage(frame.KeyboardBitmap)) + { + Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Keyboard), + DataModel, keyboardRect, false, true, "keyboard"); + } + // Render mice layer-by-layer + var devRec = new Rect(0, 0, 40, 40); + using (var g = Graphics.FromImage(frame.MouseBitmap)) + { + Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Mouse), + DataModel, devRec, false, true, "mouse"); + } + // Render headsets layer-by-layer + using (var g = Graphics.FromImage(frame.HeadsetBitmap)) + { + Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Headset), + DataModel, devRec, false, true, "headset"); + } + // Render generic devices layer-by-layer + using (var g = Graphics.FromImage(frame.GenericBitmap)) + { + Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Generic), + DataModel, devRec, false, true, "generic"); + } + // Render mousemats layer-by-layer + using (var g = Graphics.FromImage(frame.MousematBitmap)) + { + Profile?.DrawLayers(g, renderLayers.Where(rl => rl.LayerType.DrawType == DrawType.Mousemat), + DataModel, devRec, false, true, "mousemat"); + } - // Trace debugging - if (DateTime.Now.AddSeconds(-2) <= LastTrace || Logger == null) - return; + // Trace debugging + if (DateTime.Now.AddSeconds(-2) <= LastTrace || Logger == null) + return; - LastTrace = DateTime.Now; - var dmJson = JsonConvert.SerializeObject(DataModel, Formatting.Indented); - Logger.Trace("Effect datamodel as JSON: \r\n{0}", dmJson); - Logger.Trace("Effect {0} has to render {1} layers", Name, renderLayers.Count); - foreach (var renderLayer in renderLayers) - Logger.Trace("- Layer name: {0}, layer type: {1}", renderLayer.Name, renderLayer.LayerType); + LastTrace = DateTime.Now; + var dmJson = JsonConvert.SerializeObject(DataModel, Formatting.Indented); + Logger.Trace("Effect datamodel as JSON: \r\n{0}", dmJson); + Logger.Trace("Effect {0} has to render {1} layers", Name, renderLayers.Count); + foreach (var renderLayer in renderLayers) + Logger.Trace("- Layer name: {0}, layer type: {1}", renderLayer.Name, renderLayer.LayerType); + } } } diff --git a/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs b/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs index 0f04dfddf..d48cb5097 100644 --- a/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs @@ -21,38 +21,41 @@ namespace Artemis.Profiles.Layers.Models public bool ConditionMet(IDataModel subject) { - if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Value) || string.IsNullOrEmpty(Type)) - return false; - - var inspect = GeneralHelpers.GetPropertyValue(subject, Field); - if (inspect == null) - return false; - - // Put the subject in a list, allowing Dynamic Linq to be used. - if (Type == "String") + lock (subject) { - return _interpreter.Eval($"subject.{Field}.ToLower(){Operator}(value)", - new Parameter("subject", subject.GetType(), subject), - new Parameter("value", Value.ToLower())); - } + if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Value) || string.IsNullOrEmpty(Type)) + return false; - Parameter rightParam = null; - switch (Type) - { - case "Enum": - var enumType = GeneralHelpers.GetPropertyValue(subject, Field).GetType(); - rightParam = new Parameter("value", Enum.Parse(enumType, Value)); - break; - case "Boolean": - rightParam = new Parameter("value", bool.Parse(Value)); - break; - case "Int32": - rightParam = new Parameter("value", int.Parse(Value)); - break; - } + var inspect = GeneralHelpers.GetPropertyValue(subject, Field); + if (inspect == null) + return false; - return _interpreter.Eval($"subject.{Field} {Operator} value", - new Parameter("subject", subject.GetType(), subject), rightParam); + // Put the subject in a list, allowing Dynamic Linq to be used. + if (Type == "String") + { + return _interpreter.Eval($"subject.{Field}.ToLower(){Operator}(value)", + new Parameter("subject", subject.GetType(), subject), + new Parameter("value", Value.ToLower())); + } + + Parameter rightParam = null; + switch (Type) + { + case "Enum": + var enumType = GeneralHelpers.GetPropertyValue(subject, Field).GetType(); + rightParam = new Parameter("value", Enum.Parse(enumType, Value)); + break; + case "Boolean": + rightParam = new Parameter("value", bool.Parse(Value)); + break; + case "Int32": + rightParam = new Parameter("value", int.Parse(Value)); + break; + } + + return _interpreter.Eval($"subject.{Field} {Operator} value", + new Parameter("subject", subject.GetType(), subject), rightParam); + } } } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/Logging.cs b/Artemis/Artemis/Utilities/Logging.cs index a69e103fc..b8c0bf913 100644 --- a/Artemis/Artemis/Utilities/Logging.cs +++ b/Artemis/Artemis/Utilities/Logging.cs @@ -36,11 +36,13 @@ namespace Artemis.Utilities // Step 3. Set target properties debuggerTarget.Layout = @"${logger:shortName=True} - ${uppercase:${level}}: ${message}"; - fileTarget.FileName = "${specialfolder:folder=MyDocuments}/Artemis/logs/${shortdate}.txt"; fileTarget.Layout = "${longdate}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}"; - fileTarget.EnableFileDelete = true; + fileTarget.FileName = "${specialfolder:folder=MyDocuments}/Artemis/logs/log.txt"; + fileTarget.ArchiveFileName = "${specialfolder:folder=MyDocuments}/Artemis/logs/log-{#}.txt"; + fileTarget.ArchiveEvery = FileArchivePeriod.Day; + fileTarget.ArchiveNumbering = ArchiveNumberingMode.Date; + fileTarget.ArchiveOldFileOnStartup = true; fileTarget.MaxArchiveFiles = 7; - fileTarget.ArchiveEvery = FileArchivePeriod.Minute; // Step 4. Define rules var rule1 = new LoggingRule("*", logLevel, debuggerTarget); @@ -53,9 +55,12 @@ namespace Artemis.Utilities // Step 5. Activate the configuration LogManager.Configuration = config; - // Log as fatal so it always shows + // Log as fatal so it always shows, add some spacing since this indicates the start of a new log var logger = LogManager.GetCurrentClassLogger(); - logger.Fatal("INFO: Set log level to {0}", logLevel); + var logMsg = $" INFO: Set log level to {logLevel} "; + logger.Fatal(new string('-', logMsg.Length)); + logger.Fatal(logMsg); + logger.Fatal(new string('-', logMsg.Length)); } private static void MemoryTargetOnEventReceived(LogEventInfo logEventInfo) diff --git a/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs b/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs index c038d47ba..cda9415c9 100644 --- a/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs +++ b/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs @@ -1,3 +1,4 @@ +using System; using System.ComponentModel; using System.Diagnostics; using System.Dynamic; @@ -12,6 +13,7 @@ using Caliburn.Micro; using MahApps.Metro.Controls; using NLog; using ILogger = Ninject.Extensions.Logging.ILogger; +using Process = System.Diagnostics.Process; namespace Artemis.ViewModels.Flyouts { @@ -201,6 +203,12 @@ namespace Artemis.ViewModels.Flyouts MainManager.EnableProgram(); } + public void ShowLogs() + { + var logPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\logs"; + System.Diagnostics.Process.Start(logPath); + } + public void ShowDebug() { IWindowManager manager = new WindowManager(); diff --git a/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml b/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml index 8b50fe0dc..2beb89dd5 100644 --- a/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml +++ b/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml @@ -102,16 +102,19 @@ +