using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; namespace Wayne.Lib.Log { /// <summary> /// Class used to make debug logs. /// </summary> /// <example> /// This is an example of how to write a debug log entry. /// <code> /// using (DebugLogger dLog = new DebugLogger(this)) /// { /// if (dLog.IsActive(DebugLogLevel.Detailed)) /// { /// dLog.Add("This is line 1.", DebugLogLevel.Detailed); /// dLog.Add("This is line 2.", "MyCategory", DebugLogLevel.Detailed); /// } /// } /// </code> /// </example> public sealed class DebugLogger : IDisposable, IIdentifiableEntity, IDebugLogger { static NLog.Logger fdcClientLogger = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("FdcClient"); #region Fields private IIdentifiableEntity entity; private bool persistent; private object categoryDebugLevelLock = new object(); private Dictionary<object, DebugLogLevel> categoryDebugLevel = new Dictionary<object, DebugLogLevel>(); private bool logPersistentInfo; private bool disposed; #endregion #region Constructors /// <summary> /// Construction of non-persistent DebugLogger. /// </summary> /// <param name="entity"></param> public DebugLogger(IIdentifiableEntity entity) { if (Logger.IsClosed) disposed = true;// throw new LogException(LogExceptionType.LoggerClosed); if (entity != null) this.entity = entity; else this.entity = IdentifiableEntity.Empty; } /// <summary> /// Construction /// </summary> /// <param name="entity"></param> /// <param name="persistent"></param> public DebugLogger(IIdentifiableEntity entity, bool persistent) { //if (Logger.IsClosed) // disposed = true;// throw new LogException(LogExceptionType.LoggerClosed); //else //{ // if (entity != null) // this.entity = entity; // else // this.entity = IdentifiableEntity.Empty; // this.persistent = persistent; // if (persistent) // { // Logger.RegisterPersistentLogObject(this as DebugLogger); // logPersistentInfo = true; // } //} } /// <summary> /// Finalizer. /// </summary> ~DebugLogger() { Dispose(false); } #endregion #region IDisposable Members /// <summary> /// Dispose. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// Dispose. /// </summary> private void Dispose(bool disposing) { if (!disposed) { disposed = true; if (disposing) { if (persistent) { Logger.UnregisterPersistentLogObject(this as DebugLogger); } Logger.UnregisterEntity(entity); } lock (categoryDebugLevelLock) { categoryDebugLevel.Clear(); } } } #endregion #region Properties /// <summary> /// The identifiable entity that has created this debug log. /// </summary> public IIdentifiableEntity Entity { get { return entity; } } /// <summary> /// Tells whether the debug log is persistent or not. /// </summary> public bool Persistent { get { return persistent; } } #endregion #region Methods: IsActive /// <summary> /// Tells whether the default category is active in the Normal level. /// </summary> public bool IsActive() { return true; return !disposed && (DebugLogLevel.Normal <= GetDebugLevel(string.Empty)); } /// <summary> /// Tells whether the given category is active in the Normal level. /// </summary> public bool IsActive(object category) { return true; return !disposed && (DebugLogLevel.Normal <= GetDebugLevel(category)); } /// <summary> /// Tells whether the default category is active in the given level. /// </summary> public bool IsActive(DebugLogLevel debugLogLevel) { return true; return !disposed && (debugLogLevel != DebugLogLevel.Excluded) && (debugLogLevel <= GetDebugLevel(string.Empty)); } /// <summary> /// Tells whether the given category is active in the given level. /// </summary> public bool IsActive(object category, DebugLogLevel debugLogLevel) { return true; return !disposed && (debugLogLevel != DebugLogLevel.Excluded) && (debugLogLevel <= GetDebugLevel(category)); } #endregion #region Methods: GetDebugLevel /// <summary> /// Get the current debug level for the default category. /// </summary> public DebugLogLevel GetDebugLevel() { return GetDebugLevel(string.Empty); } /// <summary> /// Get the current debug level for the given category. /// </summary> public DebugLogLevel GetDebugLevel(object category) { return DebugLogLevel.Detailed; if (disposed || Logger.IsClosed) return DebugLogLevel.Excluded; if (category == null) category = string.Empty; // Check if this category's debuglevel is cached. lock (categoryDebugLevelLock) { DebugLogLevel cachedDebugLogLevel; if (categoryDebugLevel.TryGetValue(category, out cachedDebugLogLevel)) return cachedDebugLogLevel; } // Get a list of the logWriters that wants to log me. EntityCategory entityCategory = Logger.DebugConfig.GetEntityCategory(entity, category); LogWriter[] logWriters = Logger.DebugConfig.GetLogWriters(entityCategory); // Iterate through the writers and get the highest debug level. DebugLogLevel debugLogLevel = DebugLogLevel.Excluded; foreach (LogWriter writer in logWriters) { debugLogLevel = MaxDebugLogLevel(debugLogLevel, writer.GetDebugLogLevel(entityCategory)); } // Cache this debug level for future queries. lock (categoryDebugLevelLock) { categoryDebugLevel[category] = debugLogLevel; } return debugLogLevel; } #endregion #region Methods: Add /// <summary> /// Adds a new object to the debug log entry. /// </summary> /// <param name="obj">The log object that are added.</param> [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj")] public void Add(object obj) { fdcClientLogger.Debug(obj); return; if (disposed) return; if (logPersistentInfo) LogPersistentInfo(); Logger.AddEntry(new DebugLogEntry(entity, obj)); } /// <summary> /// Adds the object if debuglogger is active with the default category and detaillevel. /// </summary> /// <param name="args"></param> /// <param name="formatString"></param> public void AddIfActive(string formatString, params object[] args) { fdcClientLogger.Debug(string.Format(formatString, args)); return; if (IsActive()) { try { Add(string.Format(formatString, args)); } catch (FormatException fe) { Add(fe); Add(formatString); } } } /// <summary> /// Adds the object if debuglogger is active with the default category and detaillevel Detailed . /// </summary> /// <param name="formatString"></param> /// <param name="args"></param> public void AddIfActiveDetailed(string formatString, params object[] args) { fdcClientLogger.Debug(string.Format(formatString, args)); return; if (IsActive(DebugLogLevel.Detailed)) { try { Add(string.Format(formatString, args), DebugLogLevel.Detailed); } catch (FormatException fe) { Add(fe); Add(formatString); } } } /// <summary> /// Adds a new object to the debug log entry. /// </summary> /// <param name="obj">The log object that are added.</param> /// <param name="level">TDB</param> public void Add(object obj, DebugLogLevel level) { fdcClientLogger.Debug(obj); return; if (disposed) return; if (logPersistentInfo) LogPersistentInfo(); Logger.AddEntry(new DebugLogEntry(entity, obj, level)); } /// <summary> /// Adds a new object to the debug log entry. /// </summary> /// <param name="obj">The log object that are added.</param> /// <param name="category">A specific category that this log is about.</param> [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj")] public void Add(object obj, object category) { fdcClientLogger.Debug(obj); return; if (disposed) return; if (logPersistentInfo) LogPersistentInfo(); Logger.AddEntry(new DebugLogEntry(entity, obj, category)); } /// <summary> /// Adds a new object to the debug log entry. /// </summary> /// <param name="obj">The log object that are added.</param> /// <param name="category">A specific category that this log is about.</param> /// <param name="level">TDB</param> [SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj")] public void Add(object obj, object category, DebugLogLevel level) { fdcClientLogger.Debug(obj); return; if (disposed) return; if (logPersistentInfo) LogPersistentInfo(); Logger.AddEntry(new DebugLogEntry(entity, obj, category, level)); } /// <summary> /// /// </summary> private void LogPersistentInfo() { //Logger.AddEntry(new DebugLogEntry(entity, "Hooked persistent DebugLogger to logfile: " + IdentifiableEntity.ToString(entity, true), string.Empty, DebugLogLevel.Normal)); //logPersistentInfo = false; } #endregion #region Internal Methods /// <summary> /// Invalidates the internal flags for configuration reading. /// </summary> internal void Invalidate() { //lock (categoryDebugLevelLock) //{ // categoryDebugLevel.Clear(); //} } /// <summary> /// Static method to get the highest of two DebugLogLevel's. /// </summary> /// <param name="level1"></param> /// <param name="level2"></param> /// <returns></returns> public static DebugLogLevel MaxDebugLogLevel(DebugLogLevel level1, DebugLogLevel level2) { if (level1 > level2) return level1; else return level2; } #endregion #region IIdentifiableEntity Members /// <summary> /// The Id of the Entity. /// </summary> public int Id { get { return entity.Id; } } /// <summary> /// The EntityType of the Entity. /// </summary> public string EntityType { get { return entity.EntityType; } } /// <summary> /// This is used by the logger and should never be set by implementing classes /// </summary> public string FullEntityName { get; set; } /// <summary> /// The EntitySubType of the Entity. /// </summary> public string EntitySubType { get { return entity.EntitySubType; } } /// <summary> /// The ParentEntity of the Entity. /// </summary> public IIdentifiableEntity ParentEntity { get { return entity.ParentEntity; } } #endregion } }