2016-03-27 09:57:00 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace StardewModdingAPI
|
|
|
|
|
{
|
|
|
|
|
public static class Log
|
|
|
|
|
{
|
|
|
|
|
private static readonly LogWriter _writer;
|
|
|
|
|
|
|
|
|
|
static Log()
|
|
|
|
|
{
|
|
|
|
|
_writer = LogWriter.Instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void PrintLog(LogInfo li)
|
|
|
|
|
{
|
|
|
|
|
_writer.WriteToLog(li);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region Sync Logging
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-03-27 13:09:09 +08:00
|
|
|
|
/// NOTICE: Sync logging is discouraged. Please use Async instead.
|
2016-03-27 09:57:00 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="message">Message to log</param>
|
|
|
|
|
/// <param name="colour">Colour of message</param>
|
|
|
|
|
public static void SyncColour(object message, ConsoleColor colour)
|
|
|
|
|
{
|
|
|
|
|
PrintLog(new LogInfo(message?.ToString(), colour));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2016-03-27 13:09:09 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Catch unhandled exception from the application
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>Should be moved out of here if we do more than just log the exception.</remarks>
|
|
|
|
|
public static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("An exception has been caught");
|
|
|
|
|
File.WriteAllText(Constants.LogDir + "\\MODDED_ErrorLog.Log_" + DateTime.UtcNow.Ticks + ".txt", e.ExceptionObject.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Catch thread exception from the application
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <remarks>Should be moved out of here if we do more than just log the exception.</remarks>
|
|
|
|
|
public static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("A thread exception has been caught");
|
|
|
|
|
File.WriteAllText(Constants.LogDir + "\\MODDED_ErrorLog.Log_" + Extensions.Random.Next(100000000, 999999999) + ".txt", e.Exception.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-27 09:57:00 +08:00
|
|
|
|
#region Async Logging
|
|
|
|
|
|
|
|
|
|
public static void AsyncColour(object message, ConsoleColor colour)
|
|
|
|
|
{
|
2016-03-27 13:09:09 +08:00
|
|
|
|
Task.Run(() => { PrintLog(new LogInfo(message?.ToString(), colour)); });
|
2016-03-27 09:57:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void Async(object message)
|
|
|
|
|
{
|
|
|
|
|
AsyncColour(message?.ToString(), ConsoleColor.Gray);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void AsyncR(object message)
|
|
|
|
|
{
|
|
|
|
|
AsyncColour(message?.ToString(), ConsoleColor.Red);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void AsyncO(object message)
|
|
|
|
|
{
|
|
|
|
|
AsyncColour(message.ToString(), ConsoleColor.DarkYellow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void AsyncY(object message)
|
|
|
|
|
{
|
|
|
|
|
AsyncColour(message?.ToString(), ConsoleColor.Yellow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void AsyncG(object message)
|
|
|
|
|
{
|
|
|
|
|
AsyncColour(message?.ToString(), ConsoleColor.Green);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void AsyncC(object message)
|
|
|
|
|
{
|
|
|
|
|
AsyncColour(message?.ToString(), ConsoleColor.Cyan);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void AsyncM(object message)
|
|
|
|
|
{
|
|
|
|
|
AsyncColour(message?.ToString(), ConsoleColor.Magenta);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ToRemove
|
|
|
|
|
|
|
|
|
|
public static void LogValueNotSpecified()
|
|
|
|
|
{
|
2016-03-27 13:09:09 +08:00
|
|
|
|
AsyncR("<value> must be specified");
|
2016-03-27 09:57:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void LogObjectValueNotSpecified()
|
|
|
|
|
{
|
2016-03-27 13:09:09 +08:00
|
|
|
|
AsyncR("<object> and <value> must be specified");
|
2016-03-27 09:57:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void LogValueInvalid()
|
|
|
|
|
{
|
2016-03-27 13:09:09 +08:00
|
|
|
|
AsyncR("<value> is invalid");
|
2016-03-27 09:57:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void LogObjectInvalid()
|
|
|
|
|
{
|
2016-03-27 13:09:09 +08:00
|
|
|
|
AsyncR("<object> is invalid");
|
2016-03-27 09:57:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void LogValueNotInt32()
|
|
|
|
|
{
|
2016-03-27 13:09:09 +08:00
|
|
|
|
AsyncR("<value> must be a whole number (Int32)");
|
2016-03-27 09:57:00 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Obsolete("Parameter 'values' is no longer supported. Format before logging.")]
|
|
|
|
|
private static void PrintLog(object message, bool disableLogging, params object[] values)
|
|
|
|
|
{
|
|
|
|
|
PrintLog(new LogInfo(message?.ToString()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Obsolete("Parameter 'values' is no longer supported. Format before logging.")]
|
|
|
|
|
public static void Success(object message, params object[] values)
|
|
|
|
|
{
|
|
|
|
|
AsyncG(message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Obsolete("Parameter 'values' is no longer supported. Format before logging.")]
|
|
|
|
|
public static void Verbose(object message, params object[] values)
|
|
|
|
|
{
|
|
|
|
|
Async(message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Obsolete("Parameter 'values' is no longer supported. Format before logging.")]
|
|
|
|
|
public static void Comment(object message, params object[] values)
|
|
|
|
|
{
|
|
|
|
|
AsyncC(message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Obsolete("Parameter 'values' is no longer supported. Format before logging.")]
|
|
|
|
|
public static void Info(object message, params object[] values)
|
|
|
|
|
{
|
|
|
|
|
AsyncY(message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Obsolete("Parameter 'values' is no longer supported. Format before logging.")]
|
2016-03-27 13:09:09 +08:00
|
|
|
|
public static void AsyncR(object message, params object[] values)
|
2016-03-27 09:57:00 +08:00
|
|
|
|
{
|
|
|
|
|
AsyncR(message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Obsolete("Parameter 'values' is no longer supported. Format before logging.")]
|
|
|
|
|
public static void Debug(object message, params object[] values)
|
|
|
|
|
{
|
|
|
|
|
AsyncO(message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-03-27 13:09:09 +08:00
|
|
|
|
/// A Logging class implementing the Singleton pattern and an internal Queue to be flushed perdiodically
|
2016-03-27 09:57:00 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
public class LogWriter
|
|
|
|
|
{
|
|
|
|
|
private static LogWriter _instance;
|
|
|
|
|
private static ConcurrentQueue<LogInfo> _logQueue;
|
|
|
|
|
private static DateTime _lastFlushTime = DateTime.Now;
|
|
|
|
|
private static StreamWriter _stream;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-03-27 13:09:09 +08:00
|
|
|
|
/// Private to prevent creation of other instances
|
2016-03-27 09:57:00 +08:00
|
|
|
|
/// </summary>
|
2016-03-27 13:09:09 +08:00
|
|
|
|
private LogWriter()
|
|
|
|
|
{
|
|
|
|
|
}
|
2016-03-27 09:57:00 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-03-27 13:09:09 +08:00
|
|
|
|
/// Exposes _instace and creates a new one if it is null
|
2016-03-27 09:57:00 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
internal static LogWriter Instance
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
if (_instance == null)
|
|
|
|
|
{
|
|
|
|
|
_instance = new LogWriter();
|
|
|
|
|
// Field cannot be used by anything else regardless, do not surround with lock { }
|
|
|
|
|
// ReSharper disable once InconsistentlySynchronizedField
|
|
|
|
|
_logQueue = new ConcurrentQueue<LogInfo>();
|
|
|
|
|
Console.WriteLine(Constants.LogPath);
|
|
|
|
|
_stream = new StreamWriter(Constants.LogPath, false);
|
|
|
|
|
Console.WriteLine("Created log instance");
|
|
|
|
|
}
|
|
|
|
|
return _instance;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-03-27 13:09:09 +08:00
|
|
|
|
/// Writes into the ConcurrentQueue the Message specified
|
2016-03-27 09:57:00 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="message">The message to write to the log</param>
|
|
|
|
|
public void WriteToLog(string message)
|
|
|
|
|
{
|
|
|
|
|
lock (_logQueue)
|
|
|
|
|
{
|
2016-03-27 13:09:09 +08:00
|
|
|
|
var logEntry = new LogInfo(message);
|
2016-03-27 09:57:00 +08:00
|
|
|
|
_logQueue.Enqueue(logEntry);
|
|
|
|
|
|
|
|
|
|
if (_logQueue.Any())
|
|
|
|
|
{
|
|
|
|
|
FlushLog();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-03-27 13:09:09 +08:00
|
|
|
|
/// Writes into the ConcurrentQueue the Entry specified
|
2016-03-27 09:57:00 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="logEntry">The logEntry to write to the log</param>
|
|
|
|
|
public void WriteToLog(LogInfo logEntry)
|
|
|
|
|
{
|
|
|
|
|
lock (_logQueue)
|
|
|
|
|
{
|
|
|
|
|
_logQueue.Enqueue(logEntry);
|
|
|
|
|
|
|
|
|
|
if (_logQueue.Any())
|
|
|
|
|
{
|
|
|
|
|
FlushLog();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-03-27 13:09:09 +08:00
|
|
|
|
/// Flushes the ConcurrentQueue to the log file specified in Constants
|
2016-03-27 09:57:00 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
private void FlushLog()
|
|
|
|
|
{
|
|
|
|
|
lock (_stream)
|
|
|
|
|
{
|
|
|
|
|
LogInfo entry;
|
|
|
|
|
while (_logQueue.TryDequeue(out entry))
|
|
|
|
|
{
|
|
|
|
|
string m = $"[{entry.LogTime}] {entry.Message}";
|
|
|
|
|
|
|
|
|
|
Console.ForegroundColor = entry.Colour;
|
|
|
|
|
Console.WriteLine(m);
|
|
|
|
|
Console.ForegroundColor = ConsoleColor.Gray;
|
|
|
|
|
|
|
|
|
|
_stream.WriteLine(m);
|
|
|
|
|
}
|
|
|
|
|
_stream.Flush();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2016-03-27 13:09:09 +08:00
|
|
|
|
/// A struct to store the message and the Date and Time the log entry was created
|
2016-03-27 09:57:00 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
public struct LogInfo
|
|
|
|
|
{
|
|
|
|
|
public string Message { get; set; }
|
|
|
|
|
public string LogTime { get; set; }
|
|
|
|
|
public string LogDate { get; set; }
|
|
|
|
|
public ConsoleColor Colour { get; set; }
|
|
|
|
|
|
|
|
|
|
public LogInfo(string message, ConsoleColor colour = ConsoleColor.Gray)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(message))
|
|
|
|
|
message = "[null]";
|
|
|
|
|
Message = message;
|
|
|
|
|
LogDate = DateTime.Now.ToString("yyyy-MM-dd");
|
|
|
|
|
LogTime = DateTime.Now.ToString("hh:mm:ss.fff tt");
|
|
|
|
|
Colour = colour;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|