diff options
-rw-r--r-- | src/StardewModdingAPI/Framework/LogFileManager.cs | 46 | ||||
-rw-r--r-- | src/StardewModdingAPI/Framework/Monitor.cs | 104 | ||||
-rw-r--r-- | src/StardewModdingAPI/IMonitor.cs | 14 | ||||
-rw-r--r-- | src/StardewModdingAPI/LogLevel.cs | 24 | ||||
-rw-r--r-- | src/StardewModdingAPI/StardewModdingAPI.csproj | 4 |
5 files changed, 192 insertions, 0 deletions
diff --git a/src/StardewModdingAPI/Framework/LogFileManager.cs b/src/StardewModdingAPI/Framework/LogFileManager.cs new file mode 100644 index 00000000..c2a2105b --- /dev/null +++ b/src/StardewModdingAPI/Framework/LogFileManager.cs @@ -0,0 +1,46 @@ +using System; +using System.IO; + +namespace StardewModdingAPI.Framework +{ + /// <summary>Manages reading and writing to log file.</summary> + internal class LogFileManager : IDisposable + { + /********* + ** Properties + *********/ + /// <summary>The underlying stream writer.</summary> + private readonly StreamWriter Stream; + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="path">The log file to write.</param> + public LogFileManager(string path) + { + // create log directory if needed + string logDir = Path.GetDirectoryName(path); + if (logDir == null) + throw new ArgumentException($"The log path '{path}' is not valid."); + Directory.CreateDirectory(logDir); + + // open log file stream + this.Stream = new StreamWriter(path, append: false) { AutoFlush = true }; + } + + /// <summary>Write a message to the log.</summary> + /// <param name="message">The message to log.</param> + public void WriteLine(string message) + { + this.Stream.WriteLine(message); + } + + /// <summary>Release all resources.</summary> + public void Dispose() + { + this.Stream.Dispose(); + } + } +}
\ No newline at end of file diff --git a/src/StardewModdingAPI/Framework/Monitor.cs b/src/StardewModdingAPI/Framework/Monitor.cs new file mode 100644 index 00000000..4fe1df04 --- /dev/null +++ b/src/StardewModdingAPI/Framework/Monitor.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace StardewModdingAPI.Framework +{ + /// <summary>Encapsulates monitoring and logic for a given module.</summary> + internal class Monitor : IMonitor + { + /********* + ** Properties + *********/ + /// <summary>The name of the module which logs messages using this instance.</summary> + private readonly string Source; + + /// <summary>The log file to which to write messages.</summary> + private readonly LogFileManager LogFile; + + /// <summary>The maximum length of the <see cref="LogLevel"/> values.</summary> + private static readonly int MaxLevelLength = (from level in Enumerable.Cast<LogLevel>(Enum.GetValues(typeof(LogLevel))) select level.ToString().Length).Max(); + + /// <summary>The console text color for each log level.</summary> + private static readonly Dictionary<LogLevel, ConsoleColor> Colors = new Dictionary<LogLevel, ConsoleColor> + { + [LogLevel.Trace] = ConsoleColor.DarkGray, + [LogLevel.Debug] = ConsoleColor.DarkGray, + [LogLevel.Info] = ConsoleColor.White, + [LogLevel.Warn] = ConsoleColor.Yellow, + [LogLevel.Error] = ConsoleColor.Red, + [LogLevel.Alert] = ConsoleColor.Magenta + }; + + + /********* + ** Accessors + *********/ + /// <summary>Whether to show trace messages in the console.</summary> + internal bool ShowTraceInConsole { get; set; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="source">The name of the module which logs messages using this instance.</param> + /// <param name="logFile">The log file to which to write messages.</param> + public Monitor(string source, LogFileManager logFile) + { + // validate + if (string.IsNullOrWhiteSpace(source)) + throw new ArgumentException("The log source cannot be empty."); + if (logFile == null) + throw new ArgumentNullException(nameof(logFile), "The log file manager cannot be null."); + + // initialise + this.Source = source; + this.LogFile = logFile; + } + + /// <summary>Log a message for the player or developer.</summary> + /// <param name="message">The message to log.</param> + /// <param name="level">The log severity level.</param> + public void Log(string message, LogLevel level = LogLevel.Debug) + { + this.LogImpl(this.Source, message, Monitor.Colors[level], level); + } + + /// <summary>Log a message for the player or developer, using the specified console color.</summary> + /// <param name="source">The name of the mod logging the message.</param> + /// <param name="message">The message to log.</param> + /// <param name="color">The console color.</param> + /// <param name="level">The log level.</param> + [Obsolete("This method is provided for backwards compatibility and otherwise should not be used. Use " + nameof(Monitor) + "." + nameof(Monitor.Log) + " instead.")] + internal void LegacyLog(string source, string message, ConsoleColor color, LogLevel level = LogLevel.Debug) + { + this.LogImpl(source, message, color, level); + } + + + /********* + ** Private methods + *********/ + /// <summary>Write a message line to the log.</summary> + /// <param name="source">The name of the mod logging the message.</param> + /// <param name="message">The message to log.</param> + /// <param name="color">The console color.</param> + /// <param name="level">The log level.</param> + private void LogImpl(string source, string message, ConsoleColor color, LogLevel level) + { + // generate message + string levelStr = level.ToString().ToUpper().PadRight(Monitor.MaxLevelLength); + message = $"[{DateTime.Now:HH:mm:ss} {levelStr} {source}] {message}"; + + // log + if (this.ShowTraceInConsole || level != LogLevel.Trace) + { + Console.ForegroundColor = color; + Console.WriteLine(message); + Console.ResetColor(); + } + this.LogFile.WriteLine(message); + } + } +}
\ No newline at end of file diff --git a/src/StardewModdingAPI/IMonitor.cs b/src/StardewModdingAPI/IMonitor.cs new file mode 100644 index 00000000..8d20af01 --- /dev/null +++ b/src/StardewModdingAPI/IMonitor.cs @@ -0,0 +1,14 @@ +namespace StardewModdingAPI +{ + /// <summary>Encapsulates monitoring and logging for a given module.</summary> + public interface IMonitor + { + /********* + ** Methods + *********/ + /// <summary>Log a message for the player or developer.</summary> + /// <param name="message">The message to log.</param> + /// <param name="level">The log severity level.</param> + void Log(string message, LogLevel level = LogLevel.Debug); + } +} diff --git a/src/StardewModdingAPI/LogLevel.cs b/src/StardewModdingAPI/LogLevel.cs new file mode 100644 index 00000000..89647876 --- /dev/null +++ b/src/StardewModdingAPI/LogLevel.cs @@ -0,0 +1,24 @@ +namespace StardewModdingAPI +{ + /// <summary>The log severity levels.</summary> + public enum LogLevel + { + /// <summary>Tracing info intended for developers.</summary> + Trace, + + /// <summary>Troubleshooting info that may be relevant to the player.</summary> + Debug, + + /// <summary>Info relevant to the player. This should be used judiciously.</summary> + Info, + + /// <summary>An issue the player should be aware of. This should be used rarely.</summary> + Warn, + + /// <summary>A message indicating something went wrong.</summary> + Error, + + /// <summary>Important information to highlight for the player when player action is needed (e.g. new version available). This should be used rarely to avoid alert fatigue.</summary> + Alert + } +}
\ No newline at end of file diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj index ce302b95..2d6a7c7f 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -195,14 +195,18 @@ <Compile Include="Extensions.cs" /> <Compile Include="Framework\DeprecationLevel.cs" /> <Compile Include="Framework\DeprecationManager.cs" /> + <Compile Include="Framework\LogFileManager.cs" /> + <Compile Include="LogLevel.cs" /> <Compile Include="Framework\ModRegistry.cs" /> <Compile Include="Framework\UpdateHelper.cs" /> <Compile Include="Framework\GitRelease.cs" /> <Compile Include="Framework\UserSettings.cs" /> + <Compile Include="IMonitor.cs" /> <Compile Include="Inheritance\ChangeType.cs" /> <Compile Include="Inheritance\ItemStackChange.cs" /> <Compile Include="Inheritance\SObject.cs" /> <Compile Include="Log.cs" /> + <Compile Include="Framework\Monitor.cs" /> <Compile Include="LogInfo.cs" /> <Compile Include="LogWriter.cs" /> <Compile Include="Manifest.cs" /> |