[转]C#开发高性能Log Help类设计开发


项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小,不能因为加入log导致耗时太多。在写入日志时利用Queue来管理,写日志有一个专门的backgroud线程来处理,如果没有日志要写,这个线程处于wait状态,这就有了线程的异步处理。
 


概述


项目中要在操作数据库的异常处理中加入写Log日志,对于商业上有要求,写log时对其它操作尽可能影响小,不能因为加入log导致耗时太多。


设计思想


在写入日志时利用Queue来管理,写日志有一个专门的backgroud线程来处理,如果没有日志要写,这个线程处于wait状态,这就有了线程的异步处理。


简单的实现方式

  1. //<summary>
  2. //Write Log
  3. //<summary>
  4. public static void WriteLog(string logFile, string msg)
  5. {
  6. try
  7. {
  8. System.IO.StreamWriter sw = System.IO.File.AppendText(
  9. logPath + LogFilePrefix +" "+ logFile + " " +
  10. DateTime.Now.ToString("yyyyMMdd") + ".Log"
  11. );
  12. sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss: ") + msg);
  13. sw.Close();
  14. }
  15. catch (Exception)
  16. {
  17. throw;
  18. }
  19. }

我们的设计图


image


而后我们在AddLogMessage时semaphore.Release()就能唤醒wait中的log 线程。


