Skip to content

Instantly share code, notes, and snippets.

@dbones
Last active December 23, 2015 02:39
Show Gist options
  • Save dbones/6568314 to your computer and use it in GitHub Desktop.
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
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