@ -1 +1 @@ | |||
6744afebdfdc05ced46858bdac21e047b0d6e43f | |||
33cd6c2ad2a5a7958d22e4f89028cf896273055b |
@ -1,4 +1,4 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<packages> | |||
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net35-client" requireReinstallation="true" /> | |||
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net462" /> | |||
</packages> |
@ -0,0 +1,26 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace IllusionPlugin.Logging.Printers | |||
{ | |||
public class ColoredConsolePrinter : LogPrinter | |||
{ | |||
Logger.LogLevel filter = Logger.LogLevel.All; | |||
public override Logger.LogLevel Filter { get => filter; set => filter = value; } | |||
ConsoleColor color = Console.ForegroundColor; | |||
public ConsoleColor Color { get => color; set => color = value; } | |||
public override void Print(Logger.Level level, DateTime time, string logName, string message) | |||
{ | |||
if (((byte)level & (byte)Filter) == 0) return; | |||
Console.ForegroundColor = color; | |||
foreach (var line in message.Split(new string[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) | |||
Console.WriteLine(string.Format(Logger.LogFormat, line, logName, time, level.ToString().ToUpper())); | |||
Console.ResetColor(); | |||
} | |||
} | |||
} |
@ -0,0 +1,55 @@ | |||
using IllusionPlugin.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
using zlib; | |||
namespace IllusionInjector.Logging.Printers | |||
{ | |||
public class GlobalZFIlePrinter : LogPrinter | |||
{ | |||
public override IllusionPlugin.Logging.Logger.LogLevel Filter { get; set; } | |||
private FileInfo fileInfo; | |||
private StreamWriter fileWriter; | |||
private static FileInfo GetFileInfo() | |||
{ | |||
var logsDir = new DirectoryInfo("Logs"); | |||
logsDir.Create(); | |||
var finfo = new FileInfo(Path.Combine(logsDir.FullName, $"{DateTime.Now:YYYY.MM.DD.HH.MM}.log.z")); | |||
finfo.Create().Close(); | |||
return finfo; | |||
} | |||
public GlobalZFIlePrinter() | |||
{ | |||
fileInfo = GetFileInfo(); | |||
} | |||
public override void StartPrint() | |||
{ | |||
fileWriter = new StreamWriter( | |||
new ZOutputStream(fileInfo.Open(FileMode.Append, FileAccess.Write, FileShare.Read)) | |||
{ | |||
FlushMode = zlibConst.Z_FULL_FLUSH | |||
}, | |||
Encoding.UTF8 | |||
); | |||
} | |||
public override void Print(IllusionPlugin.Logging.Logger.Level level, DateTime time, string logName, string message) | |||
{ | |||
foreach (var line in message.Split(new string[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) | |||
fileWriter.WriteLine(string.Format("[{3} @ {2:HH:mm:ss} | {1}] {0}", line, logName, time, level.ToString().ToUpper())); | |||
} | |||
public override void EndPrint() | |||
{ | |||
fileWriter.Dispose(); | |||
} | |||
} | |||
} |
@ -0,0 +1,48 @@ | |||
using IllusionPlugin.Logging; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace IllusionInjector.Logging.Printers | |||
{ | |||
public class PluginLogFilePrinter : LogPrinter | |||
{ | |||
public override IllusionPlugin.Logging.Logger.LogLevel Filter { get; set; } | |||
private FileInfo fileInfo; | |||
private StreamWriter fileWriter; | |||
private static FileInfo GetFileInfo(string modName) | |||
{ | |||
var logsDir = new DirectoryInfo(Path.Combine("Logs",modName)); | |||
logsDir.Create(); | |||
var finfo = new FileInfo(Path.Combine(logsDir.FullName, $"{DateTime.Now:YYYY.MM.DD.HH.MM}.log")); | |||
finfo.CreateText().Close(); | |||
return finfo; | |||
} | |||
public PluginLogFilePrinter(string name) | |||
{ | |||
fileInfo = GetFileInfo(name); | |||
} | |||
public override void StartPrint() | |||
{ | |||
fileWriter = fileInfo.AppendText(); | |||
} | |||
public override void Print(IllusionPlugin.Logging.Logger.Level level, DateTime time, string logName, string message) | |||
{ | |||
foreach (var line in message.Split(new string[] { "\n", Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)) | |||
fileWriter.WriteLine(string.Format("[{3} @ {2:HH:mm:ss}] {0}", line, logName, time, level.ToString().ToUpper())); | |||
} | |||
public override void EndPrint() | |||
{ | |||
fileWriter.Dispose(); | |||
} | |||
} | |||
} |
@ -0,0 +1,134 @@ | |||
using IllusionInjector.Logging.Printers; | |||
using IllusionPlugin.Logging; | |||
using IllusionPlugin.Logging.Printers; | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading; | |||
using System.Threading.Tasks; | |||
using LoggerBase = IllusionPlugin.Logging.Logger; | |||
namespace IllusionInjector.Logging | |||
{ | |||
internal static class Logger | |||
{ | |||
private static LoggerBase _log; | |||
internal static LoggerBase log | |||
{ | |||
get | |||
{ | |||
if (_log == null) | |||
_log = new StandardLogger("IllusionInjector"); | |||
return _log; | |||
} | |||
} | |||
} | |||
public class StandardLogger : LoggerBase | |||
{ | |||
private static readonly IReadOnlyList<LogPrinter> defaultPrinters = new List<LogPrinter>() | |||
{ | |||
new ColoredConsolePrinter() | |||
{ | |||
Filter = LogLevel.DebugOnly, | |||
Color = ConsoleColor.Green, | |||
}, | |||
new ColoredConsolePrinter() | |||
{ | |||
Filter = LogLevel.InfoOnly, | |||
Color = ConsoleColor.White, | |||
}, | |||
new ColoredConsolePrinter() | |||
{ | |||
Filter = LogLevel.WarningOnly, | |||
Color = ConsoleColor.Yellow, | |||
}, | |||
new ColoredConsolePrinter() | |||
{ | |||
Filter = LogLevel.ErrorOnly, | |||
Color = ConsoleColor.Red, | |||
}, | |||
new ColoredConsolePrinter() | |||
{ | |||
Filter = LogLevel.CriticalOnly, | |||
Color = ConsoleColor.Magenta, | |||
}, | |||
new GlobalZFIlePrinter() | |||
}; | |||
private string logName; | |||
private static LogLevel showFilter = LogLevel.InfoUp; | |||
public static LogLevel Filter { get => showFilter; set => showFilter = value; } | |||
private List<LogPrinter> printers = new List<LogPrinter>(defaultPrinters); | |||
internal StandardLogger(string name) | |||
{ | |||
logName = name; | |||
printers.Add(new PluginLogFilePrinter(name)); | |||
if (_logThread == null || !_logThread.IsAlive) | |||
{ | |||
_logThread = new Thread(LogThread); | |||
_logThread.Start(); | |||
} | |||
} | |||
public override void Log(Level level, string message) | |||
{ | |||
_logQueue.Add(new LogMessage | |||
{ | |||
level = level, | |||
message = message, | |||
logger = this, | |||
time = DateTime.Now | |||
}); | |||
} | |||
internal struct LogMessage | |||
{ | |||
public Level level; | |||
public StandardLogger logger; | |||
public string message; | |||
public DateTime time; | |||
} | |||
private static BlockingCollection<LogMessage> _logQueue = new BlockingCollection<LogMessage>(); | |||
private static Thread _logThread; | |||
private static void LogThread() | |||
{ | |||
HashSet<LogPrinter> started = new HashSet<LogPrinter>(); | |||
while (_logQueue.TryTake(out LogMessage msg, Timeout.Infinite)) { | |||
foreach (var printer in msg.logger.printers) | |||
{ | |||
if (((byte)msg.level & (byte)printer.Filter) != 0) | |||
{ | |||
if (!started.Contains(printer)) | |||
{ | |||
printer.StartPrint(); | |||
started.Add(printer); | |||
} | |||
printer.Print(msg.level, msg.time, msg.logger.logName, msg.message); | |||
} | |||
} | |||
if (_logQueue.Count == 0) | |||
{ | |||
foreach (var printer in started) | |||
printer.EndPrint(); | |||
started.Clear(); | |||
} | |||
} | |||
} | |||
public static void StopLogThread() | |||
{ | |||
_logQueue.CompleteAdding(); | |||
_logThread.Join(); | |||
} | |||
} | |||
} |
@ -1 +1 @@ | |||
26a9be3d697b3ac9c2a8af98062cb97cf748184e | |||
524c2a9e58911edfdaf36eb5bf255b181a39f814 |
@ -0,0 +1,4 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<packages> | |||
<package id="zlib.net" version="1.0.4.0" targetFramework="net46" /> | |||
</packages> |
@ -1,190 +0,0 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Collections.Concurrent; | |||
using System.IO; | |||
using System.Runtime.Remoting.Messaging; | |||
using System.Threading; | |||
using IllusionPlugin; | |||
namespace IllusionPlugin { | |||
/// <summary> | |||
/// A general purpose logging class for any plugin to use. | |||
/// </summary> | |||
public class Logger { | |||
private static BlockingCollection<logMessage> _logQueue; | |||
private static Thread _watcherThread; | |||
private static bool _threadRunning; | |||
private readonly FileInfo _logFile; | |||
private string ModName; | |||
struct logMessage { | |||
public static readonly string logFormat = "[{3} @ {2:HH:mm:ss} | {1}] {0}"; | |||
public WarningLevel WarningLevel; | |||
public DateTime Time; | |||
public Logger Log; | |||
public string Message; | |||
public logMessage(string msg, Logger log, DateTime time, WarningLevel wl) { | |||
Message = msg; | |||
WarningLevel = wl; | |||
Log = log; | |||
Time = time; | |||
} | |||
} | |||
enum WarningLevel { | |||
Log, Error, Exception, Warning | |||
} | |||
static void SetupStatic() | |||
{ | |||
if (_logQueue == null) | |||
_logQueue = new BlockingCollection<logMessage>(); | |||
if (_watcherThread == null || !_watcherThread.IsAlive) | |||
{ | |||
_watcherThread = new Thread(QueueWatcher); // { IsBackground = true }; | |||
_threadRunning = true; | |||
_watcherThread.Start(); | |||
} | |||
} | |||
/// <summary> | |||
/// Creates a logger with the specified name. | |||
/// </summary> | |||
/// <param name="modName">the name of the logger</param> | |||
public Logger(string modName = "Default") { | |||
SetupStatic(); | |||
_logFile = GetPath(modName); | |||
_logFile.Create().Close(); | |||
} | |||
/// <summary> | |||
/// Creates a logger for the specified plugin. | |||
/// </summary> | |||
/// <param name="plugin">the plugin to associate the logger with</param> | |||
public Logger(IBeatSaberPlugin plugin) | |||
{ | |||
SetupStatic(); | |||
_logFile = GetPath(plugin); | |||
_logFile.Create().Close(); | |||
} | |||
/// <summary> | |||
/// Sends a message to the log. | |||
/// </summary> | |||
/// <param name="msg">the message to send</param> | |||
public void Log(string msg) { | |||
if(!_watcherThread.IsAlive) throw new Exception("Logger is Closed!"); | |||
//_logQueue.Add(new logMessage($"[LOG @ {DateTime.Now:HH:mm:ss} | {ModName}] {msg}", WarningLevel.Log)); | |||
_logQueue.Add(new logMessage(msg, this, DateTime.Now, WarningLevel.Log)); | |||
} | |||
/// <summary> | |||
/// Sends an error to the log. | |||
/// </summary> | |||
/// <param name="msg">the message to send</param> | |||
public void Error(string msg) { | |||
if(!_watcherThread.IsAlive) throw new Exception("Logger is Closed!"); | |||
//_logQueue.Add(new logMessage($"[ERROR @ {DateTime.Now:HH:mm:ss} | {ModName}] {msg}", WarningLevel.Error)); | |||
_logQueue.Add(new logMessage(msg, this, DateTime.Now, WarningLevel.Error)); | |||
} | |||
/// <summary> | |||
/// Sends an exception to the log. | |||
/// </summary> | |||
/// <param name="msg">the message to send</param> | |||
public void Exception(string msg) { | |||
if(!_watcherThread.IsAlive) throw new Exception("Logger is Closed!"); | |||
//_logQueue.Add(new logMessage($"[EXCEPTION @ {DateTime.Now:HH:mm:ss} | {ModName}] {msg}", WarningLevel.Exception)); | |||
_logQueue.Add(new logMessage(msg, this, DateTime.Now, WarningLevel.Exception)); | |||
} | |||
/// <summary> | |||
/// Sends a warning to the log. | |||
/// </summary> | |||
/// <param name="msg">the message to send</param> | |||
public void Warning(string msg) { | |||
if(!_watcherThread.IsAlive) throw new Exception("Logger is Closed!"); | |||
//_logQueue.Add(new logMessage($"[WARNING @ {DateTime.Now:HH:mm:ss} | {ModName}] {msg}", WarningLevel.Warning)); | |||
_logQueue.Add(new logMessage(msg, this, DateTime.Now, WarningLevel.Warning)); | |||
} | |||
static void QueueWatcher() { | |||
//StreamWriter wstream = null; | |||
Dictionary<string, StreamWriter> wstreams = new Dictionary<string, StreamWriter>(); | |||
while (_threadRunning && _logQueue.TryTake(out logMessage message, Timeout.Infinite)) | |||
{ | |||
string msg = string.Format(logMessage.logFormat, message.Message, message.Log.ModName, message.Time, message.WarningLevel); | |||
wstreams[message.Log.ModName] = message.Log._logFile.AppendText(); | |||
wstreams[message.Log.ModName].WriteLine(msg); | |||
Console.ForegroundColor = GetConsoleColour(message.WarningLevel); | |||
Console.WriteLine(message.Message); | |||
Console.ResetColor(); | |||
if (_logQueue.Count == 0) | |||
{ // no more messages | |||
foreach (var kvp in wstreams) | |||
{ | |||
if (kvp.Value == null) continue; | |||
kvp.Value.Dispose(); | |||
wstreams[kvp.Key] = null; | |||
} | |||
} | |||
} | |||
foreach (var kvp in wstreams) | |||
{ | |||
if (kvp.Value == null) continue; | |||
kvp.Value.Dispose(); | |||
} | |||
} | |||
/// <summary> | |||
/// Stops the logger background thread. | |||
/// </summary> | |||
public static void Stop() { | |||
_threadRunning = false; | |||
_watcherThread.Join(); | |||
} | |||
static ConsoleColor GetConsoleColour(WarningLevel level) { | |||
switch (level) { | |||
case WarningLevel.Log: | |||
return ConsoleColor.Green; | |||
case WarningLevel.Error: | |||
return ConsoleColor.Yellow; | |||
case WarningLevel.Exception: | |||
return ConsoleColor.Red; | |||
case WarningLevel.Warning: | |||
return ConsoleColor.Blue; | |||
default: | |||
return ConsoleColor.Gray; | |||
} | |||
} | |||
FileInfo GetPath(IBeatSaberPlugin plugin) => GetPath(plugin.Name); | |||
FileInfo GetPath(string modName) { | |||
ModName = modName; | |||
var logsDir = new DirectoryInfo($"./Logs/{modName}/{DateTime.Now:dd-MM-yy}"); | |||
logsDir.Create(); | |||
return new FileInfo($"{logsDir.FullName}/{logsDir.GetFiles().Length}.txt"); | |||
} | |||
} | |||
/// <summary> | |||
/// | |||
/// </summary> | |||
public static class LoggerExtensions { | |||
/// <summary> | |||
/// Gets a logger for the provided plugin. | |||
/// </summary> | |||
/// <param name="plugin">the plugin to get a logger for</param> | |||
/// <returns>a Logger instance</returns> | |||
public static Logger GetLogger(this IBeatSaberPlugin plugin) { | |||
return new Logger(plugin); | |||
} | |||
} | |||
} |
@ -0,0 +1,16 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace IllusionPlugin.Logging | |||
{ | |||
public abstract class LogPrinter | |||
{ | |||
public abstract Logger.LogLevel Filter { get; set; } | |||
public abstract void Print(Logger.Level level, DateTime time, string logName, string message); | |||
public virtual void StartPrint() { } | |||
public virtual void EndPrint() { } | |||
} | |||
} |
@ -0,0 +1,52 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
using System.Threading.Tasks; | |||
namespace IllusionPlugin.Logging | |||
{ | |||
public abstract class Logger | |||
{ | |||
public static string LogFormat { get; protected internal set; } = "[{3} @ {2:HH:mm:ss} | {1}] {0}"; | |||
public enum Level : byte | |||
{ | |||
None = 0, | |||
Debug = 1, | |||
Info = 2, | |||
Warning = 4, | |||
Error = 8, | |||
Critical = 16 | |||
} | |||
[Flags] | |||
public enum LogLevel : byte | |||
{ | |||
None = Level.None, | |||
DebugOnly = Level.Debug, | |||
InfoOnly = Level.Info, | |||
WarningOnly = Level.Warning, | |||
ErrorOnly = Level.Error, | |||
CriticalOnly = Level.Critical, | |||
ErrorUp = ErrorOnly | CriticalOnly, | |||
WarningUp = WarningOnly | ErrorUp, | |||
InfoUp = InfoOnly | WarningUp, | |||
All = DebugOnly | InfoUp, | |||
} | |||
public abstract void Log(Level level, string message); | |||
public void Log(Level level, Exception exeption) => Log(level, exeption.ToString()); | |||
public void Debug(string message) => Log(Level.Debug, message); | |||
public void Debug(Exception e) => Log(Level.Debug, e); | |||
public void Info(string message) => Log(Level.Info, message); | |||
public void Info(Exception e) => Log(Level.Info, e); | |||
public void Warn(string message) => Log(Level.Warning, message); | |||
public void Warn(Exception e) => Log(Level.Warning, e); | |||
public void Error(string message) => Log(Level.Error, message); | |||
public void Error(Exception e) => Log(Level.Error, e); | |||
public void Critical(string message) => Log(Level.Critical, message); | |||
public void Critical(Exception e) => Log(Level.Critical, e); | |||
} | |||
} |
@ -1 +1 @@ | |||
eb108721e2940659deee6bd068631e6d4749736e | |||
1bbd9ba53463d8e0c57caf8203d0145bfc70fa26 |