392 lines
18 KiB
C#
392 lines
18 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Logging Detail
|
|
/// </summary>
|
|
public enum Logging_Detail
|
|
{
|
|
NONE,
|
|
ERROR,
|
|
INFO,
|
|
DEBUG
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used to Configure a Logger Instance in the Logging Class via AddGlobalLoggerConfiguration()
|
|
/// <example>
|
|
/// <code>
|
|
/// 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;
|
|
/// </code>
|
|
/// </example>
|
|
/// </summary>
|
|
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;
|
|
}
|
|
|
|
/// <remarks>
|
|
/// 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
|
|
/// </remarks>
|
|
public class Logging
|
|
{
|
|
#region Private Static Members
|
|
|
|
private static Dictionary<string, Logging_Configuration> _loggerConfigurationMap = new Dictionary<string, Logging_Configuration>();
|
|
private static Dictionary<string, ILog> _loggerObjects = new Dictionary<string, ILog>();
|
|
|
|
// If this process is hosted in VS then it changes the stack frame
|
|
private static bool s_IsVSHosted = false;
|
|
|
|
#endregion
|
|
|
|
#region Private Construction
|
|
|
|
/// <summary>
|
|
/// Private Constructor should only be called by static GetLogger() Function
|
|
/// </summary>
|
|
/// <param name="bLogCallingTypeAndCallingFunction">if true, will log calling type and Calling Function</param>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Log Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Info(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader() + String.Format(message, args)); } }
|
|
|
|
/// <summary>
|
|
/// Log Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Info(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader(nPlusMinus) + String.Format(message, args)); } }
|
|
|
|
/// <summary>
|
|
/// Log Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="exception">Exception to Log</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Info(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader() + String.Format(message, args), exception); } }
|
|
|
|
/// <summary>
|
|
/// Log Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="exception">Exception to Log</param>
|
|
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Info(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } }
|
|
|
|
/// <summary>
|
|
/// Log Debug Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Debug(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader() + String.Format(message, args)); } }
|
|
|
|
/// <summary>
|
|
/// Log Debug Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Debug(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader(nPlusMinus) + String.Format(message, args)); } }
|
|
|
|
/// <summary>
|
|
/// Log Debug Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="exception">Exception to Log</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Debug(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader() + String.Format(message, args), exception); } }
|
|
|
|
/// <summary>
|
|
/// Log Debug Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="exception">Exception to Log</param>
|
|
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Debug(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } }
|
|
|
|
/// <summary>
|
|
/// Log Error Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Error(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader() + String.Format(message, args)); } }
|
|
|
|
/// <summary>
|
|
/// Log Error Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Error(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader(nPlusMinus) + String.Format(message, args)); } }
|
|
|
|
/// <summary>
|
|
/// Log Error Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="exception">Exception to Log</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Error(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader() + String.Format(message, args), exception); } }
|
|
|
|
/// <summary>
|
|
/// Log Error Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="exception">Exception to Log</param>
|
|
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Error(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } }
|
|
|
|
/// <summary>
|
|
/// Log Fatal Error Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Fatal(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader() + String.Format(message, args)); } }
|
|
|
|
/// <summary>
|
|
/// Log Fatal Error Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Fatal(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader(nPlusMinus) + String.Format(message, args)); } }
|
|
|
|
/// <summary>
|
|
/// Log Fatal Error Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="exception">Exception to Log</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Fatal(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader() + String.Format(message, args), exception); } }
|
|
|
|
/// <summary>
|
|
/// Log Fatal Error Information
|
|
/// </summary>
|
|
/// <param name="message">Message to write</param>
|
|
/// <param name="exception">Exception to Log</param>
|
|
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
|
|
/// <param name="args">arguments to pass to String.Format</param>
|
|
public void Fatal(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } }
|
|
|
|
/// <returns>
|
|
/// Message Header to be shown on every log message
|
|
/// </returns>
|
|
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Used to add a new Configuration and Logger Instance onto a Static Map.
|
|
/// Will create one logger instance per unique name.
|
|
/// </summary>
|
|
/// <param name="Name">a name for the logger instance</param>
|
|
/// <param name="Configuration">a valid configuration to use on the instance</param>
|
|
/// <returns>a logging object that can be used to log</returns>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used to retrieve a named logging instance that has already been created via a previous call
|
|
/// to AddGlobalLoggerConfiguration().
|
|
/// </summary>
|
|
/// <param name="Name">a name for a previously created Logging instance</param>
|
|
/// <returns>a Logging object that can be used to log</returns>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Creates a Log4Net RollingFileAppender with the specified configuration
|
|
/// </summary>
|
|
/// <param name="config">a valid configuration</param>
|
|
/// <returns>a Log4Net RollingFileAppender Object</returns>
|
|
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
|
|
}
|
|
}
|