Last active
December 23, 2015 02:39
-
-
Save dbones/6568314 to your computer and use it in GitHub Desktop.
This shows a simple pattern for implementing Configurations and setting them.
The code shows a sample logger which is set-up via the code, you could easily extend it to configure by XML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Concurrent; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Net.Mime; | |
using System.Reflection; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace TestConfuring | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
Log log = new Log(new ConfigLog()); | |
ILogger logger = log.GetLogger("root"); | |
logger.Append("test1", LogLevel.Fatal); | |
logger.Append("test2", LogLevel.Fatal); | |
logger.Append("test3", LogLevel.Error); | |
logger.Append("test4", LogLevel.Fatal); | |
logger.Append("test5", LogLevel.Infomation); | |
logger.Append("test6", LogLevel.Debug); | |
logger.Append("test7", LogLevel.Trace); | |
logger.Append("test8", LogLevel.Warning); | |
logger.Append("test9", LogLevel.Fatal); | |
logger.Append("test10", LogLevel.Fatal); | |
} | |
} | |
//Main 3 classes | |
/// <summary> | |
/// Setup the Configuration | |
/// </summary> | |
public interface IConfigure | |
{ | |
bool CanHandle(object item); | |
void Configure(object item); | |
} | |
/// <summary> | |
/// Setup the Configuration | |
/// </summary> | |
/// <typeparam name="T">tie the config down to a Configuration class</typeparam> | |
public interface IConfigure<in T> : IConfigure where T : IRequireConfiguring | |
{ | |
void Configure(T item); | |
} | |
public abstract class ConfigureBase<T> : IConfigure<T> where T : IRequireConfiguring | |
{ | |
public abstract void Configure(T item); | |
public virtual bool CanHandle(object item) | |
{ | |
return item is T; | |
} | |
public void Configure(object item) | |
{ | |
Configure((T)item); | |
} | |
} | |
/// <summary> | |
/// A Configuration class (this interface is used to tag the config class) | |
/// </summary> | |
public interface IRequireConfiguring | |
{ | |
} | |
public class Log | |
{ | |
private readonly LoggingConfiguration _config; | |
private readonly Dictionary<string, IAppender> _appenders; | |
private readonly Dictionary<string, ILogger> _loggers; | |
public Log(IConfigure configLog) | |
{ | |
_appenders = new Dictionary<string, IAppender>(); | |
_loggers = new Dictionary<string, ILogger>(); | |
_config = new LoggingConfiguration(); | |
configLog.Configure(_config); | |
foreach (var appenderConfiguration in _config.Appenders) | |
{ | |
var createMe = appenderConfiguration.AppenderType; | |
var appender = (IAppender)Activator.CreateInstance(createMe); | |
appenderConfiguration.Configure(appender); | |
_appenders.Add(appender.Name, appender); | |
} | |
foreach (var loggerConfiguration in _config.Loggers) | |
{ | |
var logger = new Logger( | |
loggerConfiguration.Name, | |
loggerConfiguration.LogLevel, | |
loggerConfiguration.Appenders.Select(x=> _appenders[x])); | |
_loggers.Add(logger.Name, logger); | |
} | |
} | |
public ILogger GetLogger(string name) | |
{ | |
return _loggers[name]; | |
} | |
} | |
/// <summary> | |
/// An exmaple of the Configuration being setup via code, you could easily do this via XML | |
/// </summary> | |
public class ConfigLog : ConfigureBase<LoggingConfiguration> | |
{ | |
public override void Configure(LoggingConfiguration item) | |
{ | |
item.AddAppender<FileAppenderConfiguration>( | |
config => | |
{ | |
config.Batch = 10; | |
config.Name = "file"; | |
config.LogFolder = ""; //current folder | |
}); | |
item.AddAppender<ConsoleAppenderConfiguration>( | |
config => | |
{ | |
config.Name = "console"; | |
config.AppendColor(LogLevel.Fatal, ConsoleColor.Red, ConsoleColor.Black); | |
}); | |
item.AddLogger( | |
config => | |
{ | |
config.Name = "root"; | |
config.LogLevel = LogLevel.Fatal; | |
config.AddAppender("file"); | |
config.AddAppender("console"); | |
}); | |
} | |
} | |
/// <summary> | |
/// This is a Config class, it holds all the data required! (note it does not set itself up) | |
/// </summary> | |
public class LoggingConfiguration : IRequireConfiguring | |
{ | |
private readonly IDictionary<string, IAppenderConfiguration> _appenders; | |
private readonly List<LoggerConfiguration> _loggers; | |
public LoggingConfiguration() | |
{ | |
_appenders = new Dictionary<string, IAppenderConfiguration>(); | |
_loggers = new List<LoggerConfiguration>(); | |
} | |
public IEnumerable<IAppenderConfiguration> Appenders { get { return _appenders.Values; } } | |
public IEnumerable<LoggerConfiguration> Loggers { get { return _loggers; } } | |
public IAppenderConfiguration GetAppenderConfiguration(string name) | |
{ | |
return _appenders[name]; | |
} | |
public void AddAppender<T>(Action<T> config) where T : IAppenderConfiguration, new() | |
{ | |
var appenderConfig = new T(); | |
config(appenderConfig); | |
_appenders.Add(appenderConfig.Name, appenderConfig); | |
} | |
public void AddAppender<T>(Func<T> config) where T : IAppenderConfiguration | |
{ | |
var appenderConfig = config(); | |
_appenders.Add(appenderConfig.Name, appenderConfig); | |
} | |
public void AddLogger(Action<LoggerConfiguration> config) | |
{ | |
var logCongfig = new LoggerConfiguration(); | |
config(logCongfig); | |
_loggers.Add(logCongfig); | |
} | |
} | |
public interface IAppenderConfiguration | |
{ | |
string Name { get; set; } | |
Type AppenderType { get; } | |
void Configure(IAppender appender); | |
} | |
public interface IAppenderConfiguration<in T> : IAppenderConfiguration where T : IAppender | |
{ | |
void Configure(T appender); | |
} | |
public abstract class AppenderConfigBase<T> : IAppenderConfiguration<T> where T : IAppender | |
{ | |
public abstract void Configure(T appender); | |
public string Name { get; set; } | |
public Type AppenderType { get { return typeof (T); } } | |
public void Configure(IAppender appender) | |
{ | |
appender.Name = Name; | |
Configure((T)appender); | |
} | |
} | |
public class LoggerConfiguration | |
{ | |
private readonly HashSet<string> _appenders = new HashSet<string>(); | |
public string Name { get; set; } | |
public LogLevel LogLevel { get; set; } | |
public IEnumerable<string> Appenders { get { return _appenders; }} | |
public void AddAppender(string name) | |
{ | |
_appenders.Add(name); | |
} | |
} | |
[Flags] | |
public enum LogLevel | |
{ | |
Trace = 1, //000001 | |
Debug = 3, //000011 | |
Infomation = 7, //000111 | |
Warning = 15, //001111 | |
Error = 31, //011111 | |
Fatal = 63 //111111 | |
} | |
public interface ILogger | |
{ | |
void Append(string message, LogLevel logLevel); | |
} | |
public class Logger : ILogger | |
{ | |
private readonly List<IAppender> _appenders; | |
public Logger(string name, LogLevel logLevel, IEnumerable<IAppender> appenders) | |
{ | |
Name = name; | |
LogLevel = logLevel; | |
_appenders = new List<IAppender>(appenders); | |
} | |
public LogLevel LogLevel { get; private set; } | |
public string Name { get; private set; } | |
public void Append(string message, LogLevel logLevel) | |
{ | |
if (logLevel > LogLevel) | |
{ | |
return; | |
} | |
//Action<IAppender, string, LogLevel> log = (appender, msg, level) => appender.Append(msg, level); | |
//should be async and ignore execptions | |
foreach (var appender in _appenders) | |
{ | |
appender.Append(message, logLevel); | |
} | |
} | |
} | |
public interface IAppender | |
{ | |
void Append(string message, LogLevel logLevel); | |
string Name { get; set; } | |
} | |
public abstract class AppenderBase : IAppender | |
{ | |
public abstract void Append(string message, LogLevel logLevel); | |
public string Name { get; set; } | |
} | |
public class ConsoleAppender : AppenderBase | |
{ | |
public ConsoleAppenderConfiguration Configuration { get; set; } | |
public override void Append(string message, LogLevel logLevel) | |
{ | |
var consoleLogColor = Configuration.GetConsoleLogColor(logLevel); | |
WriteLine(message, consoleLogColor); | |
} | |
private void WriteLine(string message, ConsoleLogColor consoleLogColor) | |
{ | |
var foregroundColor = Console.ForegroundColor; | |
var backgroundColor = Console.BackgroundColor; | |
if (consoleLogColor != null) | |
{ | |
Console.ForegroundColor = consoleLogColor.Text; | |
Console.BackgroundColor = consoleLogColor.Background; | |
} | |
Console.WriteLine(message); | |
Console.ForegroundColor = foregroundColor; | |
Console.BackgroundColor = backgroundColor; | |
} | |
} | |
public class ConsoleAppenderConfiguration : AppenderConfigBase<ConsoleAppender> | |
{ | |
private readonly IDictionary<LogLevel, ConsoleLogColor> _consoleLogColors = new Dictionary<LogLevel, ConsoleLogColor>(); | |
public void AppendColor(LogLevel logLevel, ConsoleColor text, ConsoleColor background) | |
{ | |
ConsoleLogColor consoleLogColor; | |
if (_consoleLogColors.TryGetValue(logLevel, out consoleLogColor)) | |
{ | |
consoleLogColor.Background = background; | |
consoleLogColor.Text = text; | |
} | |
else | |
{ | |
consoleLogColor = new ConsoleLogColor {LogLevel = logLevel, Background = background, Text = text}; | |
_consoleLogColors.Add(consoleLogColor.LogLevel, consoleLogColor); | |
} | |
} | |
public IEnumerable<ConsoleLogColor> ConsoleLogColors {get { return _consoleLogColors.Values; }} | |
public ConsoleLogColor GetConsoleLogColor(LogLevel logLevel) | |
{ | |
ConsoleLogColor consoleLogColor = null; | |
_consoleLogColors.TryGetValue(logLevel, out consoleLogColor); | |
return consoleLogColor; | |
} | |
public override void Configure(ConsoleAppender appender) | |
{ | |
appender.Configuration = this; | |
} | |
} | |
public class ConsoleLogColor | |
{ | |
public LogLevel LogLevel { get; set; } | |
public ConsoleColor Text { get; set; } | |
public ConsoleColor Background { get; set; } | |
} | |
public class FileAppender : AppenderBase | |
{ | |
Queue<FileEntry> _toAddToLogItems = new Queue<FileEntry>(); | |
public FileAppenderConfiguration Configuration { get; set; } | |
public override void Append(string message, LogLevel logLevel) | |
{ | |
_toAddToLogItems.Enqueue(new FileEntry(){Message = message, LogLevel = logLevel}); | |
if (_toAddToLogItems.Count != Configuration.Batch) | |
{ | |
return; | |
} | |
var path = string.IsNullOrWhiteSpace(Configuration.LogFolder) | |
? Directory.GetCurrentDirectory() | |
: Configuration.LogFolder; | |
var file = Path.Combine(path, "log.txt"); | |
FileStream stream = File.Exists(file) | |
? File.Open(file, FileMode.Append, FileAccess.Write) | |
: File.Create(file); | |
using (var writer = new StreamWriter(stream)) | |
{ | |
while (_toAddToLogItems.Count > 0) | |
{ | |
var item = _toAddToLogItems.Dequeue(); | |
writer.WriteLine(item.Message); | |
} | |
} | |
} | |
} | |
public class FileEntry | |
{ | |
public string Message { get; set; } | |
public LogLevel LogLevel { get; set; } | |
} | |
public class FileAppenderConfiguration : AppenderConfigBase<FileAppender> | |
{ | |
public string LogFolder { get; set; } | |
public int Batch { get; set; } | |
public override void Configure(FileAppender appender) | |
{ | |
appender.Configuration = this; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment