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;
}
}
}