From 99d0b2ea3acfedcd3d9f95a40b33bc154ff63aab Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 27 Mar 2024 11:49:04 -0500 Subject: [PATCH 1/3] feat: add method to log Exceptions using default Serilog options Alos modified console sink to pad non-keyed messages with 3 characters of empty space --- src/Pepperdash Core/Device.cs | 7 +-- src/Pepperdash Core/Logging/Debug.cs | 46 ++++++++++++++++--- .../Logging/DebugConsoleSink.cs | 9 +--- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/Pepperdash Core/Device.cs b/src/Pepperdash Core/Device.cs index 98c4293..25d48af 100644 --- a/src/Pepperdash Core/Device.cs +++ b/src/Pepperdash Core/Device.cs @@ -1,9 +1,6 @@ using System; using System.Collections.Generic; -using System.Linq; -using Serilog; -using Serilog.Core; -using Serilog.Sinks.SystemConsole; +using Serilog.Events; namespace PepperDash.Core { @@ -53,7 +50,7 @@ public class Device : IKeyName public Device(string key) { Key = key; - if (key.Contains('.')) Debug.Console(0, this, "WARNING: Device name's should not include '.'"); + if (key.Contains('.')) Debug.LogMessage(LogEventLevel.Information, "WARNING: Device key should not include '.'", this); Name = ""; } diff --git a/src/Pepperdash Core/Logging/Debug.cs b/src/Pepperdash Core/Logging/Debug.cs index 15ffa8e..f6b7ffc 100644 --- a/src/Pepperdash Core/Logging/Debug.cs +++ b/src/Pepperdash Core/Logging/Debug.cs @@ -14,6 +14,9 @@ using Crestron.SimplSharp.CrestronDataStore; using PepperDash.Core.Logging; using Serilog.Formatting.Compact; +using System.Runtime.CompilerServices; +using System.Diagnostics; +using Serilog.Context; namespace PepperDash.Core { @@ -35,7 +38,7 @@ public static class Debug {2, LogEventLevel.Verbose }, }; - private static Logger _logger; + private static ILogger _logger; private static readonly LoggingLevelSwitch _consoleLoggingLevelSwitch; @@ -131,6 +134,7 @@ static Debug() _defaultLoggerConfiguration = new LoggerConfiguration() .MinimumLevel.Verbose() + .Enrich.FromLogContext() .WriteTo.Sink(new DebugConsoleSink(new JsonFormatter(renderMessage: true)), levelSwitch: _consoleLoggingLevelSwitch) .WriteTo.Sink(_websocketSink, levelSwitch: _websocketLoggingLevelSwitch) .WriteTo.Sink(new DebugErrorLogSink(), LogEventLevel.Information) @@ -542,16 +546,46 @@ public static void ShowDebugLog(string s) CrestronConsole.ConsoleCommandResponse(l + CrestronEnvironment.NewLine); } + /// + /// Log an Exception using Serilog's default Exception logging mechanism + /// + /// Exception to log + /// Message template + /// Optional IKeyed device. If provided, the Key of the device will be added to the log message + /// Args to put into message template + public static void LogMessage(Exception ex, string message, IKeyed device = null, params object[] args) + { + using (LogContext.PushProperty("Key", device?.Key ?? string.Empty)) + { + _logger.Error(ex, message, args); + } + } + + /// + /// Log a message + /// + /// Level to log at + /// Message template + /// Optional IKeyed device. If provided, the Key of the device will be added to the log message + /// Args to put into message template + public static void LogMessage(LogEventLevel level, string message, IKeyed device=null, params object[] args) + { + using (LogContext.PushProperty("Key", device?.Key ?? string.Empty)) + { + _logger.Write(level, message, args); + } + } + + [Obsolete("Use overload with optional IKeyed parameter")] public static void LogMessage(LogEventLevel level, string message, params object[] args) { - _logger.Write(level, message, args); + LogMessage(level, message, null, args); } + [Obsolete("Use overload with optional IKeyed parameter")] public static void LogMessage(LogEventLevel level, IKeyed keyed, string message, params object[] args) { - var log = _logger.ForContext("Key", keyed.Key); - - log.Write(level, message, args); + LogMessage(level, message, keyed, args); } @@ -561,7 +595,7 @@ private static void LogMessage(uint level, string format, params object[] items) var logLevel = _logLevels[level]; - LogMessage(logLevel, format, items ); + LogMessage(logLevel, format, items); } private static void LogMessage(uint level, IKeyed keyed, string format, params object[] items) diff --git a/src/Pepperdash Core/Logging/DebugConsoleSink.cs b/src/Pepperdash Core/Logging/DebugConsoleSink.cs index a59928d..990d47b 100644 --- a/src/Pepperdash Core/Logging/DebugConsoleSink.cs +++ b/src/Pepperdash Core/Logging/DebugConsoleSink.cs @@ -5,12 +5,7 @@ using Serilog.Events; using Serilog.Formatting; using Serilog.Formatting.Json; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection.Emit; -using System.Text; -using System.Threading.Tasks; + namespace PepperDash.Core { @@ -26,7 +21,7 @@ public void Emit(LogEvent logEvent) if(logEvent.Properties.TryGetValue("Key",out var value) && value is ScalarValue sv && sv.Value is string rawValue) { - message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue}]: {logEvent.RenderMessage()}"; + message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue,3}]: {logEvent.RenderMessage()}"; } CrestronConsole.PrintLine(message); From 46b8e24968511ef965ee00e5f5591c7932a43dfd Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 27 Mar 2024 15:33:19 -0500 Subject: [PATCH 2/3] fix: use correct quotes --- src/Pepperdash Core/Device.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Pepperdash Core/Device.cs b/src/Pepperdash Core/Device.cs index 25d48af..749713e 100644 --- a/src/Pepperdash Core/Device.cs +++ b/src/Pepperdash Core/Device.cs @@ -50,7 +50,7 @@ public class Device : IKeyName public Device(string key) { Key = key; - if (key.Contains('.')) Debug.LogMessage(LogEventLevel.Information, "WARNING: Device key should not include '.'", this); + if (key.Contains(".")) Debug.LogMessage(LogEventLevel.Information, "WARNING: Device key should not include '.'", this); Name = ""; } From 7a4a91cfd545ed47ff00ba504ee1b2fed3f19ae6 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 1 May 2024 09:32:54 -0500 Subject: [PATCH 3/3] fix: add methods to set Error Log and File minimum level In some situations, like on VC-4, it is necessary to see verbose and debug messages in the error log/journalctl/file log. This change allows those values to be set using a method. --- src/Pepperdash Core/Logging/Debug.cs | 72 ++++++++++++++++------ src/Pepperdash Core/Logging/DebugMemory.cs | 2 +- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/src/Pepperdash Core/Logging/Debug.cs b/src/Pepperdash Core/Logging/Debug.cs index f6b7ffc..1cf916a 100644 --- a/src/Pepperdash Core/Logging/Debug.cs +++ b/src/Pepperdash Core/Logging/Debug.cs @@ -1,22 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using Crestron.SimplSharp; -using System.Reflection; -using Crestron.SimplSharp.CrestronLogger; +using Crestron.SimplSharp; +using Crestron.SimplSharp.CrestronDataStore; using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharp.CrestronLogger; using Newtonsoft.Json; -using PepperDash.Core.DebugThings; +using PepperDash.Core.Logging; using Serilog; +using Serilog.Context; using Serilog.Core; using Serilog.Events; -using Serilog.Formatting.Json; -using Crestron.SimplSharp.CrestronDataStore; -using PepperDash.Core.Logging; using Serilog.Formatting.Compact; -using System.Runtime.CompilerServices; -using System.Diagnostics; -using Serilog.Context; +using Serilog.Formatting.Json; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text.RegularExpressions; namespace PepperDash.Core { @@ -27,6 +24,8 @@ public static class Debug { private static readonly string LevelStoreKey = "ConsoleDebugLevel"; private static readonly string WebSocketLevelStoreKey = "WebsocketDebugLevel"; + private static readonly string ErrorLogLevelStoreKey = "ErrorLogDebugLevel"; + private static readonly string FileLevelStoreKey = "FileDebugLevel"; private static readonly Dictionary _logLevels = new Dictionary() { @@ -44,6 +43,10 @@ public static class Debug private static readonly LoggingLevelSwitch _websocketLoggingLevelSwitch; + private static readonly LoggingLevelSwitch _errorLogLevelSwitch; + + private static readonly LoggingLevelSwitch _fileLevelSwitch; + public static LogEventLevel WebsocketMinimumLogLevel { get { return _websocketLoggingLevelSwitch.MinimumLevel; } @@ -120,10 +123,18 @@ static Debug() var defaultWebsocketLevel = GetStoredLogEventLevel(WebSocketLevelStoreKey); + var defaultErrorLogLevel = GetStoredLogEventLevel(ErrorLogLevelStoreKey); + + var defaultFileLogLevel = GetStoredLogEventLevel(FileLevelStoreKey); + _consoleLoggingLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultConsoleLevel); _websocketLoggingLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultWebsocketLevel); + _errorLogLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultErrorLogLevel); + + _fileLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultFileLogLevel); + _websocketSink = new DebugWebsocketSink(new JsonFormatter(renderMessage: true)); var logFilePath = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? @@ -137,11 +148,12 @@ static Debug() .Enrich.FromLogContext() .WriteTo.Sink(new DebugConsoleSink(new JsonFormatter(renderMessage: true)), levelSwitch: _consoleLoggingLevelSwitch) .WriteTo.Sink(_websocketSink, levelSwitch: _websocketLoggingLevelSwitch) - .WriteTo.Sink(new DebugErrorLogSink(), LogEventLevel.Information) + .WriteTo.Sink(new DebugErrorLogSink(), levelSwitch: _errorLogLevelSwitch) .WriteTo.File(new RenderedCompactJsonFormatter(), logFilePath, rollingInterval: RollingInterval.Day, restrictedToMinimumLevel: LogEventLevel.Debug, - retainedFileCountLimit: CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? 30 : 60 + retainedFileCountLimit: CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? 30 : 60, + levelSwitch: _fileLevelSwitch ); try @@ -391,9 +403,33 @@ public static void SetWebSocketMinimumDebugLevel(LogEventLevel level) var err = CrestronDataStoreStatic.SetLocalUintValue(WebSocketLevelStoreKey, (uint) level); if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) - Console(0, "Error saving websocket debug level setting: {0}", err); + LogMessage(LogEventLevel.Information, "Error saving websocket debug level setting: {erro}", err); + + LogMessage(LogEventLevel.Information, "Websocket debug level set to {0}", _websocketLoggingLevelSwitch.MinimumLevel); + } + + public static void SetErrorLogMinimumDebugLevel(LogEventLevel level) + { + _errorLogLevelSwitch.MinimumLevel = level; + + var err = CrestronDataStoreStatic.SetLocalUintValue(ErrorLogLevelStoreKey, (uint)level); + + if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) + LogMessage(LogEventLevel.Information, "Error saving Error Log debug level setting: {error}", err); + + LogMessage(LogEventLevel.Information, "Error log debug level set to {0}", _websocketLoggingLevelSwitch.MinimumLevel); + } + + public static void SetFileMinimumDebugLevel(LogEventLevel level) + { + _errorLogLevelSwitch.MinimumLevel = level; + + var err = CrestronDataStoreStatic.SetLocalUintValue(ErrorLogLevelStoreKey, (uint)level); + + if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS) + LogMessage(LogEventLevel.Information, "Error saving File debug level setting: {error}", err); - Console(0, "Websocket debug level set to {0}", _websocketLoggingLevelSwitch.MinimumLevel); + LogMessage(LogEventLevel.Information, "File debug level set to {0}", _websocketLoggingLevelSwitch.MinimumLevel); } /// @@ -576,13 +612,11 @@ public static void LogMessage(LogEventLevel level, string message, IKeyed device } } - [Obsolete("Use overload with optional IKeyed parameter")] public static void LogMessage(LogEventLevel level, string message, params object[] args) { LogMessage(level, message, null, args); } - [Obsolete("Use overload with optional IKeyed parameter")] public static void LogMessage(LogEventLevel level, IKeyed keyed, string message, params object[] args) { LogMessage(level, message, keyed, args); diff --git a/src/Pepperdash Core/Logging/DebugMemory.cs b/src/Pepperdash Core/Logging/DebugMemory.cs index 68235e4..a5737af 100644 --- a/src/Pepperdash Core/Logging/DebugMemory.cs +++ b/src/Pepperdash Core/Logging/DebugMemory.cs @@ -2,7 +2,7 @@ using Crestron.SimplSharp; using Newtonsoft.Json; -namespace PepperDash.Core.DebugThings +namespace PepperDash.Core.Logging { /// /// Class to persist current Debug settings across program restarts