Log.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. //************************************************************************
  2. // author: yuzhengyang
  3. // date: 2017.3.29 - 2018.4.27
  4. // desc: 日志功能
  5. // Copyright (c) yuzhengyang. All rights reserved.
  6. //************************************************************************
  7. //R.Log.IsWriteFile = true;
  8. //R.Log.LogLevel = LogLevel.Warning | LogLevel.Debug;
  9. //Log.AllocConsole();
  10. //R.Log.v("this is v 啰嗦");
  11. //R.Log.d("this is d 调试");
  12. //R.Log.i("this is i 重要");
  13. //R.Log.w("this is w 警告");
  14. //R.Log.e("this is e 错误");
  15. using Azylee.Core.DataUtils.CollectionUtils;
  16. using Azylee.Core.DataUtils.StringUtils;
  17. using Azylee.Core.IOUtils.DirUtils;
  18. using Azylee.Core.IOUtils.FileUtils;
  19. using Azylee.Core.IOUtils.TxtUtils;
  20. using Azylee.Core.WindowsUtils.ConsoleUtils;
  21. using System;
  22. using System.Collections.Concurrent;
  23. using System.Collections.Generic;
  24. using System.IO;
  25. using System.Linq;
  26. using System.Runtime.InteropServices;
  27. using System.Threading;
  28. using System.Threading.Tasks;
  29. namespace Azylee.Core.LogUtils.SimpleLogUtils
  30. {
  31. /// <summary>
  32. /// Log 输出工具
  33. ///
  34. /// 说明:
  35. /// 1、Log.AllocConsole();开启控制台
  36. /// 2、Log.FreeConsole();关闭控制台
  37. /// 3、Log.i("information");输出消息
  38. /// </summary>
  39. public class Log
  40. {
  41. #region 基础属性
  42. //输出的 Log 格式
  43. const string LOG_FORMAT = "{0} {1} {2}";
  44. const string TIME_FORMAT = "HH:mm:ss.fff";
  45. const string LOG_PATH = @"azylee.log\log";
  46. private int CACHE_DAYS = 30;//缓存天数
  47. private object LogFileLock = new object();//写日志文件锁
  48. private string LogPath = AppDomain.CurrentDomain.BaseDirectory + LOG_PATH;
  49. private LogLevel ConsoleLogLevel = LogLevel.All;//日志输出到"控制台"等级
  50. private LogLevel FileLogLevel = LogLevel.All;//日志输出到"文件"等级
  51. #endregion
  52. /// <summary>
  53. /// 日志输出回调方法
  54. /// </summary>
  55. /// <param name="type">类型</param>
  56. /// <param name="msg">内容</param>
  57. public delegate void LogEventDelegate(LogType type, string msg);
  58. public LogEventDelegate LogEvent;
  59. private Log() { }
  60. /// <summary>
  61. /// 初始化 Log 工具(不建议使用)
  62. /// </summary>
  63. /// <param name="isWrite">是否写出日志</param>
  64. /// <param name="logLevel"></param>
  65. /// <param name="writeLevel"></param>
  66. [Obsolete("请使用建议的初始化方法",true)]
  67. public Log(bool isWrite, LogLevel logLevel = LogLevel.All, LogLevel writeLevel = LogLevel.All)
  68. {
  69. if (isWrite)
  70. {
  71. //IsWriteFile = true;//已禁用,使用文件输出等级控制
  72. ConsoleLogLevel = logLevel;
  73. FileLogLevel = writeLevel;
  74. }
  75. else
  76. {
  77. ConsoleLogLevel = logLevel;
  78. FileLogLevel = LogLevel.None;
  79. }
  80. }
  81. /// <summary>
  82. /// 初始化 Log 工具(建议)
  83. /// </summary>
  84. /// <param name="console">控制台输出级别</param>
  85. /// <param name="file">文件输出级别</param>
  86. /// <param name="action">日志输出回调</param>
  87. public Log(LogLevel console = LogLevel.All, LogLevel file = LogLevel.All, LogEventDelegate logEvent = null)
  88. {
  89. ConsoleLogLevel = console;
  90. FileLogLevel = file;
  91. if (logEvent != null) LogEvent += logEvent;
  92. }
  93. /// <summary>
  94. /// 设置日志路径
  95. /// </summary>
  96. /// <param name="path"></param>
  97. public void SetLogPath(string path)
  98. {
  99. if (!string.IsNullOrWhiteSpace(path))
  100. {
  101. LogPath = DirTool.Combine(path, LOG_PATH);
  102. }
  103. }
  104. /// <summary>
  105. /// 设置日志缓存天数(默认30天)
  106. /// </summary>
  107. /// <param name="days"></param>
  108. public void SetCacheDays(int days)
  109. {
  110. if (days >= 0) CACHE_DAYS = days;
  111. }
  112. #region Console 开启/关闭 API
  113. /// <summary>
  114. /// 启用系统控制台输出
  115. /// </summary>
  116. /// <returns></returns>
  117. [DllImport("kernel32.dll")]
  118. public static extern Boolean AllocConsole();
  119. /// <summary>
  120. /// 关闭系统控制台
  121. /// </summary>
  122. /// <returns></returns>
  123. [DllImport("kernel32.dll")]
  124. public static extern Boolean FreeConsole();
  125. #endregion
  126. /// <summary>
  127. /// 获取输出颜色
  128. /// </summary>
  129. /// <param name="type">输出类型</param>
  130. /// <returns></returns>
  131. private ConsoleColor GetColor(LogType type)
  132. {
  133. switch (type)
  134. {
  135. case LogType.v: return ConsoleColor.Gray;
  136. case LogType.d: return ConsoleColor.Blue;
  137. case LogType.i: return ConsoleColor.Green;
  138. case LogType.w: return ConsoleColor.Yellow;
  139. case LogType.e: return ConsoleColor.Red;
  140. default: return ConsoleColor.Gray;
  141. }
  142. }
  143. /// <summary>
  144. /// 写出到控制台
  145. /// </summary>
  146. /// <param name="type">类型</param>
  147. /// <param name="message">消息</param>
  148. private void WriteConsole(LogType type, string message)
  149. {
  150. try
  151. {
  152. message = Cons.FormatLine(message); //处理日志信息(换行)
  153. Cons.SetColor(GetColor(type), ConsoleColor.Black);
  154. Console.WriteLine(LOG_FORMAT, DateTime.Now.ToString(TIME_FORMAT), type.ToString(), message);
  155. Cons.ResetColor();
  156. //取消单独线程输出日志文件(单独线程输出日志必然会有延迟)
  157. //if (IsWriteFile) Queue.Enqueue(new LogModel() { Type = type, Message = message, CreateTime = DateTime.Now });
  158. }
  159. catch { }
  160. }
  161. /// <summary>
  162. /// 写出到日志文件
  163. /// </summary>
  164. /// <param name="log"></param>
  165. private void WriteFile(LogModel log)
  166. {
  167. lock (LogFileLock)
  168. {
  169. //设置日志目录和日志文件
  170. string filePath = LogPath;
  171. //string filePath = GetFilePath(log.Type);//根据分类分配目录
  172. string file = DirTool.Combine(filePath, DateTime.Now.ToString("yyyy-MM-dd") + ".txt");
  173. //创建日志目录
  174. DirTool.Create(filePath);
  175. //处理日志信息(换行)
  176. log.Message = Cons.FormatLine(log.Message);
  177. //写出日志
  178. TxtTool.Append(
  179. file,
  180. string.Format(LOG_FORMAT,
  181. log.CreateTime.ToString(TIME_FORMAT),
  182. log.Type.ToString(),
  183. log.Message));
  184. Cleaner(log.Type);
  185. }
  186. }
  187. /// <summary>
  188. /// 根据分类分配目录
  189. /// </summary>
  190. /// <param name="type"></param>
  191. /// <returns></returns>
  192. //private string GetFilePath(LogType type)
  193. //{
  194. // string filePath = LogPath;
  195. // switch (type)
  196. // {
  197. // case LogType.d: filePath = DirTool.Combine(LogPath, "debug"); break;
  198. // case LogType.i: filePath = DirTool.Combine(LogPath, "information"); break;
  199. // case LogType.e: filePath = DirTool.Combine(LogPath, "error"); break;
  200. // case LogType.w: filePath = DirTool.Combine(LogPath, "warning"); break;
  201. // case LogType.v: filePath = DirTool.Combine(LogPath, "verbose"); break;
  202. // }
  203. // return filePath;
  204. //}
  205. /// <summary>
  206. /// 清理过多的日志文件
  207. /// </summary>
  208. private void Cleaner(LogType type)
  209. {
  210. List<string> files = FileTool.GetFile(LogPath);
  211. //List<string> files = FileTool.GetFile(GetFilePath(type));//根据分类分配目录
  212. if (ListTool.HasElements(files))
  213. {
  214. files.ForEach(f =>
  215. {
  216. try
  217. {
  218. string filename = Path.GetFileNameWithoutExtension(f);
  219. if (filename.Length == 10)
  220. {
  221. DateTime date = DateTime.Parse(filename);
  222. if (date < DateTime.Now.AddDays(-CACHE_DAYS - 1)) FileTool.Delete(f);
  223. }
  224. else { FileTool.Delete(f); }
  225. }
  226. catch { FileTool.Delete(f); }
  227. });
  228. }
  229. }
  230. #region 分类详细输出
  231. #region 因大小写命名规范冲突,将次类方法标记为弃用
  232. /// <summary>
  233. /// 输出 verbose (啰嗦信息)
  234. /// </summary>
  235. /// <param name="msg">消息</param>
  236. [Obsolete]
  237. public void v<T>(T msg)
  238. {
  239. V(msg);
  240. }
  241. /// <summary>
  242. /// 输出 Debug (调试信息)
  243. /// </summary>
  244. /// <param name="msg">消息</param>
  245. [Obsolete]
  246. public void d<T>(T msg)
  247. {
  248. D(msg);
  249. }
  250. /// <summary>
  251. /// 输出 Information (重要信息)
  252. /// </summary>
  253. /// <param name="msg">消息</param>
  254. [Obsolete]
  255. public void i<T>(T msg)
  256. {
  257. I(msg);
  258. }
  259. /// <summary>
  260. /// 输出 Warning (警告信息)
  261. /// </summary>
  262. /// <param name="msg">消息</param>
  263. [Obsolete]
  264. public void w<T>(T msg)
  265. {
  266. W(msg);
  267. }
  268. /// <summary>
  269. /// 输出 Error (错误信息)
  270. /// </summary>
  271. /// <param name="msg">消息</param>
  272. [Obsolete]
  273. public void e<T>(T msg)
  274. {
  275. E(msg);
  276. }
  277. #endregion
  278. /// <summary>
  279. /// 输出 verbose (啰嗦信息)
  280. /// </summary>
  281. /// <param name="msg">消息</param>
  282. public void V<T>(T msg)
  283. {
  284. if ((ConsoleLogLevel & LogLevel.Verbose) == LogLevel.Verbose)
  285. WriteConsole(LogType.v, msg?.ToString());
  286. if ((FileLogLevel & LogLevel.Verbose) == LogLevel.Verbose)
  287. WriteFile(new LogModel() { Type = LogType.v, Message = msg?.ToString(), CreateTime = DateTime.Now });
  288. try { LogEvent?.Invoke(LogType.v, msg?.ToString()); } catch { }
  289. }
  290. /// <summary>
  291. /// 输出 Debug (调试信息)
  292. /// </summary>
  293. /// <param name="msg">消息</param>
  294. public void D<T>(T msg)
  295. {
  296. if ((ConsoleLogLevel & LogLevel.Debug) == LogLevel.Debug)
  297. WriteConsole(LogType.d, msg?.ToString());
  298. if ((FileLogLevel & LogLevel.Debug) == LogLevel.Debug)
  299. WriteFile(new LogModel() { Type = LogType.d, Message = msg?.ToString(), CreateTime = DateTime.Now });
  300. try { LogEvent?.Invoke(LogType.d, msg?.ToString()); } catch { }
  301. }
  302. /// <summary>
  303. /// 输出 Information (重要信息)
  304. /// </summary>
  305. /// <param name="msg">消息</param>
  306. public void I<T>(T msg)
  307. {
  308. if ((ConsoleLogLevel & LogLevel.Information) == LogLevel.Information)
  309. WriteConsole(LogType.i, msg?.ToString());
  310. if ((FileLogLevel & LogLevel.Information) == LogLevel.Information)
  311. WriteFile(new LogModel() { Type = LogType.i, Message = msg?.ToString(), CreateTime = DateTime.Now });
  312. try { LogEvent?.Invoke(LogType.i, msg?.ToString()); } catch { }
  313. }
  314. /// <summary>
  315. /// 输出 Warning (警告信息)
  316. /// </summary>
  317. /// <param name="msg">消息</param>
  318. public void W<T>(T msg)
  319. {
  320. if ((ConsoleLogLevel & LogLevel.Warning) == LogLevel.Warning)
  321. WriteConsole(LogType.w, msg?.ToString());
  322. if ((FileLogLevel & LogLevel.Warning) == LogLevel.Warning)
  323. WriteFile(new LogModel() { Type = LogType.w, Message = msg?.ToString(), CreateTime = DateTime.Now });
  324. try { LogEvent?.Invoke(LogType.w, msg?.ToString()); } catch { }
  325. }
  326. /// <summary>
  327. /// 输出 Error (错误信息)
  328. /// </summary>
  329. /// <param name="msg">消息</param>
  330. public void E<T>(T msg)
  331. {
  332. if ((ConsoleLogLevel & LogLevel.Error) == LogLevel.Error)
  333. WriteConsole(LogType.e, msg?.ToString());
  334. if ((FileLogLevel & LogLevel.Error) == LogLevel.Error)
  335. WriteFile(new LogModel() { Type = LogType.e, Message = msg?.ToString(), CreateTime = DateTime.Now });
  336. try { LogEvent?.Invoke(LogType.e, msg?.ToString()); } catch { }
  337. }
  338. #endregion
  339. }
  340. }