Log.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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. private Log() { }
  53. /// <summary>
  54. /// 初始化 Log 工具(不建议使用)
  55. /// </summary>
  56. /// <param name="isWrite">是否写出日志</param>
  57. /// <param name="logLevel"></param>
  58. /// <param name="writeLevel"></param>
  59. [Obsolete]
  60. public Log(bool isWrite, LogLevel logLevel = LogLevel.All, LogLevel writeLevel = LogLevel.All)
  61. {
  62. if (isWrite)
  63. {
  64. //IsWriteFile = true;//已禁用,使用文件输出等级控制
  65. ConsoleLogLevel = logLevel;
  66. FileLogLevel = writeLevel;
  67. }
  68. else
  69. {
  70. ConsoleLogLevel = logLevel;
  71. FileLogLevel = LogLevel.None;
  72. }
  73. }
  74. /// <summary>
  75. /// 初始化 Log 工具
  76. /// </summary>
  77. /// <param name="console">控制台输出级别</param>
  78. /// <param name="file">文件输出级别</param>
  79. public Log(LogLevel console = LogLevel.All, LogLevel file = LogLevel.All)
  80. {
  81. ConsoleLogLevel = console;
  82. FileLogLevel = file;
  83. }
  84. /// <summary>
  85. /// 设置日志路径
  86. /// </summary>
  87. /// <param name="path"></param>
  88. public void SetLogPath(string path)
  89. {
  90. if (!string.IsNullOrWhiteSpace(path))
  91. {
  92. LogPath = DirTool.Combine(path, LOG_PATH);
  93. }
  94. }
  95. /// <summary>
  96. /// 设置日志缓存天数(默认30天)
  97. /// </summary>
  98. /// <param name="days"></param>
  99. public void SetCacheDays(int days)
  100. {
  101. if (days >= 0) CACHE_DAYS = days;
  102. }
  103. #region Console 开启/关闭 API
  104. /// <summary>
  105. /// 启用系统控制台输出
  106. /// </summary>
  107. /// <returns></returns>
  108. [DllImport("kernel32.dll")]
  109. public static extern Boolean AllocConsole();
  110. /// <summary>
  111. /// 关闭系统控制台
  112. /// </summary>
  113. /// <returns></returns>
  114. [DllImport("kernel32.dll")]
  115. public static extern Boolean FreeConsole();
  116. #endregion
  117. /// <summary>
  118. /// 获取输出颜色
  119. /// </summary>
  120. /// <param name="type">输出类型</param>
  121. /// <returns></returns>
  122. private ConsoleColor GetColor(LogType type)
  123. {
  124. switch (type)
  125. {
  126. case LogType.v: return ConsoleColor.Gray;
  127. case LogType.d: return ConsoleColor.Blue;
  128. case LogType.i: return ConsoleColor.Green;
  129. case LogType.w: return ConsoleColor.Yellow;
  130. case LogType.e: return ConsoleColor.Red;
  131. default: return ConsoleColor.Gray;
  132. }
  133. }
  134. /// <summary>
  135. /// 写出到控制台
  136. /// </summary>
  137. /// <param name="type">类型</param>
  138. /// <param name="message">消息</param>
  139. private void WriteConsole(LogType type, string message)
  140. {
  141. try
  142. {
  143. message = Cons.FormatLine(message); //处理日志信息(换行)
  144. Cons.SetColor(GetColor(type), ConsoleColor.Black);
  145. Console.WriteLine(LOG_FORMAT, DateTime.Now.ToString(TIME_FORMAT), type.ToString(), message);
  146. Cons.ResetColor();
  147. //取消单独线程输出日志文件(单独线程输出日志必然会有延迟)
  148. //if (IsWriteFile) Queue.Enqueue(new LogModel() { Type = type, Message = message, CreateTime = DateTime.Now });
  149. }
  150. catch { }
  151. }
  152. /// <summary>
  153. /// 写出到日志文件
  154. /// </summary>
  155. /// <param name="log"></param>
  156. private void WriteFile(LogModel log)
  157. {
  158. lock (LogFileLock)
  159. {
  160. //设置日志目录和日志文件
  161. string filePath = GetFilePath(log.Type);
  162. string file = DirTool.Combine(filePath, DateTime.Now.ToString("yyyy-MM-dd") + ".txt");
  163. //创建日志目录
  164. DirTool.Create(filePath);
  165. //处理日志信息(换行)
  166. log.Message = Cons.FormatLine(log.Message);
  167. //写出日志
  168. TxtTool.Append(
  169. file,
  170. string.Format(LOG_FORMAT,
  171. log.CreateTime.ToString(TIME_FORMAT),
  172. log.Type.ToString(),
  173. log.Message));
  174. Cleaner(log.Type);
  175. }
  176. }
  177. /// <summary>
  178. /// 根据分类分配目录
  179. /// </summary>
  180. /// <param name="type"></param>
  181. /// <returns></returns>
  182. private string GetFilePath(LogType type)
  183. {
  184. string filePath = LogPath;
  185. switch (type)
  186. {
  187. case LogType.d: filePath = DirTool.Combine(LogPath, "debug"); break;
  188. case LogType.i: filePath = DirTool.Combine(LogPath, "information"); break;
  189. case LogType.e: filePath = DirTool.Combine(LogPath, "error"); break;
  190. case LogType.w: filePath = DirTool.Combine(LogPath, "warning"); break;
  191. case LogType.v: filePath = DirTool.Combine(LogPath, "verbose"); break;
  192. }
  193. return filePath;
  194. }
  195. /// <summary>
  196. /// 清理过多的日志文件
  197. /// </summary>
  198. private void Cleaner(LogType type)
  199. {
  200. List<string> files = FileTool.GetFile(GetFilePath(type));
  201. if (ListTool.HasElements(files))
  202. {
  203. files.ForEach(f =>
  204. {
  205. try
  206. {
  207. string filename = Path.GetFileNameWithoutExtension(f);
  208. if (filename.Length == 10)
  209. {
  210. DateTime date = DateTime.Parse(filename);
  211. if (date < DateTime.Now.AddDays(-CACHE_DAYS - 1)) FileTool.Delete(f);
  212. }
  213. else { FileTool.Delete(f); }
  214. }
  215. catch { FileTool.Delete(f); }
  216. });
  217. }
  218. }
  219. #region 分类详细输出
  220. #region 因大小写命名规范冲突,将次类方法标记为弃用
  221. /// <summary>
  222. /// 输出 verbose (啰嗦信息)
  223. /// </summary>
  224. /// <param name="msg">消息</param>
  225. [Obsolete]
  226. public void v<T>(T msg)
  227. {
  228. V(msg);
  229. }
  230. /// <summary>
  231. /// 输出 Debug (调试信息)
  232. /// </summary>
  233. /// <param name="msg">消息</param>
  234. [Obsolete]
  235. public void d<T>(T msg)
  236. {
  237. D(msg);
  238. }
  239. /// <summary>
  240. /// 输出 Information (重要信息)
  241. /// </summary>
  242. /// <param name="msg">消息</param>
  243. [Obsolete]
  244. public void i<T>(T msg)
  245. {
  246. I(msg);
  247. }
  248. /// <summary>
  249. /// 输出 Warning (警告信息)
  250. /// </summary>
  251. /// <param name="msg">消息</param>
  252. [Obsolete]
  253. public void w<T>(T msg)
  254. {
  255. W(msg);
  256. }
  257. /// <summary>
  258. /// 输出 Error (错误信息)
  259. /// </summary>
  260. /// <param name="msg">消息</param>
  261. [Obsolete]
  262. public void e<T>(T msg)
  263. {
  264. E(msg);
  265. }
  266. #endregion
  267. /// <summary>
  268. /// 输出 verbose (啰嗦信息)
  269. /// </summary>
  270. /// <param name="msg">消息</param>
  271. public void V<T>(T msg)
  272. {
  273. if ((ConsoleLogLevel & LogLevel.Verbose) == LogLevel.Verbose)
  274. WriteConsole(LogType.v, msg?.ToString());
  275. if ((FileLogLevel & LogLevel.Verbose) == LogLevel.Verbose)
  276. WriteFile(new LogModel() { Type = LogType.v, Message = msg?.ToString(), CreateTime = DateTime.Now });
  277. }
  278. /// <summary>
  279. /// 输出 Debug (调试信息)
  280. /// </summary>
  281. /// <param name="msg">消息</param>
  282. public void D<T>(T msg)
  283. {
  284. if ((ConsoleLogLevel & LogLevel.Debug) == LogLevel.Debug)
  285. WriteConsole(LogType.d, msg?.ToString());
  286. if ((FileLogLevel & LogLevel.Debug) == LogLevel.Debug)
  287. WriteFile(new LogModel() { Type = LogType.d, Message = msg?.ToString(), CreateTime = DateTime.Now });
  288. }
  289. /// <summary>
  290. /// 输出 Information (重要信息)
  291. /// </summary>
  292. /// <param name="msg">消息</param>
  293. public void I<T>(T msg)
  294. {
  295. if ((ConsoleLogLevel & LogLevel.Information) == LogLevel.Information)
  296. WriteConsole(LogType.i, msg?.ToString());
  297. if ((FileLogLevel & LogLevel.Information) == LogLevel.Information)
  298. WriteFile(new LogModel() { Type = LogType.i, Message = msg?.ToString(), CreateTime = DateTime.Now });
  299. }
  300. /// <summary>
  301. /// 输出 Warning (警告信息)
  302. /// </summary>
  303. /// <param name="msg">消息</param>
  304. public void W<T>(T msg)
  305. {
  306. if ((ConsoleLogLevel & LogLevel.Warning) == LogLevel.Warning)
  307. WriteConsole(LogType.w, msg?.ToString());
  308. if ((FileLogLevel & LogLevel.Warning) == LogLevel.Warning)
  309. WriteFile(new LogModel() { Type = LogType.w, Message = msg?.ToString(), CreateTime = DateTime.Now });
  310. }
  311. /// <summary>
  312. /// 输出 Error (错误信息)
  313. /// </summary>
  314. /// <param name="msg">消息</param>
  315. public void E<T>(T msg)
  316. {
  317. if ((ConsoleLogLevel & LogLevel.Error) == LogLevel.Error)
  318. WriteConsole(LogType.e, msg?.ToString());
  319. if ((FileLogLevel & LogLevel.Error) == LogLevel.Error)
  320. WriteFile(new LogModel() { Type = LogType.e, Message = msg?.ToString(), CreateTime = DateTime.Now });
  321. }
  322. #endregion
  323. }
  324. }