From 3618dbbd25c6f6f25bd50f0dd8cc1bf747a8169f Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 11 Oct 2024 13:06:00 -0400 Subject: [PATCH] add debug logging level (#1605) --- OneMore/Commands/Settings/GeneralSheet.cs | 28 ++- OneMore/Helpers/ILogger.cs | 96 +++++--- OneMore/Helpers/Logger.cs | 257 ++++++++++++++-------- 3 files changed, 250 insertions(+), 131 deletions(-) diff --git a/OneMore/Commands/Settings/GeneralSheet.cs b/OneMore/Commands/Settings/GeneralSheet.cs index b8265eab5f..a0c6883ad2 100644 --- a/OneMore/Commands/Settings/GeneralSheet.cs +++ b/OneMore/Commands/Settings/GeneralSheet.cs @@ -55,8 +55,19 @@ public GeneralSheet(SettingsProvider provider) : base(provider) } checkUpdatesBox.Checked = settings.Get("checkUpdates", false); - verboseBox.Checked = settings.Get("verbose", false); experimentalBox.Checked = settings.Get("experimental", false); + + // verbose|debug is the new way + // true was the old way + var loglevel = settings.Get("logging", string.Empty).ToLower(); + verboseBox.Checked = loglevel.Length == 0 + ? settings.Get("verbose", false) + : loglevel.In("verbose", "debug"); + + if (loglevel == "debug") + { + verboseBox.Enabled = false; + } } @@ -125,11 +136,18 @@ public override bool CollectSettings() ? settings.Add("checkUpdates", true) || save : settings.Remove("checkUpdates") || save; - // requires a restart - updated = verboseBox.Checked - ? settings.Add("verbose", true) || updated - : settings.Remove("verbose") || updated; + // does not require a restart; only Enabled if !debug + if (verboseBox.Enabled) + { + save = verboseBox.Checked + ? settings.Add("logging", "verbose") || save + : settings.Remove("logging") || save; + + ((Logger)logger).SetLoggingLevel(verboseBox.Checked, false); + save = settings.Remove("verbose") || save; + } + // requires a restart updated = experimentalBox.Checked ? settings.Add("experimental", true) || updated : settings.Remove("experimental") || updated; diff --git a/OneMore/Helpers/ILogger.cs b/OneMore/Helpers/ILogger.cs index b22d323844..03a09e54ab 100644 --- a/OneMore/Helpers/ILogger.cs +++ b/OneMore/Helpers/ILogger.cs @@ -20,6 +20,43 @@ public interface ILogger : IDisposable string LogPath { get; } + /// + /// If debug logging is enabled, writes a blank line to the log file + /// + void Debug(); + + + /// + /// If debug logging is enabled, writes a text message along with a newline. + /// Could be a new entry or an entry started with a Write + /// + /// + void Debug(string message); + + + /// + /// If debug logging is enabled, writes the XML of the given XElement + /// + /// + void Debug(XElement element); + + + /// + /// If debug logging is enabled, stops the stopwatch and Writes a message along + /// with the mm.ss timespan since the stopwatch was started. + /// + /// The message to log + /// True to keep the timer running + void DebugTime(string message, bool keepRunning = false); + + + /// + /// Dumps all accessible properties of the given object to JSON + /// + /// + void Dump(object obj); + + /// /// Ends the current log section; clears the preamble /// @@ -53,10 +90,33 @@ public interface ILogger : IDisposable /// - /// Dumps all accessible properties of the given object to JSON + /// If verbose logging is enabled, writes a blank line to the log file /// - /// - void Dump(object obj); + void Verbose(); + + + /// + /// If verbose logging is enabled, writes a text message along with a newline. + /// Could be a new entry or an entry started with a Write + /// + /// + void Verbose(string message); + + + /// + /// If verbose logging is enabled, writes the XML of the given XElement + /// + /// + void Verbose(XElement element); + + + /// + /// If verbose logging is enabled, stops the stopwatch and Writes a message along + /// with the mm.ss timespan since the stopwatch was started. + /// + /// The message to log + /// True to keep the timer running + void VerboseTime(string message, bool keepRunning = false); /// @@ -112,36 +172,6 @@ public interface ILogger : IDisposable void WriteLine(XElement element); - /// - /// If verbose logging is enabled, writes a blank line to the log file - /// - void Verbose(); - - - /// - /// If verbose logging is enabled, writes a text message along with a newline. - /// Could be a new entry or an entry started with a Write - /// - /// - void Verbose(string message); - - - /// - /// If verbose logging is enabled, writes the XML of the given XElement - /// - /// - void Verbose(XElement element); - - - /// - /// If verbose logging is enabled, stops the stopwatch and Writes a message along - /// with the mm.ss timespan since the stopwatch was started. - /// - /// The message to log - /// True to keep the timer running - void VerboseTime(string message, bool keepRunning = false); - - /// /// Stops the stopwatch and Writes a message along with the mm.ss timespan /// since the stopwatch was started. diff --git a/OneMore/Helpers/Logger.cs b/OneMore/Helpers/Logger.cs index 959f62bdbd..0a2798d1a7 100644 --- a/OneMore/Helpers/Logger.cs +++ b/OneMore/Helpers/Logger.cs @@ -25,7 +25,8 @@ internal class Logger : ILogger private static string appname = "OneMore"; private readonly bool stdio; - private readonly bool verbose; + private bool debug; + private bool verbose; private string preamble; private string timeBar; private bool isNewline; @@ -60,14 +61,29 @@ private Logger() { try { + // keep Logger independent of SettingsProvider var root = XElement.Load(path); var settings = root .Elements(nameof(Settings.GeneralSheet)) .FirstOrDefault(); - if (settings != null) + if (settings is not null) { - verbose = "true".EqualsICIC(settings.Element("verbose")?.Value); + if (settings.Element("logging") is XElement loption) + { + if (loption.Value.EqualsICIC("debug")) + { + verbose = debug = true; + } + else if (loption.Value.EqualsICIC("verbose")) + { + verbose = true; + } + } + else if (settings.Element("verbose") is XElement voption) + { + verbose = "true".EqualsICIC(voption.Value); + } } } catch (Exception exc) @@ -95,7 +111,7 @@ protected virtual void Dispose(bool disposing) clock?.Stop(); clock = null; - if (writer != null) + if (writer is not null) { writer.Flush(); writer.Dispose(); @@ -122,36 +138,9 @@ public static ILogger Current public string LogPath { get; private set; } - private bool EnsureWriter() - { - if (stdio) - return true; - - if (writer == null) - { - try - { - // allow the UTF8 output stream to handle Unicode characters - // by falling back to default replacement characters like '?' - var encodingWithFallback = (Encoding)(new UTF8Encoding(false)).Clone(); - encodingWithFallback.EncoderFallback = EncoderFallback.ReplacementFallback; - encodingWithFallback.DecoderFallback = DecoderFallback.ReplacementFallback; - - writer = new StreamWriter(LogPath, true, encodingWithFallback); - } - catch - { - writer = null; - } - } - - return (writer != null); - } - - public void Clear() { - if (writer != null) + if (writer is not null) { writer.Flush(); writer.Dispose(); @@ -170,6 +159,61 @@ public void Clear() } + public void Debug() + { + if (debug) + { + timeBar = "+"; + WriteLine(); + timeBar = "|"; + } + } + + + public void Debug(string message) + { + if (debug) + { + timeBar = "+"; + WriteLine(message); + timeBar = "|"; + } + } + + + public void Debug(XElement element) + { + if (debug) + { + timeBar = "+"; + WriteLine(element); + timeBar = "|"; + } + } + + + public void DebugTime(string message, bool keepRunning = false) + { + if (debug) + { + timeBar = "+"; + WriteTime(message, keepRunning); + timeBar = "|"; + } + } + + + public void Dump(object obj) + { + var frame = new StackTrace(true).GetFrame(1); + WriteLine($"DUMP {obj.GetType().FullName} " + + $"from ({Path.GetFileName(frame.GetFileName())} " + + $"@line {frame.GetFileLineNumber()})"); + + WriteLine(JsonConvert.SerializeObject(obj, Formatting.Indented)); + } + + public void End() { preamble = string.Empty; @@ -177,23 +221,43 @@ public void End() } + /// + /// Call this immediately after starting the application and before any logging. + /// The application name implies the name of the log file on disk. + /// + /// The simple name of the application public static void SetApplication(string name) { appname = name; } - // For VS Forms designer + /// + /// For VS Forms designer + /// + /// Pass in the Forms.DesignMode property! public static void SetDesignMode(bool mode) { designMode = mode; } + /// + /// Directly set verbose/debug logging flags, for use by GeneralSettings. + /// Consumer needs explict cast to Logger class + /// + /// + /// + public void SetLoggingLevel(bool verbose, bool debug) + { + this.verbose = verbose || debug; + this.debug = debug; + } + public void Start(string message = null) { - if (message != null) + if (message is not null) { WriteLine(message); } @@ -204,7 +268,7 @@ public void Start(string message = null) public void StartClock() { - if (clock == null) + if (clock is null) { clock = new Stopwatch(); } @@ -229,14 +293,47 @@ public void StopClock() } - public void Dump(object obj) + public void Verbose() { - var frame = new StackTrace(true).GetFrame(1); - WriteLine($"DUMP {obj.GetType().FullName} " + - $"from ({Path.GetFileName(frame.GetFileName())} " + - $"@line {frame.GetFileLineNumber()})"); + if (verbose) + { + timeBar = "+"; + WriteLine(); + timeBar = "|"; + } + } - WriteLine(JsonConvert.SerializeObject(obj, Formatting.Indented)); + + public void Verbose(string message) + { + if (verbose) + { + timeBar = "+"; + WriteLine(message); + timeBar = "|"; + } + } + + + public void Verbose(XElement element) + { + if (verbose) + { + timeBar = "+"; + WriteLine(element); + timeBar = "|"; + } + } + + + public void VerboseTime(string message, bool keepRunning = false) + { + if (verbose) + { + timeBar = "+"; + WriteTime(message, keepRunning); + timeBar = "|"; + } } @@ -360,75 +457,49 @@ public void WriteLine(XElement element) } - public void WriteVerbose(string message) + public void WriteTime(string message, bool keepRunning = false) { - if (verbose) + if (clock is null) { - timeBar = "+"; - Write(message); - timeBar = "|"; + WriteLine($"--:--.-- {message} @ "); + return; } - } - - public void Verbose() - { - if (verbose) + if (!keepRunning && clock.IsRunning) { - timeBar = "+"; - WriteLine(); - timeBar = "|"; + clock.Stop(); } - } - - public void Verbose(string message) - { - if (verbose) - { - timeBar = "+"; - WriteLine(message); - timeBar = "|"; - } + WriteLine($"{clock.Elapsed:mm\\:ss\\.ff} {message}"); } - public void Verbose(XElement element) - { - if (verbose) - { - timeBar = "+"; - WriteLine(element); - timeBar = "|"; - } - } - + // helpers... - public void VerboseTime(string message, bool keepRunning = false) + private bool EnsureWriter() { - if (verbose) - { - timeBar = "+"; - WriteTime(message, keepRunning); - timeBar = "|"; - } - } - + if (stdio) + return true; - public void WriteTime(string message, bool keepRunning = false) - { - if (clock == null) + if (writer is null) { - WriteLine($"--:--.-- {message} @ "); - return; - } + try + { + // allow the UTF8 output stream to handle Unicode characters + // by falling back to default replacement characters like '?' + var encodingWithFallback = (Encoding)(new UTF8Encoding(false)).Clone(); + encodingWithFallback.EncoderFallback = EncoderFallback.ReplacementFallback; + encodingWithFallback.DecoderFallback = DecoderFallback.ReplacementFallback; - if (!keepRunning && clock.IsRunning) - { - clock.Stop(); + writer = new StreamWriter(LogPath, true, encodingWithFallback); + } + catch + { + writer = null; + } } - WriteLine($"{clock.Elapsed:mm\\:ss\\.ff} {message}"); + return (writer is not null); }