当前位置: 移动技术网 > IT编程>开发语言>.net > [原创]分享一个轻量级日志类

[原创]分享一个轻量级日志类

2019年05月28日  | 移动技术网IT编程  | 我要评论

柳编工艺品批发市场,何熠飞,郑州纸杯

日常开发中,常常会在程序部署到生产环境后发现有些问题,但无法直接调试,这就需要用到日志,本来想找一些开源的完善的日志类来实现,但试了几个都感觉太重。于是意识到一个问题,懒是偷不得的,只好撸起袖子,自己写一个。这个日志类是基于订阅模式的,而且是线程安全的,现在分享给大家,希望能给大家带来帮助。

闲话不多说,直接上代码。代码有两个实现版本(java与c#),这里放出的是c#。

一共用到三个类:jzglogs.cs主类,logbuffer.cs日志缓冲类,loginfo是用于日志缓冲中做记录的实体类,基本原理是把所有待写入的日志写到缓冲中,然后一个线程轮询缓冲,发现有需要写入的数据,就写入,否则就下一次。

no.1  jzglogs.cs

  1 using system;
  2 using system.collections.generic;
  3 using system.linq;
  4 using system.text;
  5 using system.io;
  6 using system.text.regularexpressions;
  7 using system.threading;
  8 
  9 /****************************************************************************
 10 单例类     :日志记录类
 11 作者       :贾渊
 12 版本       :1.5
 13 上一版本   :1.4
 14 更新日志   :
 15     2018-07-06  创建
 16     2018-08-06  增加了属性logmode,用于改变记录日志的方式
 17     2018-12-26  修改了读写文件的线程锁定方式
 18     2019-01-14  改进日志写入的时的对象锁定方式
 19     2019-01-15  改进了日志写入的方式为多线程队列写入,操你大爷的lock,又慢又烂
 20 ****************************************************************************/
 21 
 22 namespace jzg.logs
 23 {
 24     /// <summary>
 25     /// 日志记录类
 26     /// </summary>
 27     public class jzglogs : idisposable
 28     {
 29         /// <summary>
 30         /// 记录类型:消息
 31         /// </summary>
 32         public const string logtype_info = "info";
 33         /// <summary>
 34         /// 记录类型:错误
 35         /// </summary>
 36         public const string logtype_error = "error";
 37 
 38         //线程锁
 39         private static readonly object locker = new object();
 40 
 41         //日志记录路径
 42         private string logpath = "";
 43 
 44         //日志记录方式
 45         private logmode logmode = logmode.lmall;
 46 
 47         /// <summary>
 48         /// 日志记录方式,从枚举logmode中取值
 49         /// </summary>
 50         public logmode logmode
 51         {
 52             get
 53             {
 54                 return logmode;
 55             }
 56 
 57             set
 58             {
 59                 logmode = value;
 60             }
 61         }
 62 
 63         /// <summary>
 64         /// 私有构造方法
 65         /// </summary>
 66         private jzglogs()
 67         {
 68             //默认为全记录
 69             logmode = logmode.lmall;
 70             //创建线程安全的消息队列
 71             logqueue = new logbuffer();
 72             //开启写入线程
 73             writethread = new thread(flushbuffer);
 74             writethread.isbackground = true;
 75             writethread.start();
 76         }
 77 
 78         private logbuffer logqueue;
 79 
 80         //是否停止处理缓存
 81         private volatile bool _flushalive = true;
 82 
 83         private void flushbuffer()
 84         {
 85             while (_flushalive)
 86             {
 87                 loginfo loginfo = logqueue.readbuffer();
 88                 if (loginfo == null)
 89                 {
 90                     //如果没有要写入的内容则延时100毫秒再看
 91                     thread.sleep(200);
 92                 }
 93                 else
 94                 {
 95                     try
 96                     {
 97                         using (filestream fs = new filestream(loginfo.logfile, filemode.openorcreate, fileaccess.write, fileshare.readwrite))
 98                         {
 99                             using (streamwriter sw = new streamwriter(fs))
100                             {
101                                 sw.basestream.seek(0, seekorigin.end);
102                                 sw.writeline(loginfo.logcontent);
103                                 sw.flush();
104                             }
105                         }
106                     }
107                     catch (exception)
108                     {
109                         //出错就不管丫的
110                     }
111                 }
112             }
113         }
114 
115         private static jzglogs instance = null;
116 
117         /// <summary>
118         /// 获取或设置日志记录路径
119         /// </summary>
120         public string logpath
121         {
122             get
123             {
124                 //补齐路径结束的\符号
125                 if (!logpath.endswith("\\"))
126                 {
127                     logpath += "\\";
128                 }
129                 return logpath;
130             }
131 
132             set
133             {
134                 logpath = value;
135             }
136         }
137 
138 
139         /// <summary>
140         /// 静态方法:获取实例(单例模式)
141         /// </summary>
142         /// <returns></returns>
143         [obsolete("该方法已过时,推荐使用静态属性instance代替")]
144         public static jzglogs getinstance()
145         {
146             //2019-01-14 改为二次验证单例模式,提高了性能和并发安全性
147             if (instance == null)
148             {
149                 lock (locker)
150                 {
151                     if (instance == null)
152                     {
153                         var tmp = new jzglogs();
154                         thread.memorybarrier();
155                         instance = tmp;
156                     }
157                 }
158             }
159 
160             return instance;
161         }
162 
163         /// <summary>
164         /// 静态属性:单例实例
165         /// </summary>
166         public static jzglogs instance
167         {
168             get
169             {
170                 //2019-01-14 改为二次验证单例模式,提高了性能和并发安全性
171                 if (instance == null)
172                 {
173                     lock (locker)
174                     {
175                         if (instance == null)
176                         {
177                             var tmp = new jzglogs();
178                             thread.memorybarrier();
179                             instance = tmp;
180                         }
181                     }
182                 }
183 
184                 return instance;
185             }
186         }
187 
188         //写入线程
189         private thread writethread = null;
190 
191         /// <summary>
192         /// 记录日志
193         /// </summary>
194         /// <param name="subpath">子路径</param>
195         /// <param name="logtype">记录类型</param>
196         /// <param name="tag">模块标识</param>
197         /// <param name="logcontent">记录内容</param>
198         public void log(string subpath, string logtype, string tag, string logcontent)
199         {
200             //如果未设置路径则抛出错误
201             if (string.isnullorempty(logpath))
202             {
203                 throw new exception("logpath not set");
204             }
205 
206             //判断记录模式
207             bool canlog = (logmode == logmode.lmall) || (logmode == logmode.lmerror && logtype == logtype_error) || (logmode == logmode.lminfo && logtype == logtype_info);
208             //如果不需要记录则直接退出
209             if (!canlog)
210             {
211                 return;
212             }
213 
214             //当前时间
215             datetime logtime = datetime.now;
216             //记录时间的字符串
217             string logtimestr = logtime.tostring("yyyy/mm/dd hh:mm:ss:fff");
218             //文件名
219             string filename = string.format("log_{0}.log", datetime.now.tostring("yyyymmdd"));
220 
221             //计算子路径
222             string fulllogpath = logpath + subpath;
223             //补齐路径结尾\符号
224             if (!fulllogpath.endswith("\\") && !string.isnullorempty(fulllogpath))
225             {
226                 fulllogpath += "\\";
227             }
228             //自动创建路径
229             directoryinfo di = new directoryinfo(fulllogpath);
230             if (!di.exists)
231             {
232                 di.create();
233             }
234 
235             //文件完整路径
236             string fullfilepath = fulllogpath + filename;
237             //记录格式模板
238             string contenttemplate = "【{0}】 【{1}】 【{2}】 【记录】{3}";
239             logcontent = regex.replace(logcontent, @"[\n\r]", "");//去掉换行符
240                                                                   //计算日志内容
241             string linecontent = string.format(contenttemplate, logtype, logtimestr, tag, logcontent);
242 
243             loginfo loginfo = new loginfo()
244             {
245                 logfile = fullfilepath,
246                 logcontent = linecontent
247             };
248 
249             //写入缓存
250             logqueue.writebuffer(loginfo);
251         }
252 
253         /// <summary>
254         /// 记录日志
255         /// </summary>
256         /// <param name="logtype">记录类型</param>
257         /// <param name="tag">模块标识</param>
258         /// <param name="logcontent">记录内容</param>
259         public void log(string logtype, string tag, string logcontent)
260         {
261             log("", logtype, tag, logcontent);
262         }
263 
264         /// <summary>
265         /// 释放资源
266         /// </summary>
267         public void dispose()
268         {
269             _flushalive = false;
270         }
271     }
272 
273     /// <summary>
274     /// 枚举:日志记录方式
275     /// </summary>
276     public enum logmode
277     {
278         /// <summary>
279         /// 不记录
280         /// </summary>
281         lmnone = 0,
282         /// <summary>
283         /// 全记录
284         /// </summary>
285         lmall = 1,
286         /// <summary>
287         /// 只记录info类型
288         /// </summary>
289         lminfo = 2,
290         /// <summary>
291         /// 只记录error类型
292         /// </summary>
293         lmerror = 3
294     }
295 }

no.2  logbuffer.cs

 1 using system;
 2 using system.collections.generic;
 3 using system.linq;
 4 using system.text;
 5 using system.collections.concurrent;
 6 
 7 namespace jzg.logs
 8 {
 9     /// <summary>
10     /// 日志写入缓冲
11     /// </summary>
12     public class logbuffer
13     {
14         private concurrentqueue<loginfo> logs;
15 
16         /// <summary>
17         /// 构造方法
18         /// </summary>
19         public logbuffer()
20         {
21             logs = new concurrentqueue<loginfo>();
22         }
23 
24         /// <summary>
25         /// 把日志加入写入队列末端
26         /// </summary>
27         /// <param name="loginfo">要写入的日志对象</param>
28         public void writebuffer(loginfo loginfo)
29         {
30             logs.enqueue(loginfo);
31         }
32 
33         /// <summary>
34         /// 从日志中取出开头的一条
35         /// </summary>
36         /// <returns>为null表示队列为空了</returns>
37         public loginfo readbuffer()
38         {
39             loginfo loginfo = null;
40 
41             if (!logs.trydequeue(out loginfo))
42                 return null;
43 
44             return loginfo;
45         }
46         
47         /// <summary>
48         /// 队列中的数量
49         /// </summary>
50         /// <returns></returns>
51         public int count()
52         {
53             return logs.count;
54         }
55     }
56 }

no.3  loginfo.cs

 1 using system;
 2 using system.collections.generic;
 3 using system.linq;
 4 using system.text;
 5 
 6 namespace jzg.logs
 7 {
 8     /// <summary>
 9     /// 用于缓存的日志记录实体
10     /// </summary>
11     public class loginfo
12     {
13         /// <summary>
14         /// 要记录到哪个文件里
15         /// </summary>
16         public string logfile
17         {
18             get; set;
19         }
20 
21         /// <summary>
22         /// 记录的文字内容
23         /// </summary>
24         public string logcontent
25         {
26             get; set;
27         }
28     }
29 }

 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网