LogOperator.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. //======================================================================
  2. //
  3. // Copyright (C) 2013 仙剑
  4. // All rights reserved
  5. // guid1: 4323ea5b-c739-4c99-add9-8739f89d0ab9
  6. // CLR Version: 2.0.50727.5420
  7. // Name: LogOperator
  8. // Computer: CHARLEY-PC
  9. // Organization: VoiceCyber
  10. // Namespace: VCLogWebSDK
  11. // File Name: LogOperator
  12. //
  13. // created by Charley at 2013/6/9 12:01:11
  14. // http://www.baidu.com/p/仙剑200801
  15. //
  16. //======================================================================
  17. using System;
  18. using System.Linq;
  19. using System.Text;
  20. using System.Security.AccessControl;
  21. using System.IO;
  22. using System.Threading;
  23. namespace Core.StlMes.Client.PlnSaleOrd
  24. {
  25. /// <summary>
  26. /// 日志操作,实现写日志、备份与回删日志
  27. ///
  28. /// 使用实例:
  29. /// LogOperator logOperator=new LogOperator();
  30. /// logOperator.WriteOperationLog(mode,category,msg);
  31. ///
  32. /// 可以对日志文件大小、日志文件夹大小、日志文件名、日志保存路径进行设置
  33. /// 自动备份、自动回删日志文件
  34. /// 支持无阻塞的异步方式写操作日志(logOperator.WriteOperationLogAsync(int level,category,msg))
  35. ///
  36. /// Charley
  37. /// 2013/11/5
  38. /// </summary>
  39. public class LogOperator
  40. {
  41. private const int LOG_FILE_SIZE = 1000; //log file size 1000(KB)
  42. private const int LOG_DIR_SIZE = 10; //log directory size 10(M)
  43. private const string LOG_FILE_NAME = "log";
  44. private const string LOG_PATH = "log";
  45. private const string LOG_NAME = "XJLogOperator";
  46. private const int LOG_SAVE_DAYS = 31;
  47. private delegate void WriteLogDelegate(LogMode level, string category, string msg); //利用委托异步写操作日志
  48. private WriteLogDelegate mWriteLogDelegate;
  49. private StreamWriter mLogWriter;
  50. private object mLogWriterLocker;
  51. private DateTime mLastDate;
  52. private Thread mThreadDelete;
  53. private bool m_bStart = false;
  54. #region Properties
  55. private int mLogFileMaxSize;
  56. /// <summary>
  57. /// 单个日志文件的大小,单位KB
  58. /// </summary>
  59. public int LogFileMaxSize
  60. {
  61. set { mLogFileMaxSize = value; }
  62. }
  63. private int mLogDirMaxSize;
  64. /// <summary>
  65. /// 日志文件夹总大小,单位MB,(暂未实现)
  66. /// </summary>
  67. public int LogDirMaxSize
  68. {
  69. set { mLogDirMaxSize = value; }
  70. }
  71. private string mLogFileName;
  72. /// <summary>
  73. /// 日志文件名
  74. /// </summary>
  75. public string LogFileName
  76. {
  77. get { return mLogFileName; }
  78. set { mLogFileName = value; }
  79. }
  80. private string mLogPath;
  81. private string m_LogPathDate;//包含日期的路径
  82. /// <summary>
  83. /// 日志路径(相对路径或绝对路径)
  84. /// </summary>
  85. public string LogPath
  86. {
  87. get { return mLogPath; }
  88. set
  89. {
  90. mLogPath = string.IsNullOrEmpty(value) ? LOG_PATH : value;
  91. if (!Path.IsPathRooted(mLogPath))
  92. {
  93. m_LogPathDate = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format("{0}{1}", mLogPath, "\\" + DateTime.Now.ToString("yyyyMMdd")));
  94. }
  95. if (mLogWriter != null)
  96. {
  97. try
  98. {
  99. mLogWriter.Dispose();
  100. //mLogWriter.Close();
  101. mLogWriter = null;
  102. }
  103. catch { }
  104. string path = Path.Combine(m_LogPathDate, m_LogPathDate);
  105. mLogWriter = new StreamWriter(path, true, Encoding.Default);
  106. }
  107. }
  108. }
  109. private string mErrorMsg;
  110. /// <summary>
  111. /// 操作错误消息
  112. /// </summary>
  113. public string ErrorMsg
  114. {
  115. get { return mErrorMsg; }
  116. }
  117. private string mLogName;
  118. /// <summary>
  119. /// 日志名称
  120. /// </summary>
  121. public string LogName
  122. {
  123. set { mLogName = value; }
  124. }
  125. private LogMode mLogMode;
  126. /// <summary>
  127. /// 日志级别
  128. /// </summary>
  129. public LogMode LogMode
  130. {
  131. get { return mLogMode; }
  132. set { mLogMode = value; }
  133. }
  134. public int mLogSaveDays;
  135. /// <summary>
  136. /// 日志保留天数
  137. /// </summary>
  138. // public int LogSaveDays
  139. // {
  140. // get { return mLogSaveDays; }
  141. // set { mLogSaveDays = value; }
  142. // }
  143. #endregion
  144. /// <summary>
  145. /// 使用默认值创建日志实例
  146. /// </summary>
  147. public LogOperator()
  148. {
  149. mWriteLogDelegate = WriteOperationLogWithoutReturn;
  150. mLogWriterLocker = new object();
  151. mLogMode = LogMode.General;
  152. mLogName = LOG_NAME;
  153. mLogFileMaxSize = LOG_FILE_SIZE;
  154. mLogDirMaxSize = LOG_DIR_SIZE;
  155. mLogFileName = LOG_FILE_NAME;
  156. mLogPath = LOG_PATH;
  157. mLastDate = DateTime.Now;
  158. mLogSaveDays = -1;
  159. if (!Path.IsPathRooted(mLogPath))
  160. {
  161. m_LogPathDate = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format("{0}{1}", mLogPath, "\\" + DateTime.Now.ToString("yyyyMMdd")));
  162. }
  163. }
  164. /// <summary>
  165. /// 指定日志名称
  166. /// </summary>
  167. /// <param name="logName"></param>
  168. public LogOperator(string logName)
  169. : this()
  170. {
  171. mLogName = logName;
  172. }
  173. /// <summary>
  174. /// 启动日志写入器
  175. /// </summary>
  176. /// <returns></returns>
  177. public bool Start()
  178. {
  179. if (string.IsNullOrEmpty(mLogPath) || string.IsNullOrEmpty(mLogFileName))
  180. {
  181. mErrorMsg = "Log file name or log file path is empty.";
  182. return false;
  183. }
  184. try
  185. {
  186. DateTime now = DateTime.Now;
  187. mLastDate = now;
  188. m_LogPathDate = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format("{0}{1}", mLogPath, "\\" + DateTime.Now.ToString("yyyyMMdd")));
  189. string dir = Path.IsPathRooted(mLogPath) ? mLogPath : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, string.Format("{0}{1}", mLogPath, "\\" + DateTime.Now.ToString("yyyyMMdd")));
  190. if (!Directory.Exists(dir))
  191. {
  192. Directory.CreateDirectory(dir);
  193. addDirPower(dir, "Everyone", "FullControl");
  194. }
  195. string path = Path.Combine(dir, string.Format("{0}{1}.txt", mLogFileName, now.ToString("yyyMMdd")));
  196. lock (mLogWriterLocker)
  197. {
  198. if (mLogWriter != null)
  199. {
  200. try
  201. {
  202. mLogWriter.Dispose();
  203. mLogWriter.Close();
  204. mLogWriter = null;
  205. }
  206. catch { }
  207. }
  208. mLogWriter = new StreamWriter(path, true, Encoding.Default);
  209. }
  210. mLogWriter.WriteLine("{0}\tLog Started.{1}", LogMode.Info, mLastDate.ToString("yyyy/MM/dd"));
  211. mLogWriter.Flush();
  212. if (!m_bStart)
  213. {
  214. StartDeleteLogThread();
  215. m_bStart = true;
  216. }
  217. return true;
  218. }
  219. catch (Exception ex)
  220. {
  221. mErrorMsg = ex.Message;
  222. return false;
  223. }
  224. }
  225. /// <summary>
  226. /// 停止并关闭日志写入器
  227. /// </summary>
  228. public void Stop()
  229. {
  230. StopDeleteThread();
  231. if (mLogWriter != null)
  232. {
  233. try
  234. {
  235. mLogWriter.Dispose();
  236. mLogWriter.Close();
  237. mLogWriter = null;
  238. }
  239. catch { }
  240. }
  241. }
  242. /// <summary>
  243. /// 写操作日志
  244. /// </summary>
  245. /// <param name="mode">日志级别</param>
  246. /// <param name="category">类别</param>
  247. /// <param name="msg">消息</param>
  248. /// <returns></returns>
  249. public bool WriteOperationLog(LogMode mode, string category, string msg)
  250. {
  251. try
  252. {
  253. if ((mode & mLogMode) == 0) { return true; }
  254. DateTime now = DateTime.Now;
  255. if (mLastDate.Date != now.Date)
  256. {
  257. if (!Start())
  258. {
  259. return false;
  260. }
  261. }
  262. if (mLogWriter == null)
  263. {
  264. Start();
  265. }
  266. if (category.Length <= 8)
  267. {
  268. category = category + "\t";
  269. }
  270. string formatstr = string.Format("{0}\t{1}\t{2}\t{3}", mode, DateTime.Now.ToString("HH:mm:ss.fff"), category, msg);
  271. lock (mLogWriterLocker)
  272. {
  273. if (mLogWriter != null)
  274. {
  275. mLogWriter.WriteLine(formatstr);
  276. mLogWriter.Flush();
  277. }
  278. }
  279. if (!BackupLog())
  280. {
  281. return false;
  282. }
  283. return true;
  284. }
  285. catch (Exception ex)
  286. {
  287. mErrorMsg = ex.ToString();
  288. return false;
  289. }
  290. }
  291. /// <summary>
  292. /// 写操作日志
  293. /// </summary>
  294. /// <param name="mode"></param>
  295. /// <param name="msg"></param>
  296. /// <returns></returns>
  297. public bool WriteOperationLog(LogMode mode, string msg)
  298. {
  299. return WriteOperationLog(mode, mLogName, msg);
  300. }
  301. /// <summary>
  302. /// 以无阻塞的异步方式写操作日志
  303. /// </summary>
  304. /// <param name="mode">日志级别</param>
  305. /// <param name="category"></param>
  306. /// <param name="msg"></param>
  307. public void WriteOperationAsync(LogMode mode, string category, string msg)
  308. {
  309. mWriteLogDelegate.BeginInvoke(mode, category, msg, null, null);
  310. }
  311. /// <summary>
  312. /// 记录Debug日志
  313. /// </summary>
  314. /// <param name="category">类别</param>
  315. /// <param name="msg">消息</param>
  316. /// <returns></returns>
  317. public bool LogDebug(string category, string msg)
  318. {
  319. return WriteOperationLog(LogMode.Debug, category, msg);
  320. }
  321. /// <summary>
  322. /// 记录Info日志
  323. /// </summary>
  324. /// <param name="category">类别</param>
  325. /// <param name="msg">消息</param>
  326. /// <returns></returns>
  327. public bool LogInfo(string category, string msg)
  328. {
  329. return WriteOperationLog(LogMode.Info, category, msg);
  330. }
  331. /// <summary>
  332. /// 记录Warn日志
  333. /// </summary>
  334. /// <param name="category">类别</param>
  335. /// <param name="msg">消息</param>
  336. /// <returns></returns>
  337. public bool LogWarn(string category, string msg)
  338. {
  339. return WriteOperationLog(LogMode.Warn, category, msg);
  340. }
  341. /// <summary>
  342. /// 记录Error日志
  343. /// </summary>
  344. /// <param name="category">类别</param>
  345. /// <param name="msg">消息</param>
  346. /// <returns></returns>
  347. public bool LogError(string category, string msg)
  348. {
  349. return WriteOperationLog(LogMode.Error, category, msg);
  350. }
  351. /// <summary>
  352. /// 记录Fatal日志
  353. /// </summary>
  354. /// <param name="category">类别</param>
  355. /// <param name="msg">消息</param>
  356. /// <returns></returns>
  357. public bool LogFatal(string category, string msg)
  358. {
  359. return WriteOperationLog(LogMode.Fatal, category, msg);
  360. }
  361. #region BackupLog
  362. /// <summary>
  363. /// 备份日志文件
  364. /// </summary>
  365. /// <returns></returns>
  366. private bool BackupLog()
  367. {
  368. string filePath = Path.Combine(m_LogPathDate, string.Format("{0}{1}.txt", mLogFileName, mLastDate.ToString("yyyyMMdd")));
  369. if (!File.Exists(filePath))
  370. {
  371. mErrorMsg = string.Format("File not exist.\t{0}", filePath);
  372. return false;
  373. }
  374. lock (mLogWriterLocker)
  375. {
  376. var file = new FileInfo(filePath);
  377. long size = file.Length;
  378. if (size > mLogFileMaxSize * 1024)
  379. {
  380. string path = string.Empty;
  381. path = Path.Combine(m_LogPathDate, string.Format("{0}{1}.txt", mLogFileName, DateTime.Now.ToString("yyyyMMddhhmmssfff")));
  382. mLogWriter.Dispose();
  383. mLogWriter.Close();
  384. try
  385. {
  386. file.MoveTo(path);
  387. }
  388. catch { }
  389. mLogWriter = new StreamWriter(filePath, true, Encoding.Default);
  390. WriteOperationLog(LogMode.Info, "BackupLog", string.Format("Backup log {0} successful.", path));
  391. }
  392. }
  393. return true;
  394. }
  395. #endregion
  396. #region Other
  397. private void WriteOperationLogWithoutReturn(LogMode mode, string category, string msg)
  398. {
  399. WriteOperationLog(mode, category, msg);
  400. }
  401. private void addDirPower(string dirName, string username, string power)
  402. {
  403. DirectoryInfo dirInfo = new DirectoryInfo(dirName);
  404. if ((dirInfo.Attributes & FileAttributes.ReadOnly) != 0)
  405. {
  406. dirInfo.Attributes = FileAttributes.Normal;
  407. }
  408. //取得访问控制列表
  409. DirectorySecurity dirSecurity = dirInfo.GetAccessControl();
  410. switch (power)
  411. {
  412. case "FullControl":
  413. dirSecurity.AddAccessRule(new FileSystemAccessRule(username, FileSystemRights.FullControl, InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly, AccessControlType.Allow));
  414. break;
  415. case "ReadOnly":
  416. dirSecurity.AddAccessRule(new FileSystemAccessRule(username, FileSystemRights.Read, AccessControlType.Allow));
  417. break;
  418. case "Write":
  419. dirSecurity.AddAccessRule(new FileSystemAccessRule(username, FileSystemRights.Write, AccessControlType.Allow));
  420. break;
  421. case "Modify":
  422. dirSecurity.AddAccessRule(new FileSystemAccessRule(username, FileSystemRights.Modify, AccessControlType.Allow));
  423. break;
  424. }
  425. dirInfo.SetAccessControl(dirSecurity);
  426. }
  427. #endregion
  428. #region DeleteLog
  429. private void StartDeleteLogThread()
  430. {
  431. if (mThreadDelete != null)
  432. {
  433. try
  434. {
  435. mThreadDelete.Abort();
  436. mThreadDelete = null;
  437. }
  438. catch
  439. {
  440. }
  441. }
  442. try
  443. {
  444. mThreadDelete = new Thread(DeleteLogWorker);
  445. mThreadDelete.Start();
  446. }
  447. catch
  448. {
  449. //WriteOperationLog(LogMode.Error, "StartDeleteThread",string.Format("Start delete thread fail.\t{0}", ex.Message));
  450. }
  451. }
  452. private void StopDeleteThread()
  453. {
  454. if (mThreadDelete != null)
  455. {
  456. try
  457. {
  458. mThreadDelete.Abort();
  459. mThreadDelete = null;
  460. }
  461. catch { }
  462. }
  463. }
  464. public void SleepSeconds(int nSecond)
  465. {
  466. for (int i = 0; i < nSecond; i++)
  467. {
  468. Thread.Sleep(1000);
  469. }
  470. }
  471. private void DeleteLogWorker()
  472. {
  473. while (true)
  474. {
  475. SleepSeconds(5);
  476. if (mLogSaveDays < 0)
  477. {
  478. continue;
  479. }
  480. DeleteLog();
  481. SleepSeconds(3600);
  482. }
  483. }
  484. /// <summary>
  485. /// 回删日志文件
  486. /// </summary>
  487. /// <returns></returns>
  488. private void DeleteLog()
  489. {
  490. string dir = Path.IsPathRooted(mLogPath) ? mLogPath : Path.Combine(AppDomain.CurrentDomain.BaseDirectory, mLogPath);
  491. DirectoryInfo logdir = new DirectoryInfo(dir);
  492. var ListFiles = logdir.GetDirectories("*").OrderByDescending(f => f.LastWriteTime).ToList();
  493. DateTime now = DateTime.Now;
  494. for (int i = ListFiles.Count - 1; i >= 0; i--)
  495. {
  496. if ((now - ListFiles[i].LastWriteTime).TotalDays > mLogSaveDays)
  497. {
  498. try
  499. {
  500. WriteOperationLog(LogMode.Warn, "DeleteLogFile", string.Format("Delete log file {0}", ListFiles[i].Name));
  501. ListFiles[i].Delete(true);
  502. }
  503. catch (Exception ex)
  504. {
  505. WriteOperationLog(LogMode.Warn, "DeleteLogFile", string.Format("Delete log file fail!\t{0}", ex.Message));
  506. }
  507. }
  508. }
  509. }
  510. #endregion
  511. }
  512. /// <summary>
  513. /// 日志级别,可任意组合
  514. /// </summary>
  515. [Flags]
  516. public enum LogMode
  517. {
  518. /// <summary>
  519. /// 调试
  520. /// </summary>
  521. Debug = 1,
  522. /// <summary>
  523. /// 信息(默认)
  524. /// </summary>
  525. Info = 2,
  526. /// <summary>
  527. /// 警告
  528. /// </summary>
  529. Warn = 4,
  530. /// <summary>
  531. /// 错误
  532. /// </summary>
  533. Error = 8,
  534. /// <summary>
  535. /// 致命
  536. /// </summary>
  537. Fatal = 16,
  538. /// <summary>
  539. /// 所有消息
  540. /// </summary>
  541. All = Debug | Info | Warn | Error | Fatal,
  542. /// <summary>
  543. /// 一般
  544. /// </summary>
  545. General = Info | Warn | Error | Fatal,
  546. /// <summary>
  547. /// 自定义info 消息
  548. /// </summary>
  549. Infomsg = Info | Warn | Error,
  550. /// <summary>
  551. /// 自定义debug 消息
  552. /// </summary>
  553. Debugmsg = Debug | Warn | Error,
  554. /// <summary>
  555. /// 自定义默认 消息
  556. /// </summary>
  557. Defaultmsg = Warn | Error
  558. }
  559. }