StatusLog.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. //************************************************************************
  2. // author: yuzhengyang
  3. // date: 2018.4.17 - 2018.4.27
  4. // desc: 程序运行状态日志
  5. // Copyright (c) yuzhengyang. All rights reserved.
  6. //************************************************************************
  7. using Azylee.Core.AppUtils;
  8. using Azylee.Core.DataUtils.CollectionUtils;
  9. using Azylee.Core.IOUtils.DirUtils;
  10. using Azylee.Core.IOUtils.FileUtils;
  11. using Azylee.Core.IOUtils.TxtUtils;
  12. using Azylee.Core.WindowsUtils.APIUtils;
  13. using Azylee.Core.WindowsUtils.InfoUtils;
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Diagnostics;
  17. using System.IO;
  18. using System.Linq;
  19. using System.Text;
  20. using System.Threading;
  21. using System.Threading.Tasks;
  22. namespace Azylee.Core.LogUtils.StatusLogUtils
  23. {
  24. public sealed class StatusLog
  25. {
  26. #region 单例模式
  27. private static StatusLog _StatusLog;
  28. private static readonly object syncObject = new object();
  29. private StatusLog() { }
  30. public static StatusLog Instance
  31. {
  32. get
  33. {
  34. if (_StatusLog == null)
  35. lock (syncObject)
  36. if (_StatusLog == null)
  37. _StatusLog = new StatusLog();
  38. return _StatusLog;
  39. }
  40. }
  41. #endregion
  42. #region 基础属性
  43. const string LOG_PATH = @"azylee.log";//存储路径
  44. const int Interval = 1000;//监测间隔时间
  45. const int WriteInterval = 60 * Interval;//写出间隔时间
  46. private int CACHE_DAYS = 30;//缓存天数
  47. private string LogPath = AppDomain.CurrentDomain.BaseDirectory + LOG_PATH;//存储路径
  48. private DateTime Time = DateTime.Now;//标记当前时间
  49. private Task Listener = null;//监测任务
  50. private Process AppProcess = Process.GetCurrentProcess();
  51. private CancellationTokenSource CancelToken = new CancellationTokenSource();//监测取消Token
  52. private PerformanceCounter ComputerProcessor = ComputerStatusTool.Processor();//电脑CPU监控
  53. #endregion
  54. public void SetLogPath(string path)
  55. {
  56. if (!string.IsNullOrWhiteSpace(path))
  57. {
  58. LogPath = DirTool.Combine(path, LOG_PATH);
  59. }
  60. }
  61. public void SetCacheDays(int days)
  62. {
  63. if (days >= 0) CACHE_DAYS = days;
  64. }
  65. public bool Start()
  66. {
  67. //如果任务停止运行,则重新创建Token,并释放上次任务
  68. if (Listener != null && Listener.Status != TaskStatus.Running)
  69. {
  70. try
  71. {
  72. CancelToken = new CancellationTokenSource();
  73. Listener.Dispose();
  74. }
  75. catch { }
  76. }
  77. //如果任务没取消,并且没有运行任务,则运行任务
  78. if (!CancelToken.IsCancellationRequested && (Listener == null || Listener.Status != TaskStatus.Running))
  79. {
  80. Listener = Task.Factory.StartNew(() =>
  81. {
  82. try
  83. {
  84. WriteConfig();
  85. int runtime = 0;//运行时间(毫秒)
  86. long afk = WindowsAPI.GetLastInputTime();//空闲时间缓存
  87. TimeSpan pin = TimeSpan.Zero;//程序运行时间戳
  88. StatusLogModel status = null;//运行状态信息模型
  89. while (!CancelToken.IsCancellationRequested)
  90. {
  91. pin = AppProcess.TotalProcessorTime;//程序运行时间戳
  92. runtime += Interval;//增加运行时间
  93. Thread.Sleep(Interval);//等待间隔时间
  94. //每秒钟都会执行的操作
  95. CollectStatus(ref status, runtime, afk, pin);//收集数据
  96. afk = WindowsAPI.GetLastInputTime();//空闲时间缓存
  97. //每分钟进行汇总输出
  98. if (runtime >= WriteInterval)
  99. {
  100. WriteStatus(status);//写出数据
  101. runtime = 0;//重置运行时间
  102. status = null;//重置数据
  103. }
  104. }
  105. }
  106. catch { }
  107. }, CancelToken.Token);
  108. return true;
  109. }
  110. return false;
  111. }
  112. public bool Stop()
  113. {
  114. try
  115. {
  116. if (!CancelToken.IsCancellationRequested)
  117. {
  118. CancelToken.Cancel();
  119. }
  120. return true;
  121. }
  122. catch { return false; }
  123. }
  124. /// <summary>
  125. /// 写出资源配置信息
  126. /// </summary>
  127. private void WriteConfig()
  128. {
  129. //记录固定资源信息
  130. string path = DirTool.Combine(LogPath, "resource");
  131. string file = DirTool.Combine(path, "computer.ini");
  132. //创建目录
  133. DirTool.Create(path);
  134. //写出信息
  135. IniTool.WriteValue(file, "system", "ram", ComputerInfoTool.TotalPhysicalMemory().ToString());
  136. IniTool.WriteValue(file, "system", "drive", ComputerInfoTool.GetSystemDriveTotalSize().ToString());
  137. }
  138. /// <summary>
  139. /// 收集数据
  140. /// </summary>
  141. /// <returns></returns>
  142. private bool CollectStatus(ref StatusLogModel status, int runtime, long afk, TimeSpan pin)
  143. {
  144. try
  145. {
  146. int count = runtime / Interval;//收集次数,用来帮助平均值计算
  147. if (status == null) status = new StatusLogModel() { Time = DateTime.Now };
  148. //固定值数据
  149. status.Long = runtime;//运行时长
  150. //累计值数据
  151. long afktemp = WindowsAPI.GetLastInputTime() - afk;
  152. if (afktemp > 0) status.AFK = status.AFK + afktemp;
  153. //计算平均值数据
  154. int cpu = 0;
  155. try { cpu = (int)ComputerProcessor.NextValue(); } catch { }//CPU占用
  156. long ram = (long)ComputerInfoTool.AvailablePhysicalMemory();//系统可用内存
  157. int appcpu = (int)AppInfoTool.CalcCpuRate(AppProcess, pin, Interval);//程序CPU占用
  158. long appram = AppInfoTool.RAM();//程序内存占用
  159. long sysdisk = ComputerInfoTool.GetSystemDriveAvailableSize();//系统盘可用空间
  160. status.CpuPer = ((count - 1) * status.CpuPer + cpu) / count;//CPU占用
  161. status.RamFree = ((count - 1) * status.RamFree + ram) / count;//系统可用内存
  162. status.AppCpuPer = ((count - 1) * status.AppCpuPer + appcpu) / count;//程序CPU占用
  163. status.AppRamUsed = ((count - 1) * status.AppRamUsed + appram) / count;//程序内存占用
  164. status.SysDriveFree = ((count - 1) * status.SysDriveFree + sysdisk) / count;//系统盘可用空间
  165. return true;
  166. }
  167. catch { return false; }
  168. }
  169. /// <summary>
  170. /// 写出运行时状态信息
  171. /// </summary>
  172. private void WriteStatus(StatusLogModel status)
  173. {
  174. try
  175. {
  176. if (status != null)
  177. {
  178. //处理比率
  179. status.Long = status.Long / 1000;
  180. status.AFK = status.AFK / 1000;
  181. //设置日志目录和日志文件
  182. string path = DirTool.Combine(LogPath, "status");
  183. string file = DirTool.Combine(path, DateTime.Now.ToString("yyyy-MM-dd") + ".txt");
  184. //创建日志目录
  185. DirTool.Create(path);
  186. //写出日志
  187. TxtTool.Append(file, status.ToString());
  188. }
  189. Cleaner();
  190. }
  191. catch { }
  192. }
  193. /// <summary>
  194. /// 清理过多的状态信息文件
  195. /// </summary>
  196. private void Cleaner()
  197. {
  198. string path = DirTool.Combine(LogPath, "status");
  199. List<string> files = FileTool.GetFile(path);
  200. if (ListTool.HasElements(files))
  201. {
  202. files.ForEach(f =>
  203. {
  204. try
  205. {
  206. string filename = Path.GetFileNameWithoutExtension(f);
  207. if (filename.Length == 10)
  208. {
  209. DateTime date = DateTime.Parse(filename);
  210. if (date < Time.AddDays(-CACHE_DAYS - 1)) FileTool.Delete(f);
  211. }
  212. else { FileTool.Delete(f); }
  213. }
  214. catch { FileTool.Delete(f); }
  215. });
  216. }
  217. }
  218. }
  219. }