LoggerThread.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. namespace Wayne.Lib.Log
  5. {
  6. internal class LoggerThread : IDisposable
  7. {
  8. #region Fields
  9. private readonly Thread thread;
  10. private readonly AutoResetEvent waitEvent;
  11. private readonly Queue<LogEntry> entryQueue = new Queue<LogEntry>();
  12. private readonly object entryQueueLock = new object();
  13. private readonly object logWritingLock = new object();
  14. private bool threadShouldExit; // Flag that is used to indicate to the thread that it should exit gracefully.
  15. private bool disposed;
  16. private readonly LogConfig logConfig;
  17. #endregion
  18. #region Construction & Finalizer
  19. /// <summary>
  20. /// Initializes a new instance of the Logger thread and starts it.
  21. /// </summary>
  22. /// <param name="logType"></param>
  23. /// <param name="logConfig"></param>
  24. public LoggerThread(LogType logType, LogConfig logConfig)
  25. {
  26. this.logConfig = logConfig;
  27. //Create the wait event
  28. waitEvent = new AutoResetEvent(false);
  29. //Create the thread.
  30. thread = new Thread(Execute) { Priority = ThreadPriority.Lowest };
  31. switch (logType)
  32. {
  33. case LogType.Debug:
  34. thread.Name = "Debug Logger thread";
  35. break;
  36. case LogType.Event:
  37. thread.Name = "Event Logger thread";
  38. break;
  39. }
  40. thread.IsBackground = true;
  41. thread.Start();
  42. }
  43. /// <summary>
  44. /// Finalizer
  45. /// </summary>
  46. ~LoggerThread()
  47. {
  48. Dispose(false);
  49. }
  50. #endregion
  51. #region IDisposable Members
  52. /// <summary>
  53. /// Disposes the resources owned by the logger thread.
  54. /// </summary>
  55. public void Dispose()
  56. {
  57. Dispose(true);
  58. GC.SuppressFinalize(this);
  59. }
  60. /// <summary>
  61. /// Internal dispose method.
  62. /// </summary>
  63. /// <param name="disposing"></param>
  64. private void Dispose(bool disposing)
  65. {
  66. if (!disposed)
  67. {
  68. disposed = true;
  69. if (disposing)
  70. {
  71. threadShouldExit = true;
  72. waitEvent.Set();
  73. waitEvent.Close();
  74. thread.Join();
  75. }
  76. }
  77. }
  78. #endregion
  79. #region The thread method
  80. /// <summary>
  81. /// The main function for the logger thread.
  82. /// </summary>
  83. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
  84. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")]
  85. private void Execute()
  86. {
  87. while (!threadShouldExit)
  88. {
  89. try
  90. {
  91. // Wait for an event.
  92. waitEvent.WaitOne();
  93. if (!disposed)
  94. {
  95. // Clear the entry queue.
  96. bool queueEmpty;
  97. do
  98. {
  99. // Pick the next logEntry in the queue safely in a locked way.
  100. LogEntry logEntry = null;
  101. lock (entryQueueLock)
  102. {
  103. if (entryQueue.Count > 0)
  104. logEntry = entryQueue.Dequeue();
  105. queueEmpty = (entryQueue.Count == 0);
  106. }
  107. // Was there a log entry for me?
  108. if (!disposed && (logEntry != null))
  109. PerformLog(logEntry);
  110. }
  111. while (!queueEmpty);
  112. }
  113. }
  114. catch (Exception exception)
  115. {
  116. Logger.FireOnThreadException(new LogException(LogExceptionType.GeneralThreadException,
  117. "An Exception is caught in the Logger.Execute() method. See inner exception!", exception));
  118. }
  119. #if WindowsCE
  120. catch
  121. {
  122. Logger.FireOnThreadException(new LogException(LogExceptionType.GeneralThreadException,
  123. "An unknown exception is caught in the Logger.Execute() method."));
  124. }
  125. #endif
  126. }
  127. }
  128. /// <summary>
  129. /// Performs the actual logging.
  130. /// </summary>
  131. /// <param name="logEntry"></param>
  132. private void PerformLog(LogEntry logEntry)
  133. {
  134. lock (logWritingLock)
  135. {
  136. LogWriter[] logWriters;
  137. DebugMarkerLogEntry debugMarkerLogEntry = logEntry as DebugMarkerLogEntry;
  138. if (debugMarkerLogEntry != null)
  139. {
  140. // Get all active LogWriters.
  141. logWriters = logConfig.GetLogWriters();
  142. }
  143. else
  144. {
  145. // Get a list of the LogWriters that wants to log this entry.
  146. logWriters = logConfig.GetLogWriters(logEntry.EntityCategory);
  147. }
  148. // Call them in turn and write the log entry.
  149. foreach (LogWriter writer in logWriters)
  150. writer.Write(logEntry);
  151. }
  152. }
  153. #endregion
  154. #region Public Methods
  155. /// <summary>
  156. /// Adds an entry that should be handled by the logger thread.
  157. /// </summary>
  158. /// <param name="logEntry"></param>
  159. public void AddEntry(LogEntry logEntry)
  160. {
  161. if (disposed)
  162. return;
  163. if (Logger.Synchronized)
  164. {
  165. PerformLog(logEntry);
  166. }
  167. else
  168. {
  169. lock (entryQueueLock)
  170. {
  171. entryQueue.Enqueue(logEntry);
  172. }
  173. waitEvent.Set();
  174. }
  175. }
  176. #endregion
  177. }
  178. }