代码设计

  1. /// <summary>
  2. /// Author: spring yang
  3. /// Create time:2012/3/30
  4. /// Log Help class
  5. /// </summary>
  6. /// <remarks>High performance log class</remarks>
  7. public class Log : IDisposable
  8. {
  9. //Log Message queue
  10. private static Queue<LogMessage> _logMessages;
  11. //log save directory
  12. private static string _logDirectory;
  13. //log write file state
  14. private static bool _state;
  15. //log type
  16. private static LogType _logType;
  17. //log life time sign
  18. private static DateTime _timeSign;
  19. //log file stream writer
  20. private static StreamWriter _writer;
  21. /// <summary>
  22. /// Wait enqueue wirte log message semaphore will release
  23. /// </summary>
  24. private Semaphore _semaphore;
  25. /// <summary>
  26. /// Single instance
  27. /// </summary>
  28. private static Log _log;
  29. /// <summary>
  30. /// Gets a single instance
  31. /// </summary>
  32. public static Log LogInstance
  33. {
  34. get { return _log ?? (_log = new Log()); }
  35. }
  36. private object _lockObjeck;
  37. /// <summary>
  38. /// Initialize Log instance
  39. /// </summary>
  40. private void Initialize()
  41. {
  42. if (_logMessages == null)
  43. { _state = true;
  44. string logPath = System.Configuration.ConfigurationManager.AppSettings["LogDirectory"];
  45. _logDirectory = string.IsNullOrEmpty(logPath) ? ".\\log\\" : logPath;
  46. if (!Directory.Exists(_logDirectory)) Directory.CreateDirectory(_logDirectory);
  47. _logType = LogType.Daily;
  48. _lockObjeck=new object();
  49. _semaphore = new Semaphore(0, int.MaxValue, Constants.LogSemaphoreName);
  50. _logMessages = new Queue<LogMessage>();
  51. var thread = new Thread(Work) {IsBackground = true};
  52. thread.Start();
  53. }
  54. }
  55. /// <summary>
  56. /// Create a log instance
  57. /// </summary>
  58. private Log()
  59. {
  60. Initialize();
  61. }
  62. /// <summary>
  63. /// Log save name type,default is daily
  64. /// </summary>
  65. public LogType LogType
  66. {
  67. get { return _logType; }
  68. set { _logType = value; }
  69. }
  70. /// <summary>
  71. /// Write Log file work method
  72. /// </summary>
  73. private void Work()
  74. {
  75. while (true)
  76. {
  77. //Determine log queue have record need wirte
  78. if (_logMessages.Count > 0)
  79. {
  80. FileWriteMessage();
  81. }
  82. else
  83. if (WaitLogMessage()) break;
  84. }
  85. }
  86. /// <summary>
  87. /// Write message to log file
  88. /// </summary>
  89. private void FileWriteMessage()
  90. {
  91. LogMessage logMessage=null;
  92. lock (_lockObjeck)
  93. {
  94. if(_logMessages.Count>0)
  95. logMessage = _logMessages.Dequeue();
  96. }
  97. if (logMessage != null)
  98. {
  99. FileWrite(logMessage);
  100. }
  101. }
  102. /// <summary>
  103. /// The thread wait a log message
  104. /// </summary>
  105. /// <returns>is close or not</returns>
  106. private bool WaitLogMessage()
  107. {
  108. //determine log life time is true or false
  109. if (_state)
  110. {
  111. WaitHandle.WaitAny(new WaitHandle[] { _semaphore }, -1, false);
  112. return false;
  113. }
  114. FileClose();
  115. return true;
  116. }
  117. /// <summary>
  118. /// Gets file name by log type
  119. /// </summary>
  120. /// <returns>log file name</returns>
  121. private string GetFilename()
  122. {
  123. DateTime now = DateTime.Now;
  124. string format = "";
  125. switch (_logType)
  126. {
  127. case LogType.Daily:
  128. _timeSign = new DateTime(now.Year, now.Month, now.Day);
  129. _timeSign = _timeSign.AddDays(1);
  130. format = "yyyyMMdd'.log'";
  131. break;
  132. case LogType.Weekly:
  133. _timeSign = new DateTime(now.Year, now.Month, now.Day);
  134. _timeSign = _timeSign.AddDays(7);
  135. format = "yyyyMMdd'.log'";
  136. break;
  137. case LogType.Monthly:
  138. _timeSign = new DateTime(now.Year, now.Month, 1);
  139. _timeSign = _timeSign.AddMonths(1);
  140. format = "yyyyMM'.log'";
  141. break;
  142. case LogType.Annually:
  143. _timeSign = new DateTime(now.Year, 1, 1);
  144. _timeSign = _timeSign.AddYears(1);
  145. format = "yyyy'.log'";
  146. break;
  147. }
  148. return now.ToString(format);
  149. }
  150. /// <summary>
  151. /// Write log file message
  152. /// </summary>
  153. /// <param name="msg"></param>
  154. private void FileWrite(LogMessage msg)
  155. {
  156. try
  157. {
  158. if (_writer == null)
  159. {
  160. FileOpen();
  161. }
  162. else
  163. {
  164. //determine the log file is time sign
  165. if (DateTime.Now >= _timeSign)
  166. {
  167. FileClose();
  168. FileOpen();
  169. }
  170. _writer.WriteLine(Constants.LogMessageTime+msg.Datetime);
  171. _writer.WriteLine(Constants.LogMessageType+msg.Type);
  172. _writer.WriteLine(Constants.LogMessageContent+msg.Text);
  173. _writer.Flush();
  174. }
  175. }
  176. catch (Exception e)
  177. {
  178. Console.Out.Write(e);
  179. }
  180. }
  181. /// <summary>
  182. /// Open log file write log message
  183. /// </summary>
  184. private void FileOpen()
  185. {
  186. _writer = new StreamWriter(Path.Combine(_logDirectory, GetFilename()), true, Encoding.UTF8);
  187. }
  188. /// <summary>
  189. /// Close log file
  190. /// </summary>
  191. private void FileClose()
  192. {
  193. if (_writer != null)
  194. {
  195. _writer.Flush();
  196. _writer.Close();
  197. _writer.Dispose();
  198. _writer = null;
  199. }
  200. }
  201. /// <summary>
  202. /// Enqueue a new log message and release a semaphore
  203. /// </summary>
  204. /// <param name="msg">Log message</param>
  205. public void Write(LogMessage msg)
  206. {
  207. if (msg != null)
  208. {
  209. lock (_lockObjeck)
  210. {
  211. _logMessages.Enqueue(msg);
  212. _semaphore.Release();
  213. }
  214. }
  215. }
  216. /// <summary>
  217. /// Write message by message content and type
  218. /// </summary>
  219. /// <param name="text">log message</param>
  220. /// <param name="type">message type</param>
  221. public void Write(string text, MessageType type)
  222. {
  223. Write(new LogMessage(text, type));
  224. }
  225. /// <summary>
  226. /// Write Message by datetime and message content and type
  227. /// </summary>
  228. /// <param name="dateTime">datetime</param>
  229. /// <param name="text">message content</param>
  230. /// <param name="type">message type</param>
  231. public void Write(DateTime dateTime, string text, MessageType type)
  232. {
  233. Write(new LogMessage(dateTime, text, type));
  234. }
  235. /// <summary>
  236. /// Write message ty exception and message type
  237. /// </summary>
  238. /// <param name="e">exception</param>
  239. /// <param name="type">message type</param>
  240. public void Write(Exception e, MessageType type)
  241. {
  242. Write(new LogMessage(e.Message, type));
  243. }
  244. #region IDisposable member
  245. /// <summary>
  246. /// Dispose log
  247. /// </summary>
  248. public void Dispose()
  249. {
  250. _state = false;
  251. }
  252. #endregion
  253. }
  254. /// <summary>
  255. /// Log Type
  256. /// </summary>
  257. /// <remarks>Create log by daily or weekly or monthly or annually</remarks>
  258. public enum LogType
  259. {
  260. /// <summary>
  261. /// Create log by daily
  262. /// </summary>
  263. Daily,
  264. /// <summary>
  265. /// Create log by weekly
  266. /// </summary>
  267. Weekly,
  268. /// <summary>
  269. /// Create log by monthly
  270. /// </summary>
  271. Monthly,
  272. /// <summary>
  273. /// Create log by annually
  274. /// </summary>
  275. Annually
  276. }
  277. /// <summary>
  278. /// Log Message Class
  279. /// </summary>
  280. public class LogMessage
  281. {
  282. /// <summary>
  283. /// Create Log message instance
  284. /// </summary>
  285. public LogMessage()
  286. : this("", MessageType.Unknown)
  287. {
  288. }
  289. /// <summary>
  290. /// Crete log message by message content and message type
  291. /// </summary>
  292. /// <param name="text">message content</param>
  293. /// <param name="messageType">message type</param>
  294. public LogMessage(string text, MessageType messageType)
  295. : this(DateTime.Now, text, messageType)
  296. {
  297. }
  298. /// <summary>
  299. /// Create log message by datetime and message content and message type
  300. /// </summary>
  301. /// <param name="dateTime">date time </param>
  302. /// <param name="text">message content</param>
  303. /// <param name="messageType">message type</param>
  304. public LogMessage(DateTime dateTime, string text, MessageType messageType)
  305. {
  306. Datetime = dateTime;
  307. Type = messageType;
  308. Text = text;
  309. }
  310. /// <summary>
  311. /// Gets or sets datetime
  312. /// </summary>
  313. public DateTime Datetime { get; set; }
  314. /// <summary>
  315. /// Gets or sets message content
  316. /// </summary>
  317. public string Text { get; set; }
  318. /// <summary>
  319. /// Gets or sets message type
  320. /// </summary>
  321. public MessageType Type { get; set; }
  322. /// <summary>
  323. /// Get Message to string
  324. /// </summary>
  325. /// <returns></returns>
  326. public new string ToString()
  327. {
  328. return Datetime.ToString(CultureInfo.InvariantCulture) + "\t" + Text + "\n";
  329. }
  330. }
  331. /// <summary>
  332. /// Log Message Type enum
  333. /// </summary>
  334. public enum MessageType
  335. {
  336. /// <summary>
  337. /// unknown type
  338. /// </summary>
  339. Unknown,
  340. /// <summary>
  341. /// information type
  342. /// </summary>
  343. Information,
  344. /// <summary>
  345. /// warning type
  346. /// </summary>
  347. Warning,
  348. /// <summary>
  349. /// error type
  350. /// </summary>
  351. Error,
  352. /// <summary>
  353. /// success type
  354. /// </summary>
  355. Success
  356. }

Test Case:

  1. public static void TestLog()
  2. {
  3. Log.LogInstance.Write( "Test Message",MessageType.Information);
  4. Log.LogInstance.Write("one",MessageType.Error);
  5. Log.LogInstance.Write("two", MessageType.Success);
  6. Log.LogInstance.Write("three", MessageType.Warning);
  7. }

运行结果:


image


接受Mainz的建议,改了部分代码。

原文地址:https://www.cnblogs.com/zhangzt/p/2462377.html