ThreadLog.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.IO;
  5. using System.Text;
  6. using System.Threading;
  7. namespace CommonTool
  8. {
  9. public class ThreadLog : IDisposable
  10. {
  11. //日志对象的缓存队列
  12. private static Queue<Msg> _msgs;
  13. //日志文件保存的路径
  14. private static string _path;
  15. //日志写入线程的控制标记
  16. private static bool _state;
  17. //日志记录的类型
  18. private static LogType _type;
  19. //日志文件生命周期的时间标记
  20. private static DateTime _timeSign;
  21. //日志文件写入流对象
  22. private static StreamWriter _writer;
  23. Thread _thread;
  24. /// <summary>
  25. /// 创建日志对象的新实例,采用默认当前程序位置作为日志路径和默认的每日日志文件类型记录日志
  26. /// </summary>
  27. public ThreadLog()
  28. : this(".\\", LogType.Daily)
  29. {
  30. }
  31. /// <summary>
  32. /// 创建日志对象的新实例,采用默认当前程序位置作为日志路径并指定日志类型
  33. /// </summary>
  34. /// <param name="t">日志文件创建方式的枚举</param>
  35. public ThreadLog(LogType t)
  36. : this(".\\", t)
  37. {
  38. }
  39. /// <summary>
  40. /// 创建日志对象的新实例,根据指定的日志文件路径和指定的日志文件创建类型
  41. /// </summary>
  42. /// <param name="p">日志文件保存路径</param>
  43. /// <param name="t">日志文件创建方式的枚举</param>
  44. public ThreadLog(string p, LogType t)
  45. {
  46. if (_msgs == null)
  47. {
  48. _state = true;
  49. _path = p;
  50. _type = t;
  51. _msgs = new Queue<Msg>();
  52. _thread = new Thread(Work) {IsBackground = true};
  53. //保证线程随主程序退出而退出
  54. _thread.Start();
  55. }
  56. }
  57. //日志文件写入线程执行的方法
  58. private void Work()
  59. {
  60. while (true)
  61. {
  62. //判断队列中是否存在待写入的日志
  63. if (_msgs.Count > 0)
  64. {
  65. Msg msg;
  66. lock (_msgs)
  67. {
  68. msg = _msgs.Dequeue();
  69. }
  70. if (msg != null)
  71. {
  72. FileWrite(msg);
  73. }
  74. }
  75. else
  76. {
  77. //判断是否已经发出终止日志并关闭的消息
  78. if (_state)
  79. {
  80. Thread.Sleep(1);
  81. }
  82. else
  83. {
  84. FileClose();
  85. break;
  86. }
  87. }
  88. }
  89. if (_thread != null && _thread.IsAlive)
  90. {
  91. _thread.Abort();
  92. _thread = null;
  93. }
  94. }
  95. //根据日志类型获取日志文件名,并同时创建文件到期的时间标记
  96. //通过判断文件的到期时间标记将决定是否创建新文件。
  97. private string GetFilename()
  98. {
  99. DateTime now = DateTime.Now;
  100. string format = "";
  101. switch (_type)
  102. {
  103. case LogType.Daily:
  104. _timeSign = new DateTime(now.Year, now.Month, now.Day);
  105. _timeSign = _timeSign.AddDays(1);
  106. format = "yyyyMMdd'.log'";
  107. break;
  108. case LogType.Weekly:
  109. _timeSign = new DateTime(now.Year, now.Month, now.Day);
  110. _timeSign = _timeSign.AddDays(7);
  111. format = "yyyyMMdd'.log'";
  112. break;
  113. case LogType.Monthly:
  114. _timeSign = new DateTime(now.Year, now.Month, 1);
  115. _timeSign = _timeSign.AddMonths(1);
  116. format = "yyyyMM'.log'";
  117. break;
  118. case LogType.Annually:
  119. _timeSign = new DateTime(now.Year, 1, 1);
  120. _timeSign = _timeSign.AddYears(1);
  121. format = "yyyy'.log'";
  122. break;
  123. }
  124. return now.ToString(format);
  125. }
  126. //写入日志文本到文件的方法
  127. private void FileWrite(Msg msg)
  128. {
  129. try
  130. {
  131. if (_writer == null)
  132. {
  133. FileOpen();
  134. }
  135. //判断文件到期标志,如果当前文件到期则关闭当前文件创建新的日志文件
  136. if (DateTime.Now >= _timeSign)
  137. {
  138. FileClose();
  139. FileOpen();
  140. }
  141. if (_writer != null)
  142. {
  143. Thread.Sleep(1);
  144. _writer.Write(msg.Datetime);
  145. _writer.Write('\t');
  146. _writer.Write(msg.Type);
  147. _writer.Write('\t');
  148. _writer.WriteLine(msg.Text);
  149. _writer.Flush();
  150. }
  151. }
  152. catch (Exception e)
  153. {
  154. Console.Out.Write(e);
  155. }
  156. }
  157. //打开文件准备写入
  158. private void FileOpen()
  159. {
  160. if (!Directory.Exists(_path))
  161. Directory.CreateDirectory(_path);
  162. _writer = new StreamWriter(_path + GetFilename(), true, Encoding.UTF8);
  163. }
  164. //关闭打开的日志文件
  165. private void FileClose()
  166. {
  167. if (_writer != null)
  168. {
  169. _writer.Flush();
  170. _writer.Close();
  171. _writer.Dispose();
  172. _writer = null;
  173. }
  174. }
  175. public void WriteErr(string pcMsg)
  176. {
  177. Write(new Msg(pcMsg, LogMsgType.Error));
  178. }
  179. public void WriteInfor(string pcMsg)
  180. {
  181. Write(new Msg(pcMsg, LogMsgType.Information));
  182. }
  183. public void WriteSuccess(string pcMsg)
  184. {
  185. Write(new Msg(pcMsg, LogMsgType.Success));
  186. }
  187. public void WriteUnknown(string pcMsg)
  188. {
  189. Write(new Msg(pcMsg, LogMsgType.Unknown));
  190. }
  191. public void WriteWarning(string pcMsg)
  192. {
  193. Write(new Msg(pcMsg, LogMsgType.Warning));
  194. }
  195. /// <summary>
  196. /// 写入新日志,根据指定的日志对象Msg
  197. /// </summary>
  198. /// <param name="msg">日志内容对象</param>
  199. public void Write(Msg msg)
  200. {
  201. if (msg != null)
  202. {
  203. lock (_msgs)
  204. {
  205. _msgs.Enqueue(msg);
  206. }
  207. }
  208. }
  209. /// <summary>
  210. /// 写入新日志,根据指定的日志内容和信息类型,采用当前时间为日志时间写入新日志
  211. /// </summary>
  212. /// <param name="text">日志内容</param>
  213. /// <param name="type">信息类型</param>
  214. public void Write(string text, LogMsgType type)
  215. {
  216. Write(new Msg(text, type));
  217. }
  218. /// <summary>
  219. /// 写入新日志,根据指定的日志时间、日志内容和信息类型写入新日志
  220. /// </summary>
  221. /// <param name="dt">日志时间</param>
  222. /// <param name="text">日志内容</param>
  223. /// <param name="type">信息类型</param>
  224. public void Write(DateTime dt, string text, LogMsgType type)
  225. {
  226. Write(new Msg(dt, text, type));
  227. }
  228. /// <summary>
  229. /// 写入新日志,根据指定的异常类和信息类型写入新日志
  230. /// </summary>
  231. /// <param name="e">异常对象</param>
  232. /// <param name="type">信息类型</param>
  233. public void Write(Exception e, LogMsgType type)
  234. {
  235. Write(new Msg(e.Message, type));
  236. }
  237. #region IDisposable 成员
  238. /// <summary>
  239. /// 销毁日志对象
  240. /// </summary>
  241. public void Dispose()
  242. {
  243. _state = false;
  244. }
  245. #endregion
  246. static ThreadLog _sysLog;
  247. public static ThreadLog SysLog
  248. {
  249. get
  250. {
  251. if (_sysLog == null)
  252. {
  253. string lcpath = AppConfig.DefConfig.ReadString("LOGPATH");
  254. if (!string.IsNullOrEmpty(lcpath) && lcpath.Length > 0)
  255. {
  256. try
  257. {
  258. Directory.CreateDirectory(lcpath);
  259. }
  260. catch
  261. {
  262. // ignored
  263. }
  264. }
  265. _sysLog = Directory.Exists(lcpath) ? new ThreadLog(lcpath, LogType.Daily) : new ThreadLog(".\\Log\\", LogType.Daily);
  266. }
  267. return _sysLog;
  268. }
  269. }
  270. }
  271. public enum LogType
  272. {
  273. /// <summary>
  274. /// 此枚举指示每天创建一个新的日志文件
  275. /// </summary>
  276. Daily,
  277. /// <summary>
  278. /// 此枚举指示每周创建一个新的日志文件
  279. /// </summary>
  280. Weekly,
  281. /// <summary>
  282. /// 此枚举指示每月创建一个新的日志文件
  283. /// </summary>
  284. Monthly,
  285. /// <summary>
  286. /// 此枚举指示每年创建一个新的日志文件
  287. /// </summary>
  288. Annually
  289. }
  290. public class Msg
  291. {
  292. //日志记录的时间
  293. private DateTime _datetime;
  294. //日志记录的内容
  295. private string _text;
  296. //日志记录的类型
  297. /// <summary>
  298. /// 创建新的日志记录实例;日志记录的内容为空,消息类型为MsgType.Unknown,日志时间为当前时间
  299. /// </summary>
  300. public Msg()
  301. : this("", LogMsgType.Unknown)
  302. {
  303. }
  304. /// <summary>
  305. /// 创建新的日志记录实例;日志事件为当前时间
  306. /// </summary>
  307. /// <param name="t">日志记录的文本内容</param>
  308. /// <param name="p">日志记录的消息类型</param>
  309. public Msg(string t, LogMsgType p)
  310. : this(DateTime.Now, t, p)
  311. {
  312. }
  313. /// <summary>
  314. /// 创建新的日志记录实例;
  315. /// </summary>
  316. /// <param name="dt">日志记录的时间</param>
  317. /// <param name="t">日志记录的文本内容</param>
  318. /// <param name="p">日志记录的消息类型</param>
  319. public Msg(DateTime dt, string t, LogMsgType p)
  320. {
  321. _datetime = dt;
  322. Type = p;
  323. _text = t;
  324. }
  325. /// <summary>
  326. /// 获取或设置日志记录的时间
  327. /// </summary>
  328. public DateTime Datetime
  329. {
  330. get { return _datetime; }
  331. set { _datetime = value; }
  332. }
  333. /// <summary>
  334. /// 获取或设置日志记录的文本内容
  335. /// </summary>
  336. public string Text
  337. {
  338. get { return _text; }
  339. set { _text = value; }
  340. }
  341. /// <summary>
  342. /// 获取或设置日志记录的消息类型
  343. /// </summary>
  344. public LogMsgType Type { get; set; }
  345. public override string ToString()
  346. {
  347. return _datetime.ToString(CultureInfo.InvariantCulture) + "\t" + _text + "\n";
  348. }
  349. }
  350. public enum LogMsgType
  351. {
  352. //[3:钥匙授权],[4:开锁记录],[5:资产登记],[6:资产编码],[7:人员],[8:参数设置],[9:系统日志],[0:异常日志],[]
  353. /// <summary>
  354. /// 钥匙授权
  355. /// </summary>
  356. Authorize = 3,
  357. /// <summary>
  358. /// 开锁记录
  359. /// </summary>
  360. OpenLogs = 4,
  361. /// <summary>
  362. /// 资产登记
  363. /// </summary>
  364. Register = 5,
  365. /// <summary>
  366. /// 资产编码
  367. /// </summary>
  368. Coding = 6,
  369. /// <summary>
  370. /// 人员分组
  371. /// </summary>
  372. Persons = 7,
  373. /// <summary>
  374. /// 参数设置
  375. /// </summary>
  376. SysParameter = 8,
  377. /// <summary>
  378. /// 指示普通信息类型的日志记录
  379. /// </summary>
  380. Information = 9,
  381. /// <summary>
  382. /// 指示警告信息类型的日志记录
  383. /// </summary>
  384. Warning = 10,
  385. /// <summary>
  386. /// 指示未知信息类型的日志记录
  387. /// </summary>
  388. Unknown = 99,
  389. /// <summary>
  390. /// 指示错误信息类型的日志记录
  391. /// </summary>
  392. Error = 0,
  393. /// <summary>
  394. /// 指示成功信息类型的日志记录
  395. /// </summary>
  396. Success = 1
  397. }
  398. }