LogManager.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Text.RegularExpressions;
  7. using System.Threading;
  8. using System.Threading.Tasks;
  9. namespace Masuit.Tools.Core.Logging
  10. {
  11. /// <summary>
  12. /// 日志组件
  13. /// </summary>
  14. public class LogManager
  15. {
  16. static readonly ConcurrentQueue<Tuple<string, string>> LogQueue = new ConcurrentQueue<Tuple<string, string>>();
  17. /// <summary>
  18. /// 自定义事件
  19. /// </summary>
  20. public static event Action<LogInfo> Event;
  21. static LogManager()
  22. {
  23. var writeTask = new Task(obj =>
  24. {
  25. while (true)
  26. {
  27. Pause.WaitOne(1000, true);
  28. List<string[]> temp = new List<string[]>();
  29. foreach (var logItem in LogQueue)
  30. {
  31. string logPath = logItem.Item1;
  32. string logMergeContent = String.Concat(logItem.Item2, Environment.NewLine, "----------------------------------------------------------------------------------------------------------------------", Environment.NewLine);
  33. string[] logArr = temp.FirstOrDefault(d => d[0].Equals(logPath));
  34. if (logArr != null)
  35. {
  36. logArr[1] = string.Concat(logArr[1], logMergeContent);
  37. }
  38. else
  39. {
  40. logArr = new[] { logPath, logMergeContent };
  41. temp.Add(logArr);
  42. }
  43. LogQueue.TryDequeue(out Tuple<string, string> _);
  44. }
  45. foreach (var item in temp)
  46. {
  47. WriteText(item[0], item[1]);
  48. }
  49. }
  50. }, null, TaskCreationOptions.LongRunning);
  51. writeTask.Start();
  52. }
  53. private static AutoResetEvent Pause => new AutoResetEvent(false);
  54. /// <summary>
  55. /// 日志存放目录,默认日志放在当前应用程序运行目录下的logs文件夹中
  56. /// </summary>
  57. public static string LogDirectory
  58. {
  59. get => AppContext.BaseDirectory + "logs";
  60. set { }
  61. }
  62. /// <summary>
  63. /// 写入Info级别的日志
  64. /// </summary>
  65. /// <param name="info"></param>
  66. public static void Info(string info)
  67. {
  68. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(info).ToUpper()} {info}"));
  69. LogInfo log = new LogInfo()
  70. {
  71. LogLevel = LogLevel.Info,
  72. Message = info,
  73. Time = DateTime.Now,
  74. ThreadId = Thread.CurrentThread.ManagedThreadId
  75. };
  76. Event?.Invoke(log);
  77. }
  78. /// <summary>
  79. /// 写入Info级别的日志
  80. /// </summary>
  81. /// <param name="source"></param>
  82. /// <param name="info"></param>
  83. public static void Info(string source, string info)
  84. {
  85. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(info).ToUpper()} {source} {info}"));
  86. LogInfo log = new LogInfo()
  87. {
  88. LogLevel = LogLevel.Info,
  89. Message = info,
  90. Time = DateTime.Now,
  91. ThreadId = Thread.CurrentThread.ManagedThreadId,
  92. Source = source
  93. };
  94. Event?.Invoke(log);
  95. }
  96. /// <summary>
  97. /// 写入Info级别的日志
  98. /// </summary>
  99. /// <param name="source"></param>
  100. /// <param name="info"></param>
  101. public static void Info(Type source, string info)
  102. {
  103. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(info).ToUpper()} {source.FullName} {info}"));
  104. LogInfo log = new LogInfo()
  105. {
  106. LogLevel = LogLevel.Info,
  107. Message = info,
  108. Time = DateTime.Now,
  109. ThreadId = Thread.CurrentThread.ManagedThreadId,
  110. Source = source.FullName
  111. };
  112. Event?.Invoke(log);
  113. }
  114. /// <summary>
  115. /// 写入debug级别日志
  116. /// </summary>
  117. /// <param name="debug">异常对象</param>
  118. public static void Debug(string debug)
  119. {
  120. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(debug).ToUpper()} {debug}"));
  121. LogInfo log = new LogInfo()
  122. {
  123. LogLevel = LogLevel.Debug,
  124. Message = debug,
  125. Time = DateTime.Now,
  126. ThreadId = Thread.CurrentThread.ManagedThreadId
  127. };
  128. Event?.Invoke(log);
  129. }
  130. /// <summary>
  131. /// 写入debug级别日志
  132. /// </summary>
  133. /// <param name="source">异常源的类型</param>
  134. /// <param name="debug">异常对象</param>
  135. public static void Debug(string source, string debug)
  136. {
  137. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(debug).ToUpper()} {source} {debug}"));
  138. LogInfo log = new LogInfo()
  139. {
  140. LogLevel = LogLevel.Debug,
  141. Message = debug,
  142. Time = DateTime.Now,
  143. ThreadId = Thread.CurrentThread.ManagedThreadId,
  144. Source = source
  145. };
  146. Event?.Invoke(log);
  147. }
  148. /// <summary>
  149. /// 写入debug级别日志
  150. /// </summary>
  151. /// <param name="source">异常源的类型</param>
  152. /// <param name="debug">异常对象</param>
  153. public static void Debug(Type source, string debug)
  154. {
  155. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(debug).ToUpper()} {source.FullName} {debug}"));
  156. LogInfo log = new LogInfo()
  157. {
  158. LogLevel = LogLevel.Debug,
  159. Message = debug,
  160. Time = DateTime.Now,
  161. ThreadId = Thread.CurrentThread.ManagedThreadId,
  162. Source = source.FullName
  163. };
  164. Event?.Invoke(log);
  165. }
  166. /// <summary>
  167. /// 写入error级别日志
  168. /// </summary>
  169. /// <param name="error">异常对象</param>
  170. public static void Error(Exception error)
  171. {
  172. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {error.Source} {error.Message}{Environment.NewLine}{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {error.Source} {error.StackTrace}"));
  173. LogInfo log = new LogInfo()
  174. {
  175. LogLevel = LogLevel.Error,
  176. Message = error.Message,
  177. Time = DateTime.Now,
  178. ThreadId = Thread.CurrentThread.ManagedThreadId,
  179. Source = error.Source,
  180. Exception = error,
  181. ExceptionType = error.GetType().Name
  182. };
  183. Event?.Invoke(log);
  184. }
  185. /// <summary>
  186. /// 写入error级别日志
  187. /// </summary>
  188. /// <param name="source">异常源的类型</param>
  189. /// <param name="error">异常对象</param>
  190. public static void Error(Type source, Exception error)
  191. {
  192. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {source.FullName} {error.Message}{Environment.NewLine}{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {source.FullName} {error.StackTrace}"));
  193. LogInfo log = new LogInfo()
  194. {
  195. LogLevel = LogLevel.Error,
  196. Message = error.Message,
  197. Time = DateTime.Now,
  198. ThreadId = Thread.CurrentThread.ManagedThreadId,
  199. Source = source.FullName,
  200. Exception = error,
  201. ExceptionType = error.GetType().Name
  202. };
  203. Event?.Invoke(log);
  204. }
  205. /// <summary>
  206. /// 写入error级别日志
  207. /// </summary>
  208. /// <param name="source">异常源的类型</param>
  209. /// <param name="error">异常信息</param>
  210. public static void Error(Type source, string error)
  211. {
  212. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {source.FullName} {error}"));
  213. LogInfo log = new LogInfo()
  214. {
  215. LogLevel = LogLevel.Error,
  216. Message = error,
  217. Time = DateTime.Now,
  218. ThreadId = Thread.CurrentThread.ManagedThreadId,
  219. Source = source.FullName,
  220. //Exception = error,
  221. ExceptionType = error.GetType().Name
  222. };
  223. Event?.Invoke(log);
  224. }
  225. /// <summary>
  226. /// 写入error级别日志
  227. /// </summary>
  228. /// <param name="source">异常源的类型</param>
  229. /// <param name="error">异常对象</param>
  230. public static void Error(string source, Exception error)
  231. {
  232. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {source} {error.Message}{Environment.NewLine}{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {source} {error.StackTrace}"));
  233. LogInfo log = new LogInfo()
  234. {
  235. LogLevel = LogLevel.Error,
  236. Message = error.Message,
  237. Time = DateTime.Now,
  238. ThreadId = Thread.CurrentThread.ManagedThreadId,
  239. Source = source,
  240. Exception = error,
  241. ExceptionType = error.GetType().Name
  242. };
  243. Event?.Invoke(log);
  244. }
  245. /// <summary>
  246. /// 写入error级别日志
  247. /// </summary>
  248. /// <param name="source">异常源的类型</param>
  249. /// <param name="error">异常信息</param>
  250. public static void Error(string source, string error)
  251. {
  252. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(error).ToUpper()} {source} {error}"));
  253. LogInfo log = new LogInfo()
  254. {
  255. LogLevel = LogLevel.Error,
  256. Message = error,
  257. Time = DateTime.Now,
  258. ThreadId = Thread.CurrentThread.ManagedThreadId,
  259. Source = source,
  260. //Exception = error,
  261. ExceptionType = error.GetType().Name
  262. };
  263. Event?.Invoke(log);
  264. }
  265. /// <summary>
  266. /// 写入fatal级别日志
  267. /// </summary>
  268. /// <param name="fatal">异常对象</param>
  269. public static void Fatal(Exception fatal)
  270. {
  271. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {fatal.Source} {fatal.Message}{Environment.NewLine}{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {fatal.Source} {fatal.StackTrace}"));
  272. LogInfo log = new LogInfo()
  273. {
  274. LogLevel = LogLevel.Fatal,
  275. Message = fatal.Message,
  276. Time = DateTime.Now,
  277. ThreadId = Thread.CurrentThread.ManagedThreadId,
  278. Source = fatal.Source,
  279. Exception = fatal,
  280. ExceptionType = fatal.GetType().Name
  281. };
  282. Event?.Invoke(log);
  283. }
  284. /// <summary>
  285. /// 写入fatal级别日志
  286. /// </summary>
  287. /// <param name="source">异常源的类型</param>
  288. /// <param name="fatal">异常对象</param>
  289. public static void Fatal(Type source, Exception fatal)
  290. {
  291. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {source.FullName} {fatal.Message}{Environment.NewLine}{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {source.FullName} {fatal.StackTrace}"));
  292. LogInfo log = new LogInfo()
  293. {
  294. LogLevel = LogLevel.Fatal,
  295. Message = fatal.Message,
  296. Time = DateTime.Now,
  297. ThreadId = Thread.CurrentThread.ManagedThreadId,
  298. Source = source.FullName,
  299. Exception = fatal,
  300. ExceptionType = fatal.GetType().Name
  301. };
  302. Event?.Invoke(log);
  303. }
  304. /// <summary>
  305. /// 写入fatal级别日志
  306. /// </summary>
  307. /// <param name="source">异常源的类型</param>
  308. /// <param name="fatal">异常对象</param>
  309. public static void Fatal(Type source, string fatal)
  310. {
  311. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {source.FullName} {fatal}"));
  312. LogInfo log = new LogInfo()
  313. {
  314. LogLevel = LogLevel.Fatal,
  315. Message = fatal,
  316. Time = DateTime.Now,
  317. ThreadId = Thread.CurrentThread.ManagedThreadId,
  318. Source = source.FullName,
  319. //Exception = fatal,
  320. ExceptionType = fatal.GetType().Name
  321. };
  322. Event?.Invoke(log);
  323. }
  324. /// <summary>
  325. /// 写入fatal级别日志
  326. /// </summary>
  327. /// <param name="source">异常源的类型</param>
  328. /// <param name="fatal">异常对象</param>
  329. public static void Fatal(string source, Exception fatal)
  330. {
  331. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {source} {fatal.Message}{Environment.NewLine}{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {source} {fatal.StackTrace}"));
  332. LogInfo log = new LogInfo()
  333. {
  334. LogLevel = LogLevel.Fatal,
  335. Message = fatal.Message,
  336. Time = DateTime.Now,
  337. ThreadId = Thread.CurrentThread.ManagedThreadId,
  338. Source = source,
  339. Exception = fatal,
  340. ExceptionType = fatal.GetType().Name
  341. };
  342. Event?.Invoke(log);
  343. }
  344. /// <summary>
  345. /// 写入fatal级别日志
  346. /// </summary>
  347. /// <param name="source">异常源的类型</param>
  348. /// <param name="fatal">异常对象</param>
  349. public static void Fatal(string source, string fatal)
  350. {
  351. LogQueue.Enqueue(new Tuple<string, string>(GetLogPath(), $"{DateTime.Now} [{Thread.CurrentThread.ManagedThreadId}] {nameof(fatal).ToUpper()} {source} {fatal}"));
  352. LogInfo log = new LogInfo()
  353. {
  354. LogLevel = LogLevel.Fatal,
  355. Message = fatal,
  356. Time = DateTime.Now,
  357. ThreadId = Thread.CurrentThread.ManagedThreadId,
  358. Source = source,
  359. ExceptionType = fatal.GetType().Name
  360. };
  361. Event?.Invoke(log);
  362. }
  363. private static string GetLogPath()
  364. {
  365. string newFilePath;
  366. String logDir = string.IsNullOrEmpty(LogDirectory) ? Path.Combine(Environment.CurrentDirectory, "logs") : LogDirectory;
  367. if (!Directory.Exists(logDir))
  368. {
  369. Directory.CreateDirectory(logDir);
  370. }
  371. string extension = ".log";
  372. string fileNameNotExt = DateTime.Now.ToString("yyyyMMdd");
  373. string fileNamePattern = string.Concat(fileNameNotExt, "(*)", extension);
  374. List<string> filePaths = Directory.GetFiles(logDir, fileNamePattern, SearchOption.TopDirectoryOnly).ToList();
  375. if (filePaths.Count > 0)
  376. {
  377. int fileMaxLen = filePaths.Max(d => d.Length);
  378. string lastFilePath = filePaths.Where(d => d.Length == fileMaxLen).OrderByDescending(d => d).FirstOrDefault();
  379. if (new FileInfo(lastFilePath).Length > 1 * 1024 * 1024)
  380. {
  381. string no = new Regex(@"(?is)(?<=\()(.*)(?=\))").Match(Path.GetFileName(lastFilePath)).Value;
  382. bool parse = int.TryParse(no, out int tempno);
  383. string formatno = $"({(parse ? (tempno + 1) : tempno)})";
  384. string newFileName = String.Concat(fileNameNotExt, formatno, extension);
  385. newFilePath = Path.Combine(logDir, newFileName);
  386. }
  387. else
  388. {
  389. newFilePath = lastFilePath;
  390. }
  391. }
  392. else
  393. {
  394. string newFileName = string.Concat(fileNameNotExt, $"({0})", extension);
  395. newFilePath = Path.Combine(logDir, newFileName);
  396. }
  397. return newFilePath;
  398. }
  399. private static void WriteText(string logPath, string logContent)
  400. {
  401. try
  402. {
  403. if (!File.Exists(logPath))
  404. {
  405. File.CreateText(logPath).Close();
  406. }
  407. using (StreamWriter sw = File.AppendText(logPath))
  408. {
  409. sw.Write(logContent);
  410. }
  411. }
  412. catch (Exception)
  413. {
  414. // ignored
  415. }
  416. }
  417. }
  418. }