using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using Diag = System.Diagnostics; // Log4Net Declarations using log4net.Appender; using log4net.Core; using log4net.Layout; using log4net.Config; using log4net; using Yaulw.Other; namespace Yaulw.File { /// /// Logging Detail /// public enum Logging_Detail { NONE, ERROR, INFO, DEBUG } /// /// Used to Configure a Logger Instance in the Logging Class via AddGlobalLoggerConfiguration() /// /// /// Logging_Configuration config; /// config.LogFileNameNPath = "c:\\LogFile.log"; /// config.Detail = Logging_Detail.Error; /// config.UseExclusiveFileLock = false; /// config.maxFileSizeInMB = 4; /// config.numOfBackupLogFiles = 3; /// config.Log4NetDetailPatternLayout = "%date{dd MMM HH:mm:ss,fff} [%thread] %level - %message%newline"; (Default) /// "%date{dd MMM yyyy HH:mm:ss,fff} [%thread] %level %logger - %message%newline"; /// config.LogCallingTypeAndCallingFunction = true; /// /// /// public struct Logging_Configuration { public string LogFileNameNPath; public Logging_Detail Detail; public bool UseExclusiveFileLock; public int maxFileSizeInMB; public int numOfBackupLogFiles; public string Log4NetDetailPatternLayout; public bool LogCallingType; public bool LogCallingFunction; } /// /// Is a Wrapper Object around Log4Net's Rolling File Appender. /// Use it by calling AddGlobalLoggerConfiguration() with a valid Logging Configuration. /// You can configure multipe Logger Instances distinguished by Name. /// subsequent calls can call GetLogger() with the named Logger instance to receive a valid logger object /// public class Logging { #region Private Static Members private static Dictionary _loggerConfigurationMap = new Dictionary(); private static Dictionary _loggerObjects = new Dictionary(); // If this process is hosted in VS then it changes the stack frame private static bool s_IsVSHosted = false; #endregion #region Private Construction /// /// Private Constructor should only be called by static GetLogger() Function /// /// if true, will log calling type and Calling Function private Logging(bool bLogCallingType, bool bLogCallingFunction) { s_IsVSHosted = Diag.Process.GetCurrentProcess().ProcessName.Contains("vshost"); _LogCallingType = bLogCallingType; _LogCallingFunction = bLogCallingFunction; } #endregion #region Internal Members // Initialized by GetLogger() internal ILog _Log4NetLog = null; // Initialized by GetLogger() internal bool _LogCallingType = false; // Initialized by GetLogger() internal bool _LogCallingFunction = false; #endregion #region Public Log Methods /// /// Log Information /// /// Message to write /// arguments to pass to String.Format public void Info(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader() + String.Format(message, args)); } } /// /// Log Information /// /// Message to write /// Use this to add/substract from the base stack level you want to retrieve /// arguments to pass to String.Format public void Info(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader(nPlusMinus) + String.Format(message, args)); } } /// /// Log Information /// /// Message to write /// Exception to Log /// arguments to pass to String.Format public void Info(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader() + String.Format(message, args), exception); } } /// /// Log Information /// /// Message to write /// Exception to Log /// Use this to add/substract from the base stack level you want to retrieve /// arguments to pass to String.Format public void Info(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } } /// /// Log Debug Information /// /// Message to write /// arguments to pass to String.Format public void Debug(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader() + String.Format(message, args)); } } /// /// Log Debug Information /// /// Message to write /// Use this to add/substract from the base stack level you want to retrieve /// arguments to pass to String.Format public void Debug(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader(nPlusMinus) + String.Format(message, args)); } } /// /// Log Debug Information /// /// Message to write /// Exception to Log /// arguments to pass to String.Format public void Debug(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader() + String.Format(message, args), exception); } } /// /// Log Debug Information /// /// Message to write /// Exception to Log /// Use this to add/substract from the base stack level you want to retrieve /// arguments to pass to String.Format public void Debug(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } } /// /// Log Error Information /// /// Message to write /// arguments to pass to String.Format public void Error(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader() + String.Format(message, args)); } } /// /// Log Error Information /// /// Message to write /// Use this to add/substract from the base stack level you want to retrieve /// arguments to pass to String.Format public void Error(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader(nPlusMinus) + String.Format(message, args)); } } /// /// Log Error Information /// /// Message to write /// Exception to Log /// arguments to pass to String.Format public void Error(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader() + String.Format(message, args), exception); } } /// /// Log Error Information /// /// Message to write /// Exception to Log /// Use this to add/substract from the base stack level you want to retrieve /// arguments to pass to String.Format public void Error(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } } /// /// Log Fatal Error Information /// /// Message to write /// arguments to pass to String.Format public void Fatal(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader() + String.Format(message, args)); } } /// /// Log Fatal Error Information /// /// Message to write /// Use this to add/substract from the base stack level you want to retrieve /// arguments to pass to String.Format public void Fatal(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader(nPlusMinus) + String.Format(message, args)); } } /// /// Log Fatal Error Information /// /// Message to write /// Exception to Log /// arguments to pass to String.Format public void Fatal(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader() + String.Format(message, args), exception); } } /// /// Log Fatal Error Information /// /// Message to write /// Exception to Log /// Use this to add/substract from the base stack level you want to retrieve /// arguments to pass to String.Format public void Fatal(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } } /// /// Message Header to be shown on every log message /// /// Use this to add/substract from the base stack level you want to retrieve private string MessageHeader(int nPlusMinus = 0) { // When Running this from via VS it behaves differently then when // running it outside of it, when running it regularly, each foreach loop if (s_IsVSHosted) { if (_LogCallingType && _LogCallingFunction) return StackWalker.GetTypeFromStack(nPlusMinus + 1) + " - " + StackWalker.GetMethodNameFromStack(nPlusMinus + 1) + "()- "; else if (_LogCallingFunction) return StackWalker.GetMethodNameFromStack(nPlusMinus + 1) + "()- "; else return ""; } else { if (_LogCallingType && _LogCallingFunction) return StackWalker.GetTypeFromStack(nPlusMinus) + " - " + StackWalker.GetMethodNameFromStack(nPlusMinus) + "()- "; else if (_LogCallingFunction) return StackWalker.GetMethodNameFromStack(nPlusMinus) + "()- "; else return ""; } } #endregion #region Public Static Configuration and Logger Creation Methods /// /// Used to add a new Configuration and Logger Instance onto a Static Map. /// Will create one logger instance per unique name. /// /// a name for the logger instance /// a valid configuration to use on the instance /// a logging object that can be used to log public static Logging AddGlobalLoggerConfiguration(string Name, Logging_Configuration Configuration) { // Must have a Valid Input if (string.IsNullOrEmpty(Name)) throw new ArgumentException("Name Is Invalid"); if (!_loggerObjects.Keys.Contains(Name.ToLower())) { // Create the Repository log4net.Repository.ILoggerRepository repository = LogManager.CreateRepository(Name.ToLower()); // Create FileAppender Configuration RollingFileAppender appender = RollingFileAppenderCreator(Configuration); // Run the Configuration against the Repository BasicConfigurator.Configure(repository, appender); // Add Configuration to our Static Map _loggerConfigurationMap[Name.ToLower()] = Configuration; // Last, but not least, Create the new Logging Instance Object and Store it _loggerObjects[Name.ToLower()] = LogManager.GetLogger(Name.ToLower(), Name.ToLower()); } // Let the Caller get the Logging Object return GetLogger(Name); } /// /// Used to retrieve a named logging instance that has already been created via a previous call /// to AddGlobalLoggerConfiguration(). /// /// a name for a previously created Logging instance /// a Logging object that can be used to log public static Logging GetLogger(string Name) { if (_loggerObjects.Keys.Contains(Name.ToLower()) && _loggerConfigurationMap.Keys.Contains(Name.ToLower())) { bool bLogCallingType = _loggerConfigurationMap[Name.ToLower()].LogCallingType; bool bLogCallingFunction = _loggerConfigurationMap[Name.ToLower()].LogCallingFunction; Logging logger = new Logging(bLogCallingType, bLogCallingFunction); logger._Log4NetLog = _loggerObjects[Name.ToLower()]; return logger; } else throw new ArgumentException("Must call AddGlobalLoggerConfiguration() with a Configuration Before calling this Function"); } #endregion #region Private Static Helper Methods /// /// Creates a Log4Net RollingFileAppender with the specified configuration /// /// a valid configuration /// a Log4Net RollingFileAppender Object private static RollingFileAppender RollingFileAppenderCreator(Logging_Configuration config) { #region Input Validation if (config.maxFileSizeInMB <= 0) throw new ArgumentException("Logging_Configuration - Invalid maxFileSizeInMB"); if (config.numOfBackupLogFiles < 0) throw new ArgumentException("Logging_Configuration - Invalid numOfBackupLogFiles"); if (String.IsNullOrEmpty(config.LogFileNameNPath)) throw new Exception("Logging_Configuration - Invalid LogFileNameNPath"); if (!Directory.Exists(Path.GetDirectoryName(config.LogFileNameNPath))) Directory.CreateDirectory(Path.GetDirectoryName(config.LogFileNameNPath)); #endregion // Create and Set Layout for FileAppender RollingFileAppender rfAppender = new RollingFileAppender(); // Set Layout if (!String.IsNullOrEmpty(config.Log4NetDetailPatternLayout)) rfAppender.Layout = new PatternLayout(config.Log4NetDetailPatternLayout); else rfAppender.Layout = new PatternLayout("%date{dd MMM HH:mm:ss,fff} [%thread] %level - %message%newline"); // Locking Minimal allows us to run Log4Net from multiple processes if (config.UseExclusiveFileLock) rfAppender.LockingModel = new FileAppender.ExclusiveLock(); else rfAppender.LockingModel = new FileAppender.MinimalLock(); // Configure FileName and always set Appent to true rfAppender.File = config.LogFileNameNPath; rfAppender.AppendToFile = true; // According to the listings on the blog site // http://blog.aggregatedintelligence.com/2009/08/log4net-logging-levels-available.html // Error, will log Error, Fatal // Info, will log Info, Error, and Fatal // Debug, will log Info, Error, Fatal and Debug if (config.Detail == Logging_Detail.NONE) rfAppender.Threshold = Level.Off; else if (config.Detail == Logging_Detail.ERROR) rfAppender.Threshold = Level.Error; else if (config.Detail == Logging_Detail.INFO) rfAppender.Threshold = Level.Info; else if (config.Detail == Logging_Detail.DEBUG) rfAppender.Threshold = Level.Debug; rfAppender.MaximumFileSize = String.Format("{0}MB", config.maxFileSizeInMB); rfAppender.MaxSizeRollBackups = config.numOfBackupLogFiles; // Setting to RollingMode.Size will make MaxSizeRollBackups work rfAppender.RollingStyle = RollingFileAppender.RollingMode.Size; rfAppender.ActivateOptions(); return rfAppender; } #endregion } }