Log.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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";
  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]
  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 = GetFilePath(log.Type);
  171. string file = DirTool.Combine(filePath, DateTime.Now.ToString("yyyy-MM-dd") + ".txt");
  172. //创建日志目录
  173. DirTool.Create(filePath);
  174. //处理日志信息(换行)
  175. log.Message = Cons.FormatLine(log.Message);
  176. //写出日志
  177. TxtTool.Append(
  178. file,
  179. string.Format(LOG_FORMAT,
  180. log.CreateTime.ToString(TIME_FORMAT),
  181. log.Type.ToString(),
  182. log.Message));
  183. Cleaner(log.Type);
  184. }
  185. }
  186. /// <summary>
  187. /// 根据分类分配目录
  188. /// </summary>
  189. /// <param name="type"></param>
  190. /// <returns></returns>
  191. private string GetFilePath(LogType type)
  192. {
  193. string filePath = LogPath;
  194. switch (type)
  195. {
  196. case LogType.d: filePath = DirTool.Combine(LogPath, "debug"); break;
  197. case LogType.i: filePath = DirTool.Combine(LogPath, "information"); break;
  198. case LogType.e: filePath = DirTool.Combine(LogPath, "error"); break;
  199. case LogType.w: filePath = DirTool.Combine(LogPath, "warning"); break;
  200. case LogType.v: filePath = DirTool.Combine(LogPath, "verbose"); break;
  201. }
  202. return filePath;
  203. }
  204. /// <summary>
  205. /// 清理过多的日志文件
  206. /// </summary>
  207. private void Cleaner(LogType type)
  208. {
  209. List<string> files = FileTool.GetFile(GetFilePath(type));
  210. if (ListTool.HasElements(files))
  211. {
  212. files.ForEach(f =>
  213. {
  214. try
  215. {
  216. string filename = Path.GetFileNameWithoutExtension(f);
  217. if (filename.Length == 10)
  218. {
  219. DateTime date = DateTime.Parse(filename);
  220. if (date < DateTime.Now.AddDays(-CACHE_DAYS - 1)) FileTool.Delete(f);
  221. }
  222. else { FileTool.Delete(f); }
  223. }
  224. catch { FileTool.Delete(f); }
  225. });
  226. }
  227. }
  228. #region 分类详细输出
  229. #region 因大小写命名规范冲突,将次类方法标记为弃用
  230. /// <summary>
  231. /// 输出 verbose (啰嗦信息)
  232. /// </summary>
  233. /// <param name="msg">消息</param>
  234. [Obsolete]
  235. public void v<T>(T msg)
  236. {
  237. V(msg);
  238. }
  239. /// <summary>
  240. /// 输出 Debug (调试信息)
  241. /// </summary>
  242. /// <param name="msg">消息</param>
  243. [Obsolete]
  244. public void d<T>(T msg)
  245. {
  246. D(msg);
  247. }
  248. /// <summary>
  249. /// 输出 Information (重要信息)
  250. /// </summary>
  251. /// <param name="msg">消息</param>
  252. [Obsolete]
  253. public void i<T>(T msg)
  254. {
  255. I(msg);
  256. }
  257. /// <summary>
  258. /// 输出 Warning (警告信息)
  259. /// </summary>
  260. /// <param name="msg">消息</param>
  261. [Obsolete]
  262. public void w<T>(T msg)
  263. {
  264. W(msg);
  265. }
  266. /// <summary>
  267. /// 输出 Error (错误信息)
  268. /// </summary>
  269. /// <param name="msg">消息</param>
  270. [Obsolete]
  271. public void e<T>(T msg)
  272. {
  273. E(msg);
  274. }
  275. #endregion
  276. /// <summary>
  277. /// 输出 verbose (啰嗦信息)
  278. /// </summary>
  279. /// <param name="msg">消息</param>
  280. public void V<T>(T msg)
  281. {
  282. if ((ConsoleLogLevel & LogLevel.Verbose) == LogLevel.Verbose)
  283. WriteConsole(LogType.v, msg?.ToString());
  284. if ((FileLogLevel & LogLevel.Verbose) == LogLevel.Verbose)
  285. WriteFile(new LogModel() { Type = LogType.v, Message = msg?.ToString(), CreateTime = DateTime.Now });
  286. try { LogEvent(LogType.v, msg?.ToString()); } catch { }
  287. }
  288. /// <summary>
  289. /// 输出 Debug (调试信息)
  290. /// </summary>
  291. /// <param name="msg">消息</param>
  292. public void D<T>(T msg)
  293. {
  294. if ((ConsoleLogLevel & LogLevel.Debug) == LogLevel.Debug)
  295. WriteConsole(LogType.d, msg?.ToString());
  296. if ((FileLogLevel & LogLevel.Debug) == LogLevel.Debug)
  297. WriteFile(new LogModel() { Type = LogType.d, Message = msg?.ToString(), CreateTime = DateTime.Now });
  298. try { LogEvent(LogType.d, msg?.ToString()); } catch { }
  299. }
  300. /// <summary>
  301. /// 输出 Information (重要信息)
  302. /// </summary>
  303. /// <param name="msg">消息</param>
  304. public void I<T>(T msg)
  305. {
  306. if ((ConsoleLogLevel & LogLevel.Information) == LogLevel.Information)
  307. WriteConsole(LogType.i, msg?.ToString());
  308. if ((FileLogLevel & LogLevel.Information) == LogLevel.Information)
  309. WriteFile(new LogModel() { Type = LogType.i, Message = msg?.ToString(), CreateTime = DateTime.Now });
  310. try { LogEvent(LogType.i, msg?.ToString()); } catch { }
  311. }
  312. /// <summary>
  313. /// 输出 Warning (警告信息)
  314. /// </summary>
  315. /// <param name="msg">消息</param>
  316. public void W<T>(T msg)
  317. {
  318. if ((ConsoleLogLevel & LogLevel.Warning) == LogLevel.Warning)
  319. WriteConsole(LogType.w, msg?.ToString());
  320. if ((FileLogLevel & LogLevel.Warning) == LogLevel.Warning)
  321. WriteFile(new LogModel() { Type = LogType.w, Message = msg?.ToString(), CreateTime = DateTime.Now });
  322. try { LogEvent(LogType.w, msg?.ToString()); } catch { }
  323. }
  324. /// <summary>
  325. /// 输出 Error (错误信息)
  326. /// </summary>
  327. /// <param name="msg">消息</param>
  328. public void E<T>(T msg)
  329. {
  330. if ((ConsoleLogLevel & LogLevel.Error) == LogLevel.Error)
  331. WriteConsole(LogType.e, msg?.ToString());
  332. if ((FileLogLevel & LogLevel.Error) == LogLevel.Error)
  333. WriteFile(new LogModel() { Type = LogType.e, Message = msg?.ToString(), CreateTime = DateTime.Now });
  334. try { LogEvent(LogType.e, msg?.ToString()); } catch { }
  335. }
  336. #endregion
  337. }
  338. }