自己动手丰衣足食 ,C#框架系列----- 日志框架
工作快三年,入园子差不多有三年了,每天茶余饭后,轻敲鼠标偷偷的打开博客园,肆无忌惮的品尝着各种干货,慢慢的从新人变成了老司机,从软香蕉变成了硬橡胶,一篇篇优质的博客让我陶醉其中无法自拔,俗话说三年之痛,七年之痒,在这个我认为不痛不痒的时候,是时候奉献一下自己的积累,开始准备一个简单框架系列主要包括----日志,基于HTTP传输,Windows内部消息通讯,面向对象容器包装等,目前只总结了这么多,我们就废话少数开始第一个框架。
首先做一下简单的需求分析,常见的日志功能需求:
1. 按日期类型记录(天、周、月、年)
2. 按文件大小记录(行数或字节)
3. 按日志等级记录(Unknow、Error、Warning、Info、Debug)
4. 定时清理日志(依据实际大小制定具体天数)
5. 为方便开发调试,针对服务类型开发,同时显示在Console界面(继承TraceListener)
6. 支持多线程同时日志记录
框架准备:轻量级日志框架,我给它起了个名字,就叫做LogLight
枚举类型:
1 public enum EnumLogType 2 { 3 Daily, 4 Weekly, 5 Monthly, 6 Annually 7 } 8 9 public enum EunmMsgType 10 { 11 Unknown, 12 Error, 13 Warning, 14 Info, 15 Debug 16 }
每行内容对象,重写ToString方法,重载构造函数
1 public class LogMsg 2 { 3 public LogMsg(string text, string category) 4 { 5 Category = category; 6 DateTime = DateTime.Now; 7 Text = text; 8 Type = EunmMsgType.Unknown; 9 } 10 11 public LogMsg(string text, EunmMsgType type) 12 { 13 Category = ""; 14 DateTime = DateTime.Now; 15 Text = text; 16 Type = type; 17 } 18 19 public LogMsg(DateTime dt, string text, EunmMsgType type) 20 { 21 Category = ""; 22 DateTime = dt; 23 Text = text; 24 Type = type; 25 } 26 27 public string Text { get; set; } 28 29 public DateTime DateTime { get; set; } 30 31 public string Category { get; set; } 32 33 public EunmMsgType Type { get; set; } 34 35 public override string ToString() 36 { 37 var bulider = new StringBuilder(); 38 bulider.Append(DateTime.ToString("yyyy-MM-dd HH:mm:ss:ff")); 39 bulider.Append(Category); 40 bulider.Append(" "); 41 bulider.Append(Text); 42 return bulider.ToString(); 43 } 44 }
程序入口
1 public class LogLightConsole 2 { 3 public static EunmMsgType LogLevel = EunmMsgType.Debug; 4 5 public static void WriteLog(string sInfo, EunmMsgType type) 6 { 7 if (type <= LogLevel) 8 { 9 Trace.WriteLine(new LogMsg(sInfo, type)); 10 } 11 } 12 }
根据设定条件创建文件,定义文件行条数,定期删除文件,支持多线程操作,防止同时访问队列造成的死锁
1 public class Logger : IDisposable 2 { 3 private static readonly int _keepLogDayCount = 15; 4 5 private static int _lineCount; 6 7 private static readonly int _lineMaxCount = 0x3d090;//2500 8 9 private static Queue<LogMsg> _msgs; 10 11 private static string _path; 12 13 private static bool _state; 14 15 private static DateTime _timeSign; 16 17 private static EnumLogType _type; 18 19 private static StreamWriter _writer; 20 21 private readonly bool _bOutputCount = false; 22 23 private readonly string _format = "yyyy-MM-dd HH:mm:ss:fff"; 24 25 private long _count; 26 27 public Logger(string path, EnumLogType type) 28 { 29 if (_msgs == null) 30 { 31 _state = true; 32 _path = path; 33 _type = type; 34 _msgs = new Queue<LogMsg>(); 35 var thread = new Thread(Work) {IsBackground = true}; 36 thread.Start(); 37 } 38 } 39 40 public void Dispose() 41 { 42 _state = false; 43 } 44 45 private void FileClose() 46 { 47 if (_writer == null) return; 48 _writer.Flush(); 49 _writer.Close(); 50 _writer.Dispose(); 51 _writer = null; 52 } 53 54 private void FileOpen() 55 { 56 _lineCount = 0; 57 _writer = new StreamWriter(GetFileName(), true, Encoding.UTF8); 58 } 59 60 private void FileWrite(LogMsg msg) 61 { 62 try 63 { 64 if (_writer == null) 65 { 66 FileOpen(); 67 } 68 69 if (_writer != null) 70 { 71 if ((DateTime.Now >= _timeSign) || _lineCount > _lineMaxCount) 72 { 73 FileClose(); 74 try 75 { 76 var fileSn = 0; 77 for (var str = _path + GetFilenameBeforeDays(0, _keepLogDayCount); 78 File.Exists(str); 79 str = _path + GetFilenameBeforeDays(fileSn, _keepLogDayCount)) 80 { 81 File.Delete(str); 82 fileSn++; 83 } 84 } 85 catch (Exception exception) 86 { 87 Console.Out.Write(exception); 88 } 89 FileOpen(); 90 } 91 _lineCount++; 92 _writer.Write(msg.DateTime.ToString(_format)); 93 _writer.Write(' '); 94 if (msg.Type == EunmMsgType.Unknown) 95 { 96 _writer.Write(msg.Category); 97 } 98 else 99 { 100 _writer.Write(msg.Type); 101 } 102 _writer.Write(' '); 103 _writer.WriteLine(msg.Text); 104 _writer.Flush(); 105 } 106 } 107 catch (Exception exception) 108 { 109 Console.Out.Write(exception); 110 } 111 } 112 113 private string GetFileName() 114 { 115 var num = 0; 116 var now = DateTime.Now; 117 var format = ""; 118 119 Label_OO0E: 120 switch (_type) 121 { 122 case EnumLogType.Daily: 123 _timeSign = new DateTime(now.Year, now.Month, now.Day); 124 _timeSign = _timeSign.AddDays(1.0); 125 format = "yyyyMMdd"; 126 break; 127 case EnumLogType.Weekly: 128 _timeSign = new DateTime(now.Year, now.Month, now.Day); 129 _timeSign = _timeSign.AddDays(7.0); 130 format = "yyyyMMdd"; 131 break; 132 case EnumLogType.Monthly: 133 _timeSign = new DateTime(now.Year, now.Month, 1); 134 _timeSign = _timeSign.AddMonths(1); 135 format = "yyyyMM"; 136 break; 137 case EnumLogType.Annually: 138 _timeSign = new DateTime(now.Year, 1, 1); 139 _timeSign = _timeSign.AddYears(1); 140 format = "yyyy"; 141 break; 142 } 143 if (File.Exists(_path + now.ToString(format) + string.Format("-{0}.log", num))) 144 { 145 num++; 146 goto Label_OO0E; 147 } 148 return _path + now.ToString(format) + string.Format("-{0}.log", num); 149 } 150 151 private string GetFilenameBeforeDays(int fileSn, int dayCount) 152 { 153 var time = DateTime.Now - TimeSpan.FromDays(dayCount); 154 var format = ""; 155 switch (_type) 156 { 157 case EnumLogType.Daily: 158 format = "yyyyMMdd"; 159 break; 160 case EnumLogType.Weekly: 161 format = "yyyyMMdd"; 162 break; 163 case EnumLogType.Monthly: 164 format = "yyyyMM"; 165 break; 166 case EnumLogType.Annually: 167 format = "yyyy"; 168 break; 169 } 170 return time.ToString(format) + string.Format("-{0}.log", fileSn); 171 } 172 173 private void Work() 174 { 175 Label_0000: 176 while (_msgs.Count > 0) 177 { 178 LogMsg msg = null; 179 lock (_msgs) 180 { 181 if (_msgs.Count > 0) 182 { 183 msg = _msgs.Dequeue(); 184 _count -= 1L; 185 } 186 187 if (msg != null) 188 { 189 if (_bOutputCount) 190 { 191 msg.Text = msg.Text + string.Format("{0}", _count); 192 } 193 FileWrite(msg); 194 } 195 } 196 } 197 198 if (_state) 199 { 200 Thread.Sleep(1); 201 goto Label_0000; 202 } 203 FileClose(); 204 } 205 206 public void Write(LogMsg msg) 207 { 208 if (msg != null) 209 { 210 lock (_msgs) 211 { 212 _count += 1L; 213 _msgs.Enqueue(msg); 214 } 215 } 216 } 217 218 public void Write(string text, EunmMsgType type) 219 { 220 Write(new LogMsg(text, type)); 221 } 222 223 public void Write(string text, string category) 224 { 225 Write(new LogMsg(text, category)); 226 } 227 }
初始化框架类,调用TraceLinster监听日志输入,重写WriteLine方法(非常重要)--->调用logger写方法
public class LogConsole : TraceListener { public static readonly LogConsole InstanceLogConsole = new LogConsole(); private Logger _logger; public void Init(bool UserDebugOutput, bool UseCrForWriteLine, string sPath) { if (!Directory.Exists(sPath)) { Directory.CreateDirectory(sPath); } _logger = new Logger(sPath, EnumLogType.Daily); if (UserDebugOutput) { Debug.Listeners.Add(this); } else { Trace.Listeners.Add(this); } } protected override void Dispose(bool disposing) { if (disposing && (_logger != null)) { _logger.Dispose(); _logger = null; } } public override void WriteLine(object o) { var logMsg = o as LogMsg; if (logMsg != null) { var msg = logMsg; if (_logger != null) { _logger.Write(msg); } Console.WriteLine(msg.ToString()); } } public override void WriteLine(string message, string category) { if (_logger != null) { _logger.Write(message, category); } } public override void WriteLine(string message) { if (_logger != null) { _logger.Write(message, EunmMsgType.Info); } } public override void Write(string message) { if (_logger != null) { _logger.Write(message, EunmMsgType.Info); } } }
测试代码:
class Program { static void Main(string[] args) { var path = AppDomain.CurrentDomain.BaseDirectory + "Log\\"; LogConsole.InstanceLogConsole.Init(true,true,path); Test test = new Test(); test.Work(); Console.ReadLine(); } } public class Test { public void Work() { for (int i = 0; i < 100; i++) { ThreadPool.QueueUserWorkItem(Go, i.ToString()); } } private void Go(object state) { LogLightConsole.WriteLog(state.ToString(), EunmMsgType.Info); } }
希望可以帮到大家,如果你喜欢或者感觉还可以点个赞给作者点动力,如果转载请注明连接。http://www.cnblogs.com/dongqinnanren/p/5964686.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?