Skip to content

Instantly share code, notes, and snippets.

@jirkapenzes
Created November 4, 2012 22:47
Show Gist options
  • Save jirkapenzes/4014154 to your computer and use it in GitHub Desktop.
Save jirkapenzes/4014154 to your computer and use it in GitHub Desktop.
Simple logger in one file
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Reflection;
using System.Text;
using SimpleLogger.Logging;
using SimpleLogger.Logging.Formatters;
using SimpleLogger.Logging.Handlers;
using SimpleLogger.Logging.Module;
namespace SimpleLogger
{
public static class Logger
{
private static readonly LogPublisher LogPublisher;
private static readonly ModuleManager ModuleManager;
private static readonly DebugLogger DebugLogger;
private static readonly CustomLevelManager LevelManager;
private static readonly object Sync = new object();
private static Level _defaultLevel = Level.Info;
private static bool _isTurned = true;
private static bool _isTurnedDebug = true;
public enum Level
{
None,
Info,
Warning,
Error,
Severe,
Fine,
Debug
}
static Logger()
{
lock (Sync)
{
LogPublisher = new LogPublisher();
ModuleManager = new ModuleManager();
DebugLogger = new DebugLogger();
LevelManager = new CustomLevelManager();
}
}
public static void DefaultInitialization()
{
LoggerHandlerManager
.AddHandler(new ConsoleLoggerHandler())
.AddHandler(new FileLoggerHandler());
Log(Level.Info, "Default initialization");
}
public static Level DefaultLevel
{
get { return _defaultLevel; }
set { _defaultLevel = value; }
}
public static ILoggerHandlerManager LoggerHandlerManager
{
get { return LogPublisher; }
}
public static void Log()
{
Log("There is no message");
}
public static void Log(string message)
{
Log(_defaultLevel, message);
}
public static void Log(Level level, string message)
{
var stackFrame = FindStackFrame();
var methodBase = GetCallingMethodBase(stackFrame);
var callingMethod = methodBase.Name;
var callingClass = methodBase.ReflectedType.Name;
var lineNumber = stackFrame.GetFileLineNumber();
Log(level, message, callingClass, callingMethod, lineNumber);
}
public static void Log(Exception exception)
{
Log(Level.Error, exception.Message);
ModuleManager.ExceptionLog(exception);
}
public static void Log<TClass>(Exception exception) where TClass : class
{
var message = string.Format("Log exception -> Message: {0}\nStackTrace: {1}", exception.Message,
exception.StackTrace);
Log<TClass>(Level.Error, message);
}
public static void Log<TClass>(string message) where TClass : class
{
Log<TClass>(_defaultLevel, message);
}
public static void Log<TClass>(Level level, string message) where TClass : class
{
var stackFrame = FindStackFrame();
var methodBase = GetCallingMethodBase(stackFrame);
var callingMethod = methodBase.Name;
var callingClass = typeof(TClass).Name;
var lineNumber = stackFrame.GetFileLineNumber();
Log(level, message, callingClass, callingMethod, lineNumber);
}
private static void Log(Level level, string message, string callingClass, string callingMethod, int lineNumber)
{
if (!_isTurned || (!_isTurnedDebug && level == Level.Debug))
return;
var currentDateTime = DateTime.Now;
ModuleManager.BeforeLog();
var logMessage = new LogMessage(level.ToString(), message, currentDateTime, callingClass, callingMethod, lineNumber);
LogPublisher.Publish(logMessage);
ModuleManager.AfterLog(logMessage);
}
private static MethodBase GetCallingMethodBase(StackFrame stackFrame)
{
return stackFrame == null
? MethodBase.GetCurrentMethod() : stackFrame.GetMethod();
}
private static StackFrame FindStackFrame()
{
var stackTrace = new StackTrace();
for (var i = 0; i < stackTrace.GetFrames().Count(); i++)
{
var methodBase = stackTrace.GetFrame(i).GetMethod();
var name = MethodBase.GetCurrentMethod().Name;
if (!methodBase.Name.Equals("Log") && !methodBase.Name.Equals(name))
return new StackFrame(i, true);
}
return null;
}
public static void AddCustomLevel(string level)
{
LevelManager.AddLevel(level);
}
public static void On()
{
_isTurned = true;
}
public static void Off()
{
_isTurned = false;
}
public static void DebugOn()
{
_isTurnedDebug = true;
}
public static void DebugOff()
{
_isTurnedDebug = false;
}
public static IList<LoggerModule> Modules
{
get { return ModuleManager.Modules; }
}
public static IEnumerable<LogMessage> Messages
{
get { return LogPublisher.Messages; }
}
public static DebugLogger Debug
{
get { return DebugLogger; }
}
}
}
namespace SimpleLogger.Logging
{
internal class LogPublisher : ILoggerHandlerManager
{
private readonly IList<ILoggerHandler> _loggerHandlers;
private readonly IList<LogMessage> _messages;
public LogPublisher()
{
_loggerHandlers = new List<ILoggerHandler>();
_messages = new List<LogMessage>();
}
public void Publish(LogMessage logMessage)
{
_messages.Add(logMessage);
foreach (var loggerHandler in _loggerHandlers)
loggerHandler.Publish(logMessage);
}
public ILoggerHandlerManager AddHandler(ILoggerHandler loggerHandler)
{
if (loggerHandler != null)
_loggerHandlers.Add(loggerHandler);
return this;
}
public bool RemoveHandler(ILoggerHandler loggerHandler)
{
return _loggerHandlers.Remove(loggerHandler);
}
public IEnumerable<LogMessage> Messages
{
get { return _messages; }
}
}
}
namespace SimpleLogger.Logging
{
public class LogMessage
{
public DateTime DateTime { get; set; }
public string Level { get; set; }
public string Text { get; set; }
public string CallingClass { get; set; }
public string CallingMethod { get; set; }
public int LineNumber { get; set; }
public LogMessage() { }
public LogMessage(string level, string text, DateTime dateTime, string callingClass, string callingMethod, int lineNumber)
{
Level = level;
Text = text;
DateTime = dateTime;
CallingClass = callingClass;
CallingMethod = callingMethod;
LineNumber = lineNumber;
}
public override string ToString()
{
return new DefaultLoggerFormatter().ApplyFormat(this);
}
}
}
namespace SimpleLogger.Logging
{
public interface ILoggerHandlerManager
{
ILoggerHandlerManager AddHandler(ILoggerHandler loggerHandler);
bool RemoveHandler(ILoggerHandler loggerHandler);
}
}
namespace SimpleLogger.Logging
{
public interface ILoggerHandler
{
void Publish(LogMessage logMessage);
}
}
namespace SimpleLogger.Logging
{
public class DebugLogger
{
private const Logger.Level DebugLevel = Logger.Level.Debug;
public void Log()
{
Log("There is no message");
}
public void Log(string message)
{
Logger.Log(DebugLevel, message);
}
public void Log(Exception exception)
{
Logger.Log(DebugLevel, exception.Message);
}
public void Log<TClass>(Exception exception) where TClass : class
{
var message = string.Format("Log exception -> Message: {0}\nStackTrace: {1}", exception.Message, exception.StackTrace);
Logger.Log<TClass>(DebugLevel, message);
}
public void Log<TClass>(string message) where TClass : class
{
Logger.Log<TClass>(DebugLevel, message);
}
}
}
namespace SimpleLogger.Logging
{
class CustomLevelManager
{
private readonly HashSet<string> _levels;
public CustomLevelManager()
{
_levels = new HashSet<string>();
}
public void AddLevel(string level)
{
if (_levels.Contains(level))
throw new ArithmeticException("Level is already defined. ");
_levels.Add(level);
}
public bool IsDefinedLevel(string level)
{
return _levels.Contains(level);
}
}
}
namespace SimpleLogger.Logging.Module
{
public class ModuleManager
{
private readonly IList<LoggerModule> _modules;
public ModuleManager()
{
_modules = new List<LoggerModule>();
}
public void BeforeLog()
{
foreach (var loggerModule in _modules)
loggerModule.BeforeLog();
}
public void AfterLog(LogMessage logMessage)
{
foreach (var loggerModule in _modules)
loggerModule.AfterLog(logMessage);
}
public void ExceptionLog(Exception exception)
{
foreach (var loggerModule in _modules)
loggerModule.ExceptionLog(exception);
}
public IList<LoggerModule> Modules
{
get { return _modules; }
}
}
}
namespace SimpleLogger.Logging.Module
{
public abstract class LoggerModule
{
public virtual void BeforeLog() { }
public virtual void AfterLog(LogMessage logMessage) { }
public virtual void ExceptionLog(Exception exception) { }
}
}
namespace SimpleLogger.Logging.Module
{
public class EmailSenderLoggerModule : LoggerModule
{
private readonly SmtpServerConfiguration _smtpServerConfiguration;
public string Sender { get; set; }
public IList<string> Recipients { get; private set; }
public bool EnableSsl { get; set; }
private readonly string _subject;
private readonly ILoggerFormatter _loggerFormatter;
public EmailSenderLoggerModule(SmtpServerConfiguration smtpServerConfiguration)
: this(smtpServerConfiguration, GenerateSubjectName()) { }
public EmailSenderLoggerModule(SmtpServerConfiguration smtpServerConfiguration, string subject)
: this(smtpServerConfiguration, subject, new DefaultLoggerFormatter()) { }
public EmailSenderLoggerModule(SmtpServerConfiguration smtpServerConfiguration, ILoggerFormatter loggerFormatter)
: this(smtpServerConfiguration, GenerateSubjectName(), loggerFormatter) { }
public EmailSenderLoggerModule(SmtpServerConfiguration smtpServerConfiguration, string subject, ILoggerFormatter loggerFormatter)
{
_smtpServerConfiguration = smtpServerConfiguration;
_subject = subject;
_loggerFormatter = loggerFormatter;
Recipients = new List<string>();
}
public override void ExceptionLog(Exception exception)
{
if (string.IsNullOrEmpty(Sender) || Recipients.Count == 0)
throw new NullReferenceException("Not specified email sender and recipient. ");
var body = MakeEmailBodyFromLogHistory();
var client = new SmtpClient(_smtpServerConfiguration.Host, _smtpServerConfiguration.Port)
{
EnableSsl = EnableSsl,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(_smtpServerConfiguration.UserName, _smtpServerConfiguration.Password)
};
foreach (var recipient in Recipients)
{
using (var mailMessage = new MailMessage(Sender, recipient, _subject, body))
{
client.Send(mailMessage);
}
}
}
private static string GenerateSubjectName()
{
var currentDate = DateTime.Now;
return string.Format("SimpleLogger {0} {1}", currentDate.ToShortDateString(), currentDate.ToShortTimeString());
}
private string MakeEmailBodyFromLogHistory()
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Simple logger - email module");
foreach (var logMessage in Logger.Messages)
stringBuilder.AppendLine(_loggerFormatter.ApplyFormat(logMessage));
return stringBuilder.ToString();
}
}
public class SmtpServerConfiguration
{
public string UserName { get; private set; }
public string Password { get; private set; }
public string Host { get; private set; }
public int Port { get; private set; }
public SmtpServerConfiguration(string userName, string password, string host, int port)
{
UserName = userName;
Password = password;
Host = host;
Port = port;
}
}
}
namespace SimpleLogger.Logging.Handlers
{
public class FileLoggerHandler : ILoggerHandler
{
private readonly string _fileName;
private readonly string _directory;
private readonly ILoggerFormatter _loggerFormatter;
public FileLoggerHandler() : this(CreateFileName()) { }
public FileLoggerHandler(string fileName) : this(fileName, string.Empty) { }
public FileLoggerHandler(string fileName, string directory) : this(new DefaultLoggerFormatter(), fileName, directory) { }
public FileLoggerHandler(ILoggerFormatter loggerFormatter) : this(loggerFormatter, CreateFileName()) { }
public FileLoggerHandler(ILoggerFormatter loggerFormatter, string fileName) : this(loggerFormatter, fileName, string.Empty) { }
public FileLoggerHandler(ILoggerFormatter loggerFormatter, string fileName, string directory)
{
_loggerFormatter = loggerFormatter;
_fileName = fileName;
_directory = directory;
}
public void Publish(LogMessage logMessage)
{
if (!string.IsNullOrEmpty(_directory))
{
var directoryInfo = new DirectoryInfo(_directory);
if (!directoryInfo.Exists)
directoryInfo.Create();
}
using (var writer = new StreamWriter(File.Open(Path.Combine(_directory, _fileName), FileMode.Append)))
writer.WriteLine(_loggerFormatter.ApplyFormat(logMessage));
}
private static string CreateFileName()
{
var currentDate = DateTime.Now;
var guid = Guid.NewGuid();
return string.Format("Log_{0:0000}{1:00}{2:00}-{3:00}{4:00}_{5}.log",
currentDate.Year, currentDate.Month, currentDate.Day, currentDate.Hour, currentDate.Minute, guid);
}
}
}
namespace SimpleLogger.Logging.Handlers
{
public class DebugConsoleLoggerHandler : ILoggerHandler
{
private readonly ILoggerFormatter _loggerFormatter;
public DebugConsoleLoggerHandler() : this(new DefaultLoggerFormatter()) { }
public DebugConsoleLoggerHandler(ILoggerFormatter loggerFormatter)
{
_loggerFormatter = loggerFormatter;
}
public void Publish(LogMessage logMessage)
{
System.Diagnostics.Debug.WriteLine(_loggerFormatter.ApplyFormat(logMessage));
}
}
}
namespace SimpleLogger.Logging.Handlers
{
public class ConsoleLoggerHandler : ILoggerHandler
{
private readonly ILoggerFormatter _loggerFormatter;
public ConsoleLoggerHandler() : this(new DefaultLoggerFormatter()) { }
public ConsoleLoggerHandler(ILoggerFormatter loggerFormatter)
{
_loggerFormatter = loggerFormatter;
}
public void Publish(LogMessage logMessage)
{
Console.WriteLine(_loggerFormatter.ApplyFormat(logMessage));
}
}
}
namespace SimpleLogger.Logging.Formatters
{
public interface ILoggerFormatter
{
string ApplyFormat(LogMessage logMessage);
}
}
namespace SimpleLogger.Logging.Formatters
{
internal class DefaultLoggerFormatter : ILoggerFormatter
{
public string ApplyFormat(LogMessage logMessage)
{
return string.Format("{0:dd.MM.yyyy HH:mm}: {1} [line: {2} {3} -> {4}()]: {5}",
logMessage.DateTime, logMessage.Level, logMessage.LineNumber, logMessage.CallingClass,
logMessage.CallingMethod, logMessage.Text);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment