summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release-notes.md10
-rw-r--r--src/StardewModdingAPI/Log.cs86
-rw-r--r--src/StardewModdingAPI/LogWriter.cs68
-rw-r--r--src/StardewModdingAPI/Program.cs4
4 files changed, 90 insertions, 78 deletions
diff --git a/release-notes.md b/release-notes.md
index 980e5414..a6a9ea94 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -1,5 +1,15 @@
# Release notes
+## 1.1
+See [log](https://github.com/CLxS/SMAPI/compare/1.0...master).
+
+* Improved logging:
+ * simplified logging API;
+ * added support for trace logs (written to the log file, but hidden in the console by default);
+ * critical errors are now sent to the regular log instead of a separate file;
+ * messages are now shown in order;
+ * messages now show which mod logged them.
+
## 1.0
See [log](https://github.com/CLxS/SMAPI/compare/0.40.1.1-3...1.0).
diff --git a/src/StardewModdingAPI/Log.cs b/src/StardewModdingAPI/Log.cs
index 665e727f..b1af111c 100644
--- a/src/StardewModdingAPI/Log.cs
+++ b/src/StardewModdingAPI/Log.cs
@@ -1,22 +1,25 @@
using System;
-using System.IO;
using System.Threading;
-using System.Threading.Tasks;
using StardewModdingAPI.Framework;
+using Monitor = StardewModdingAPI.Framework.Monitor;
namespace StardewModdingAPI
{
/// <summary>A singleton which logs messages to the SMAPI console and log file.</summary>
+ [Obsolete("Use " + nameof(Mod) + "." + nameof(Mod.Monitor))]
public static class Log
{
/*********
- ** Properties
+ ** Accessors
*********/
- /// <summary>A pseudorandom number generator used to generate log files.</summary>
- private static readonly Random Random = new Random();
+ /// <summary>The underlying logger.</summary>
+ internal static Monitor Monitor;
- /// <summary>The underlying log writer.</summary>
- private static readonly LogWriter Writer = new LogWriter(Constants.LogPath);
+ /// <summary>Tracks the installed mods.</summary>
+ internal static ModRegistry ModRegistry;
+
+ /// <summary>A temporary field to avoid infinite loops (since we use a deprecated interface to warn about the deprecated interface).</summary>
+ private static bool WarnedDeprecated;
/*********
@@ -30,8 +33,8 @@ namespace StardewModdingAPI
/// <param name="e">The event arguments.</param>
public static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
- Console.WriteLine("An exception has been caught");
- File.WriteAllText(Path.Combine(Constants.LogDir, $"MODDED_ErrorLog.Log_{DateTime.UtcNow.Ticks}.txt"), e.ExceptionObject.ToString());
+ Log.WarnDeprecated();
+ Log.Monitor.Log($"Critical app domain exception: {e.ExceptionObject}", LogLevel.Error);
}
/// <summary>Log a thread exception event.</summary>
@@ -39,8 +42,8 @@ namespace StardewModdingAPI
/// <param name="e">The event arguments.</param>
public static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
- Console.WriteLine("A thread exception has been caught");
- File.WriteAllText(Path.Combine(Constants.LogDir, $"MODDED_ErrorLog.Log_{Log.Random.Next(100000000, 999999999)}.txt"), e.Exception.ToString());
+ Log.WarnDeprecated();
+ Log.Monitor.Log($"Critical thread exception: {e.Exception}", LogLevel.Error);
}
/****
@@ -51,7 +54,8 @@ namespace StardewModdingAPI
/// <param name="color">The message color.</param>
public static void SyncColour(object message, ConsoleColor color)
{
- Log.PrintLog(new LogInfo(message?.ToString(), color));
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), color);
}
/****
@@ -62,76 +66,87 @@ namespace StardewModdingAPI
/// <param name="color">The message color.</param>
public static void AsyncColour(object message, ConsoleColor color)
{
- Task.Run(() => { Log.PrintLog(new LogInfo(message?.ToString(), color)); });
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), color);
}
/// <summary>Asynchronously log a message to the console.</summary>
/// <param name="message">The message to log.</param>
public static void Async(object message)
{
- Log.AsyncColour(message?.ToString(), ConsoleColor.Gray);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.Gray);
}
/// <summary>Asynchronously log a red message to the console.</summary>
/// <param name="message">The message to log.</param>
public static void AsyncR(object message)
{
- Log.AsyncColour(message?.ToString(), ConsoleColor.Red);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.Red);
}
/// <summary>Asynchronously log an orange message to the console.</summary>
/// <param name="message">The message to log.</param>
public static void AsyncO(object message)
{
- Log.AsyncColour(message.ToString(), ConsoleColor.DarkYellow);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.DarkYellow);
}
/// <summary>Asynchronously log a yellow message to the console.</summary>
/// <param name="message">The message to log.</param>
public static void AsyncY(object message)
{
- Log.AsyncColour(message?.ToString(), ConsoleColor.Yellow);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.Yellow);
}
/// <summary>Asynchronously log a green message to the console.</summary>
/// <param name="message">The message to log.</param>
public static void AsyncG(object message)
{
- Log.AsyncColour(message?.ToString(), ConsoleColor.Green);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.Green);
}
/// <summary>Asynchronously log a cyan message to the console.</summary>
/// <param name="message">The message to log.</param>
public static void AsyncC(object message)
{
- Log.AsyncColour(message?.ToString(), ConsoleColor.Cyan);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.Cyan);
}
/// <summary>Asynchronously log a magenta message to the console.</summary>
/// <param name="message">The message to log.</param>
public static void AsyncM(object message)
{
- Log.AsyncColour(message?.ToString(), ConsoleColor.Magenta);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.Magenta);
}
/// <summary>Asynchronously log a warning to the console.</summary>
/// <param name="message">The message to log.</param>
public static void Warning(object message)
{
- Log.AsyncColour("[WARN] " + message, ConsoleColor.DarkRed);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.Yellow, LogLevel.Warn);
}
/// <summary>Asynchronously log an error to the console.</summary>
/// <param name="message">The message to log.</param>
public static void Error(object message)
{
- Log.AsyncR("[ERROR] " + message);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.Red, LogLevel.Error);
}
/// <summary>Asynchronously log a success message to the console.</summary>
/// <param name="message">The message to log.</param>
public static void Success(object message)
{
+ Log.WarnDeprecated();
Log.AsyncG(message);
}
@@ -139,31 +154,44 @@ namespace StardewModdingAPI
/// <param name="message">The message to log.</param>
public static void Info(object message)
{
- Log.AsyncY(message);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.White, LogLevel.Info);
}
/// <summary>Asynchronously log a debug message to the console.</summary>
/// <param name="message">The message to log.</param>
public static void Debug(object message)
{
- Log.AsyncColour(message, ConsoleColor.DarkGray);
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message?.ToString(), ConsoleColor.DarkGray);
}
/// <summary>Asynchronously log a message to the file that's not shown in the console.</summary>
/// <param name="message">The message to log.</param>
internal static void LogToFile(string message)
{
- Task.Run(() => { Log.PrintLog(new LogInfo(message) { PrintConsole = false }); });
+ Log.WarnDeprecated();
+ Log.Monitor.LegacyLog(Log.GetModName(), message, ConsoleColor.DarkGray, LogLevel.Trace);
}
+
/*********
** Private methods
*********/
- /// <summary>Write a message to the log.</summary>
- /// <param name="message">The message to write.</param>
- private static void PrintLog(LogInfo message)
+ /// <summary>Raise a deprecation warning.</summary>
+ private static void WarnDeprecated()
+ {
+ if (!Log.WarnedDeprecated)
+ {
+ Log.WarnedDeprecated = true;
+ Program.DeprecationManager.Warn($"the {nameof(Log)} class", "1.1", DeprecationLevel.Notice);
+ }
+ }
+
+ /// <summary>Get the name of the mod logging a message from the stack.</summary>
+ private static string GetModName()
{
- Log.Writer.WriteToLog(message);
+ return Log.ModRegistry.GetModFromStack() ?? "<unknown mod>";
}
}
} \ No newline at end of file
diff --git a/src/StardewModdingAPI/LogWriter.cs b/src/StardewModdingAPI/LogWriter.cs
index c8c9b9e1..11bcf5f3 100644
--- a/src/StardewModdingAPI/LogWriter.cs
+++ b/src/StardewModdingAPI/LogWriter.cs
@@ -1,7 +1,5 @@
using System;
-using System.Collections.Concurrent;
-using System.IO;
-using System.Linq;
+using StardewModdingAPI.Framework;
namespace StardewModdingAPI
{
@@ -13,79 +11,51 @@ namespace StardewModdingAPI
/*********
** Properties
*********/
- /// <summary>The queued messages to flush.</summary>
- private readonly ConcurrentQueue<LogInfo> Queue;
-
- /// <summary>The underlying file stream.</summary>
- private readonly StreamWriter FileStream;
+ /// <summary>Manages reading and writing to the log file.</summary>
+ private readonly LogFileManager LogFile;
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
- /// <param name="path">The log path to write.</param>
- public LogWriter(string path)
+ /// <param name="logFile">Manages reading and writing to the log file.</param>
+ internal LogWriter(LogFileManager logFile)
{
- // create log directory (required for stream writer)
- Directory.CreateDirectory(Path.GetDirectoryName(path));
-
- // initialise
- this.Queue = new ConcurrentQueue<LogInfo>();
- this.FileStream = new StreamWriter(Constants.LogPath, false);
+ this.WarnDeprecated();
+ this.LogFile = logFile;
}
/// <summary>Queue a message for output.</summary>
/// <param name="message">The message to log.</param>
public void WriteToLog(string message)
{
- lock (this.Queue)
- {
- var logEntry = new LogInfo(message);
- this.Queue.Enqueue(logEntry);
-
- if (this.Queue.Any())
- this.FlushLog();
- }
+ this.WarnDeprecated();
+ this.WriteToLog(new LogInfo(message));
}
/// <summary>Queue a message for output.</summary>
/// <param name="message">The message to log.</param>
public void WriteToLog(LogInfo message)
{
- lock (this.Queue)
+ this.WarnDeprecated();
+ string output = $"[{message.LogTime}] {message.Message}";
+ if (message.PrintConsole)
{
- this.Queue.Enqueue(message);
- if (this.Queue.Any())
- this.FlushLog();
+ Console.ForegroundColor = message.Colour;
+ Console.WriteLine(message);
+ Console.ForegroundColor = ConsoleColor.Gray;
}
+ this.LogFile.WriteLine(output);
}
-
/*********
** Private methods
*********/
- /// <summary>Flush the underlying queue to the console and file.</summary>
- private void FlushLog()
+ /// <summary>Raise a deprecation warning.</summary>
+ private void WarnDeprecated()
{
- lock (this.FileStream)
- {
- LogInfo entry;
- while (this.Queue.TryDequeue(out entry))
- {
- string message = $"[{entry.LogTime}] {entry.Message}";
-
- if (entry.PrintConsole)
- {
- Console.ForegroundColor = entry.Colour;
- Console.WriteLine(message);
- Console.ForegroundColor = ConsoleColor.Gray;
- }
-
- this.FileStream.WriteLine(message);
- }
- this.FileStream.Flush();
- }
+ Program.DeprecationManager.Warn($"the {nameof(LogWriter)} class", "1.0", DeprecationLevel.Notice);
}
}
} \ No newline at end of file
diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs
index 859d3659..f4416e70 100644
--- a/src/StardewModdingAPI/Program.cs
+++ b/src/StardewModdingAPI/Program.cs
@@ -103,6 +103,10 @@ namespace StardewModdingAPI
}
}
+ // initialise legacy log
+ Log.Monitor = new Monitor("legacy mod", Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode };
+ Log.ModRegistry = Program.ModRegistry;
+
// hook into & launch the game
try
{