using System; using System.Collections.Generic; using System.Globalization; using System.IO; namespace Cryville.Common { /// /// A logger. /// public abstract class Logger { static readonly Dictionary Instances = new Dictionary(); static readonly Dictionary Files = new Dictionary(); static string logPath = null; /// /// Sets the path where the log files shall be stored. /// /// The path. public static void SetLogPath(string path) { logPath = path; var dir = new DirectoryInfo(path); if (!dir.Exists) dir.Create(); } /// /// Logs to the specified logger. /// /// The key of the logger. /// The severity level. /// The module that is logging. /// The format string. /// The arguments for formatting. public static void Log(string key, int level, string module, string format, params object[] args) { if (!Instances.ContainsKey(key)) return; Instances[key].Log(level, module, string.Format(format, args)); if (Files.ContainsKey(key)) Files[key].WriteLine("[{0:O}] [{1}] <{2}> {3}", DateTime.UtcNow, level, module, string.Format(format, args)); } /// /// Adds a created logger to the shared logger manager. /// /// The key of the logger. /// The logger. public static void Create(string key, Logger logger) { Instances[key] = logger; if (logPath != null) { Files[key] = new StreamWriter(logPath + "/" + ((int)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds).ToString(CultureInfo.InvariantCulture) + "-" + key + ".log") { AutoFlush = true }; } } /// /// Closes all loggers and related file streams. /// public static void Close() { Instances.Clear(); foreach (var f in Files) f.Value.Dispose(); Files.Clear(); } /// /// Logs to the logger. /// /// The severity level. /// The module that is logging. /// The message. public virtual void Log(int level, string module, string msg) { } } /// /// A that calls a callback function on log. /// public class InstantLogger : Logger { readonly Action callback; /// /// Creates an instance of the class. /// /// The callback function. /// is . public InstantLogger(Action callback) { if (callback == null) throw new ArgumentNullException("callback"); this.callback = callback; } /// public override void Log(int level, string module, string msg) { base.Log(level, module, msg); callback(level, module, msg); } } /// /// A that buffers the logs for enumeration. /// public class BufferedLogger : Logger { readonly List buffer = new List(); /// /// Creates an instance of the class. /// public BufferedLogger() { } /// public override void Log(int level, string module, string msg) { base.Log(level, module, msg); lock (buffer) { buffer.Add(new LogEntry(level, module, msg)); } } /// /// Enumerates the buffered logs. /// /// The callback function to receive the logs. public void Enumerate(Action callback) { lock (buffer) { foreach (var i in buffer) { callback(i.level, i.module, i.msg); } } buffer.Clear(); } } struct LogEntry { public int level; public string module; public string msg; public LogEntry(int level, string module, string msg) { this.level = level; this.module = module; this.msg = msg; } } }