StatusLog.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  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. private int CACHE_DAYS = 30;//缓存天数
  46. private string LogPath = AppDomain.CurrentDomain.BaseDirectory + LOG_PATH;//存储路径
  47. private DateTime Time = DateTime.Now;//标记当前时间
  48. private Task Listener = null;//监测任务
  49. private Process AppProcess = Process.GetCurrentProcess();
  50. private CancellationTokenSource CancelToken = new CancellationTokenSource();//监测取消Token
  51. private PerformanceCounter ComputerProcessor = ComputerStatusTool.Processor();//电脑CPU监控
  52. #endregion
  53. public void SetLogPath(string path)
  54. {
  55. if (!string.IsNullOrWhiteSpace(path))
  56. {
  57. LogPath = DirTool.Combine(path, LOG_PATH);
  58. }
  59. }
  60. public void SetCacheDays(int days)
  61. {
  62. if (days >= 0) CACHE_DAYS = days;
  63. }
  64. public bool Start()
  65. {
  66. //如果任务停止运行,则重新创建Token,并释放上次任务
  67. if (Listener != null && Listener.Status != TaskStatus.Running)
  68. {
  69. try
  70. {
  71. CancelToken = new CancellationTokenSource();
  72. Listener.Dispose();
  73. }
  74. catch { }
  75. }
  76. //如果任务没取消,并且没有运行任务,则运行任务
  77. if (!CancelToken.IsCancellationRequested && (Listener == null || Listener.Status != TaskStatus.Running))
  78. {
  79. Listener = Task.Factory.StartNew(() =>
  80. {
  81. try { WriteConfig(); } catch { }
  82. try
  83. {
  84. long afk = WindowsAPI.GetLastInputTime();//空闲时间缓存
  85. TimeSpan pin = TimeSpan.Zero;//程序运行时间戳
  86. StatusLogModel status = null;//运行状态信息模型
  87. DateTime recCycTime = DateTime.Now;
  88. int count = 1;
  89. while (!CancelToken.IsCancellationRequested)
  90. {
  91. pin = AppProcess.TotalProcessorTime;//程序运行时间戳
  92. Thread.Sleep(Interval);//等待间隔时间
  93. //每秒钟都会执行的操作
  94. DateTime now = DateTime.Now;
  95. int time = (int)(now - recCycTime).TotalMilliseconds;
  96. CollectStatus(ref status, count, time, ref afk, pin);//收集数据
  97. if (!(recCycTime.Year == now.Year && recCycTime.Month == now.Month && recCycTime.Day == now.Day && recCycTime.Hour == now.Hour && recCycTime.Minute == now.Minute))
  98. {
  99. WriteStatus(status);//写出数据
  100. count = 1;//重置运行时间
  101. status = null;//重置数据
  102. recCycTime = DateTime.Now;
  103. }
  104. count++;
  105. }
  106. }
  107. catch { }
  108. }, CancelToken.Token);
  109. return true;
  110. }
  111. return false;
  112. }
  113. public bool Stop()
  114. {
  115. try
  116. {
  117. if (!CancelToken.IsCancellationRequested)
  118. {
  119. CancelToken.Cancel();
  120. }
  121. return true;
  122. }
  123. catch { return false; }
  124. }
  125. /// <summary>
  126. /// 写出资源配置信息
  127. /// </summary>
  128. private void WriteConfig()
  129. {
  130. //记录固定资源信息
  131. string path = DirTool.Combine(LogPath, "resource");
  132. string file = DirTool.Combine(path, "computer.ini");
  133. //创建目录
  134. DirTool.Create(path);
  135. //写出信息
  136. IniTool.WriteValue(file, "system", "ram", ComputerInfoTool.TotalPhysicalMemory().ToString());
  137. IniTool.WriteValue(file, "system", "drive", ComputerInfoTool.GetSystemDriveTotalSize().ToString());
  138. }
  139. /// <summary>
  140. /// 收集数据
  141. /// </summary>
  142. /// <returns></returns>
  143. private bool CollectStatus(ref StatusLogModel status, int count, int runtime, ref long afk, TimeSpan pin)
  144. {
  145. try
  146. {
  147. if (status == null) status = new StatusLogModel() { Time = DateTime.Now };
  148. //固定值数据
  149. status.Long = runtime;//运行时长
  150. //累计值数据
  151. long nowAfk = WindowsAPI.GetLastInputTime();
  152. long afktemp = nowAfk - afk;
  153. if (afktemp > 0) status.AFK = status.AFK + afktemp;
  154. //Console.WriteLine($"nowAfk: {nowAfk}, afk: {afk}, afktemp: {afktemp}, statusAFK: {status.AFK}");
  155. afk = nowAfk;
  156. //计算平均值数据
  157. int cpu = 0;
  158. try { cpu = (int)ComputerProcessor.NextValue(); } catch { }//CPU占用
  159. long ram = (long)ComputerInfoTool.AvailablePhysicalMemory();//系统可用内存
  160. int appcpu = (int)AppInfoTool.CalcCpuRate(AppProcess, pin, Interval);//程序CPU占用
  161. long appram = AppInfoTool.RAM();//程序内存占用
  162. long sysdisk = ComputerInfoTool.GetSystemDriveAvailableSize();//系统盘可用空间
  163. status.CpuPer = ((count - 1) * status.CpuPer + cpu) / count;//CPU占用
  164. status.RamFree = ((count - 1) * status.RamFree + ram) / count;//系统可用内存
  165. status.AppCpuPer = ((count - 1) * status.AppCpuPer + appcpu) / count;//程序CPU占用
  166. status.AppRamUsed = ((count - 1) * status.AppRamUsed + appram) / count;//程序内存占用
  167. status.SysDriveFree = ((count - 1) * status.SysDriveFree + sysdisk) / count;//系统盘可用空间
  168. return true;
  169. }
  170. catch { return false; }
  171. }
  172. /// <summary>
  173. /// 写出运行时状态信息
  174. /// </summary>
  175. private void WriteStatus(StatusLogModel status)
  176. {
  177. try
  178. {
  179. if (status != null)
  180. {
  181. //处理比率
  182. status.Long = status.Long / 1000;
  183. status.AFK = status.AFK / 1000;
  184. if (status.AFK > status.Long) status.AFK = status.Long;
  185. //设置日志目录和日志文件
  186. string path = DirTool.Combine(LogPath, "status");
  187. string file = DirTool.Combine(path, DateTime.Now.ToString("yyyy-MM-dd") + ".txt");
  188. //创建日志目录
  189. DirTool.Create(path);
  190. //写出日志
  191. TxtTool.Append(file, status.ToString());
  192. }
  193. Cleaner();
  194. }
  195. catch { }
  196. }
  197. /// <summary>
  198. /// 清理过多的状态信息文件
  199. /// </summary>
  200. private void Cleaner()
  201. {
  202. string path = DirTool.Combine(LogPath, "status");
  203. List<string> files = FileTool.GetFile(path);
  204. if (ListTool.HasElements(files))
  205. {
  206. files.ForEach(f =>
  207. {
  208. try
  209. {
  210. string filename = Path.GetFileNameWithoutExtension(f);
  211. if (filename.Length == 10)
  212. {
  213. DateTime date = DateTime.Parse(filename);
  214. if (date < Time.AddDays(-CACHE_DAYS - 1)) FileTool.Delete(f);
  215. }
  216. else { FileTool.Delete(f); }
  217. }
  218. catch { FileTool.Delete(f); }
  219. });
  220. }
  221. }
  222. }
  223. }