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

[来源] 达内    [编辑] 达内   [时间]2012-09-12

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

概述
项目中要在操作数据库的异常处理中加入写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.
18. throw;
19. }
20. }
我们的设计图

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

资源下载