你的日志组件记录够清晰嘛?--自己开发日志组件 Logger

现在现成的日志组件实在是太多太多,为什么我还需要自己实现呢?????

需求来源于java的log4j,

[07-31 16:40:00:557:WARN : com.game.engine.thread.ServerThread:117] -> 全局排行榜同步执行器-->ServerThread[全局排行榜同步执行器]执行 执行时间过长:23

简单的一句日志信息,但是我却可以很清晰的定位日志输出的代码位置;com.game.engine.thread包下面的ServerThread这个类文件的第117行;

而log4net却不行,

也许是因为我米有找到正确的对应配置文件、可惜吧~!

于是我打算自己重组日志组件来实现清洗的日志记录。当然你也可以说,.net平台下面的exception抛错的话日志也很清晰。

但是有时候我们逻辑错误或者是参数错误,根本不会抛错,这种情况下我们没有得到预期结果的时候只能通过简单调试找出原因。

那么很明显费时,费力,所以我就想得到像log4j那样打印出清晰的日志。

可能你会问有这个必要嘛?很有必要哦,比如你程序上线一个版本,然后打印的信息和现在最新版本行号已经不符合了,数据流向和清晰度自然而然就不存在多大的意义~!

如果需要找到这样清晰的日志。那么就需要得到方法的调用堆栈信息。

查阅文档发现 System.Diagnostics.StackTrace 类是记录堆栈信息的

于是开始无尽的测试之行

 1 namespace Sz.StackTraceTest
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Test();
 8             Console.ReadLine();
 9         }
10
11         static public void Test()
12         {
13             ShowStackTrace();
14         }
15
16         static public void ShowStackTrace()
17         {
18
19             StackTrace trace = new StackTrace();
20             var frames = trace.GetFrames();
21             foreach (var item in frames)
22             {
23                 Console.WriteLine(string.Format("[{0},文件{1},方法{2},行{3}]", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), item.GetFileName(), item.GetMethod(), item.GetFileLineNumber()));
24             }
25         }
26
27     }
28 }

运行后发现:

并未得到文件等信息,为啥会这样

        // 摘要:
        //     用调用方的帧初始化 System.Diagnostics.StackTrace 类的新实例。
        public StackTrace();
        //
        // 摘要:
        //     用调用方的帧初始化 System.Diagnostics.StackTrace 类的新实例,可以选择捕获源信息。
        //
        // 参数:
        //   fNeedFileInfo:
        //     如果为 true,则捕获文件名、行号和列号;否则为 false。
        public StackTrace(bool fNeedFileInfo);

查询了一下StackTrace类的重载得知,应该是默认构造函数并未捕获信息

那么重来一次

这次取到了。可是意外的发现,记录的文件居然 是全路径。,

显然这不是我想要的结果。

那么再试试看有么有其他路径。

于是想到,既然有函数,那么可以通过函数入手啊,函数,肯定有父节啊。

        //
        // 摘要:
        //     获取声明该成员的类。
        //
        // 返回结果:
        //     声明该成员的类的 Type 对象。
        public abstract Type DeclaringType { get; }

于是找到这个属性,声明该函数的对象。那么肯定会得到类型的完全限定名称了;

 1 namespace Sz.StackTraceTest
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Test();
 8             Console.ReadLine();
 9         }
10
11         static public void Test()
12         {
13             ShowStackTrace();
14         }
15
16         static public void ShowStackTrace()
17         {
18
19             StackTrace trace = new StackTrace(true);
20             var frames = trace.GetFrames();
21             foreach (var item in frames)
22             {
23                 Console.WriteLine(string.Format("[{0},文件{1},方法{2},行{3}]", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), item.GetMethod().DeclaringType.FullName, item.GetMethod(), item.GetFileLineNumber()));
24             }
25         }
26
27     }
28 }

看看那运行结果

得到命名空间和类型名了。

但是图中我们看到,其实我只想Test()中输出打印的地方加入一个而已,

但是打印出了整个走向,这个时候我们是普通打印日志根本不需要整个的流程走向

再次查看StackTrace类还有一个重载方式

 1         //
 2         // 摘要:
 3         //     从调用方的帧初始化 System.Diagnostics.StackTrace 类的新实例,跳过指定的帧数并可以选择捕获源信息。
 4         //
 5         // 参数:
 6         //   skipFrames:
 7         //     堆栈中的帧数,将从其上开始跟踪。
 8         //
 9         //   fNeedFileInfo:
10         //     如果为 true,则捕获文件名、行号和列号;否则为 false。
11         //
12         // 异常:
13         //   System.ArgumentOutOfRangeException:
14         //     skipFrames 参数为负数。
15         public StackTrace(int skipFrames, bool fNeedFileInfo);

跳过指定帧;

 1 namespace Sz.StackTraceTest
 2 {
 3     class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Test();
 8             Console.ReadLine();
 9         }
10
11         static public void Test()
12         {
13             Log("test");
14             Log("test");
15             Log("test");
16         }
17
18         static public void Log(string msg)
19         {
20             StackTrace trace = new StackTrace(1, true);
21             if (trace.GetFrames().Length > 0)
22             {
23                 var item = trace.GetFrame(0);
24                 Console.WriteLine(string.Format("[{0},文件{1},方法{2},行{3}]:{4}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), item.GetMethod().DeclaringType.FullName, item.GetMethod(), item.GetFileLineNumber(), msg));
25             }
26             else
27             {
28                 Console.WriteLine(string.Format("[{0},文件{1},方法{2},行{3}]:{4}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), null, null, null, msg));
29             }
30             //var frames = trace.GetFrames();
31
32             //foreach (var item in frames)
33             //{
34             //    Console.WriteLine(string.Format("[{0},文件{1},方法{2},行{3}]", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), item.GetMethod().DeclaringType.FullName, item.GetMethod(), item.GetFileLineNumber()));
35             //}
36         }
37     }
38 }

再来看看

ok已完全符合我的需求了。是不是呢???这样检查逻辑错误的时候方便许多了。

附上我的全部日志组件源码

组件实现了简单的配置;

由于日志打印控制还是输出文本文件都是比较耗时的事情;所以加入线程模型

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Diagnostics;
  4 using System.IO;
  5 using System.Linq;
  6 using System.Text;
  7 using System.Threading;
  8
  9 /**
 10  *
 11  * @author 失足程序员
 12  * @Blog http://www.cnblogs.com/ty408/
 13  * @mail [email protected]
 14  * @phone 13882122019
 15  *
 16  */
 17 namespace Sz
 18 {
 19     /// <summary>
 20     /// 日志辅助
 21     /// <para>AppSettings 设置 LogRootPath 为日志的根目录</para>
 22     /// </summary>
 23     public class Logger
 24     {
 25         static ThreadModel logConsoleThread = new ThreadModel("Console Log Thread");
 26         static ThreadModel logFileThread = new ThreadModel("File Log Thread");
 27         static string logInfoPath = "log/info/";
 28         static string logErrorPath = "log/error/";
 29
 30         /// <summary>
 31         /// 设置日志的输出根目录
 32         /// </summary>
 33         /// <param name="path"></param>
 34         static public void SetLogRootPath(string path)
 35         {
 36
 37             logInfoPath = path + logInfoPath;
 38             logErrorPath = path + logErrorPath;
 39             if (!Directory.Exists(logInfoPath)) { Directory.CreateDirectory(logInfoPath); }
 40             if (!Directory.Exists(logErrorPath)) { Directory.CreateDirectory(logErrorPath); }
 41
 42         }
 43
 44         static Logger()
 45         {
 46
 47             if (System.Configuration.ConfigurationManager.AppSettings.AllKeys.Contains("LogRootPath"))
 48             {
 49                 string logPath = System.Configuration.ConfigurationManager.AppSettings["LogRootPath"].ToString();
 50                 if (!(logPath.EndsWith("\\") || logPath.EndsWith("/")))
 51                 {
 52                     logPath = "\\";
 53                 }
 54                 logInfoPath = logPath + logInfoPath;
 55                 logErrorPath = logPath + logErrorPath;
 56             }
 57             if (!Directory.Exists(logInfoPath)) { Directory.CreateDirectory(logInfoPath); }
 58             if (!Directory.Exists(logErrorPath)) { Directory.CreateDirectory(logErrorPath); }
 59
 60         }
 61
 62         #region 日子写入文件辅助任务 class LogTaskFile : TaskBase
 63         /// <summary>
 64         /// 日子写入文件辅助任务
 65         /// </summary>
 66         class LogTaskFile : TaskBase
 67         {
 68             string msg, mathed;
 69             Exception exce;
 70             StackTrace trace;
 71             static readonly StringBuilder sb = new StringBuilder();
 72             public LogTaskFile(StackTrace trace, string mathed, string msg, Exception exce)
 73                 : base("File Log Task")
 74             {
 75                 this.mathed = mathed;
 76                 this.trace = trace;
 77                 this.msg = msg;
 78                 this.exce = exce;
 79             }
 80
 81             public override void TaskRun()
 82             {
 83                 var frame = trace.GetFrame(0);
 84                 DateTime dnow = DateTime.Now;
 85                 sb.Clear();
 86                 sb.Append("[")
 87                     .Append(dnow.NowString())
 88                     .Append(mathed.PadRight(5))
 89                     .Append(":")
 90                     .Append(frame.GetMethod().DeclaringType.FullName)
 91                     .Append(", ")
 92                     .Append(frame.GetMethod())
 93                     .Append(", ")
 94                     .Append(frame.GetFileLineNumber())
 95                     .Append("] ").Append(msg);
 96
 97                 if (exce != null)
 98                 {
 99                     sb.AppendLine("")
100                     .AppendLine("----------------------Exception--------------------------")
101                     .Append(exce.GetType().FullName).Append(": ").AppendLine(exce.Message)
102                     .AppendLine(exce.StackTrace)
103                     .AppendLine("----------------------Exception--------------------------");
104                 }
105                 string logPath = string.Format("{0}info_{1}.log", logInfoPath, dnow.ToString("yyyyMMdd"));
106
107                 System.IO.File.AppendAllText(logPath, sb.ToString(), UTF8Encoding.Default);
108                 System.IO.File.AppendAllText(logPath, "\r\n", UTF8Encoding.Default);
109
110                 logPath = string.Format("{0}error_{1}.log", logErrorPath, dnow.ToString("yyyyMMdd"));
111                 System.IO.File.AppendAllText(logPath, sb.ToString(), UTF8Encoding.Default);
112                 System.IO.File.AppendAllText(logPath, "\r\n", UTF8Encoding.Default);
113
114             }
115         }
116         #endregion
117
118         #region 日志写入控制台输出 class LogTaskConsole : TaskBase
119         /// <summary>
120         /// 日志写入控制台输出
121         /// </summary>
122         class LogTaskConsole : TaskBase
123         {
124             string msg, mathed;
125             Exception exce;
126             StackTrace trace;
127             static readonly StringBuilder sb = new StringBuilder();
128
129             public LogTaskConsole(StackTrace trace, string mathed, string msg, Exception exce)
130                 : base("Console Log Task")
131             {
132                 this.mathed = mathed;
133                 this.trace = trace;
134                 this.msg = msg;
135                 this.exce = exce;
136             }
137
138             public override void TaskRun()
139             {
140                 sb.Clear();
141                 var frame = trace.GetFrame(0);
142                 sb.Append("[")
143                     .Append(DateTime.Now.NowString())
144                     .Append(mathed.PadRight(5))
145                     .Append(":")
146                     .Append(frame.GetMethod().DeclaringType.FullName)
147                     //.Append(", ")
148                     //.Append(frame.GetMethod())
149                     .Append(", ")
150                     .Append(frame.GetFileLineNumber())
151                     .Append("] ").Append(msg);
152
153                 if (exce != null)
154                 {
155                     sb.AppendLine("")
156                     .AppendLine("----------------------Exception--------------------------")
157                     .Append(exce.GetType().FullName).Append(": ").AppendLine(exce.Message)
158                     .AppendLine(exce.StackTrace)
159                     .AppendLine("----------------------Exception--------------------------");
160                 }
161                 Console.WriteLine(sb.ToString());
162             }
163         }
164         #endregion
165
166         string name;
167         /// <summary>
168         ///
169         /// </summary>
170         /// <param name="name"></param>
171         public Logger(string name)
172         {
173             this.name = name;
174         }
175
176         /// <summary>
177         /// 输出到控制台
178         /// </summary>
179         /// <param name="msg"></param>
180         static public void Debug(string msg)
181         {
182             StackTrace trace = new StackTrace(1, true);
183             LogTaskConsole logConsole = new LogTaskConsole(trace, "Debug", msg, null);
184             logConsoleThread.AddTask(logConsole);
185         }
186
187         /// <summary>
188         /// 控制台和文本文件
189         /// </summary>
190         /// <param name="msg"></param>
191         static public void Info(string msg)
192         {
193             AddLog("Info", msg, null);
194         }
195         /// <summary>
196         /// 控制台和文本文件
197         /// </summary>
198         static public void Error(string msg)
199         {
200             AddLog("Error", msg, null);
201         }
202         /// <summary>
203         /// 控制台和文本文件
204         /// </summary>
205         static public void Error(string msg, Exception exception)
206         {
207             AddLog("Error", msg, exception);
208         }
209
210         static void AddLog(string mathed, string msg, Exception exception)
211         {
212             StackTrace trace = new StackTrace(2, true);
213             LogTaskConsole logConsole = new LogTaskConsole(trace, mathed, msg, exception);
214             logConsoleThread.AddTask(logConsole);
215             LogTaskFile logFile = new LogTaskFile(trace, mathed, msg, exception);
216             logFileThread.AddTask(logFile);
217         }
218     }
219 }

线程模型的任务类型

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6
 7 /**
 8  *
 9  * @author 失足程序员
10  * @Blog http://www.cnblogs.com/ty408/
11  * @mail [email protected]
12  * @phone 13882122019
13  *
14  */
15 namespace Sz
16 {
17     internal abstract class TaskBase
18     {
19
20         public string Name { get; private set; }
21
22         public TaskBase(string name)
23         {
24             this.Name = name;
25             TempAttribute = new ObjectAttribute();
26         }
27         public ObjectAttribute TempAttribute { get; set; }
28
29         public abstract void TaskRun();
30     }
31 }

线程模型

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading;
 6 using System.Threading.Tasks;
 7
 8 /**
 9  *
10  * @author 失足程序员
11  * @Blog http://www.cnblogs.com/ty408/
12  * @mail [email protected]
13  * @phone 13882122019
14  *
15  */
16 namespace Sz
17 {
18     /// <summary>
19     /// 线程模型
20     /// </summary>
21     internal class ThreadModel
22     {
23         public bool IsStop = false;
24         /// <summary>
25         /// ID
26         /// </summary>
27         public int ID;
28
29         static int StaticID = 0;
30
31         public ThreadModel(string name)
32         {
33             lock (typeof(ThreadModel))
34             {
35                 StaticID++;
36             }
37             ID = StaticID;
38             System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ThreadStart(Run));
39             thread.Name = name;
40             thread.IsBackground = true;
41             thread.Start();
42         }
43
44         /// <summary>
45         /// 任务队列
46         /// </summary>
47         protected System.Collections.Concurrent.ConcurrentQueue<TaskBase> taskQueue = new System.Collections.Concurrent.ConcurrentQueue<TaskBase>();
48
49         /// <summary>
50         /// 加入任务
51         /// </summary>
52         /// <param name="t"></param>
53         public virtual void AddTask(TaskBase t)
54         {
55             taskQueue.Enqueue(t);
56             //防止线程正在阻塞时添加进入了新任务
57             are.Set();
58         }
59
60         //通知一个或多个正在等待的线程已发生事件
61         protected ManualResetEvent are = new ManualResetEvent(false);
62
63         protected virtual void Run()
64         {
65             while (true)
66             {
67                 while (!taskQueue.IsEmpty)
68                 {
69                     TaskBase t = null;
70                     if (!taskQueue.IsEmpty && taskQueue.TryDequeue(out t))
71                     {
72                         try
73                         {
74                             t.TaskRun();//执行任务
75                             t = null;
76                         }
77                         catch (Exception ex)
78                         {
79                             Logger.Error("Thread:<" + Thread.CurrentThread.Name + "> TaskRun <" + t.Name + ">", ex);
80                         }
81                     }
82                 }
83                 are.Reset();
84                 //队列为空等待200毫秒继续
85                 are.WaitOne(200);
86             }
87         }
88     }
89 }

到此为止,日志组件完成。如果有需要的或者原因的可以自己加入,数据库,和mail处理的

时间: 2024-10-20 15:58:54

你的日志组件记录够清晰嘛?--自己开发日志组件 Logger的相关文章

11.22 访问日志不记录静态文件11.23 访问日志切割11.24 静态元素过期时间

11.22 访问日志不记录静态文件11.23 访问日志切割11.24 静态元素过期时间编辑虚拟配置文件:vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf11.23 访问日志切割修改完配置文件后,需要重新访问下网址才能生动生成日志文件,以后每到00:00就会自动生成以系统日期为名字的新的日志文件编辑虚拟配置文件:vim /usr/local/apache2.4/conf/extra/httpd-vhosts.conf修改完后重新加载配置文件

11.22 访问日志不记录静态文件 11.23 访问日志切割 11.24 静态元素过期时间

11.22 访问日志不记录静态文件 11.23 访问日志切割 11.24 静态元素过期时间 11.22 访问日志不记录静态文件 11.23 访问日志切割 11.24 静态元素过期时间 原文地址:http://blog.51cto.com/wbyyy/2083288

nginx设置日志不记录404或者200或者其他日志信息

这里我们用到的是ngx_log_if,它是Nginx的一个第三方模块. 第一步: 先到Github下载ngx_log_if地址https://github.com/cfsego/ngx_log_if/ ,你可以下载压缩包,然后在解压unzip  ngx_log_if-master.zip 第二步 编译安装nginx   ./configure   --prefix=/usr/local/nginx   --with-pcre  --add -module=/root/ngx_log_if-mas

访问日志不记录静态文件、配置访问日志切割、配置静态元素过期时间

访问日志不记录指定类型的文件 一个网站会有很多元素,尤其是图片.js.css等静态的文件非常多,用户每请求一个页面就会访问诸多的图片.js等静态元素,这些元素的请求都会被记录在日志中.如果一个站点访问量很大,那么访问日志文件增长会非常快,这不仅对于服务器的磁盘空间造成影响,更重要的是会影响磁盘的读写速度.实际上这些巨量的静态元素请求记录到日志里的意义并不大,所以可以限制这些静态元素去记录日志,并且需要把日志按天归档,一天一个日志,这样也可以防止单个日志文件过大. 编辑虚拟主机配置文件vim /u

访问日志不记录指定文件类型 、 访问日志切割 、静态元素过期时间

一:访问日志不记录指定文件类型 #vim /usr/local/apache2/conf/extra/httpd-vhosts.conf 在对应的虚拟主机配置文件中加入 相关配置为: SetEnvIf Request_URI "..gif$" image-request SetEnvIf Request_URI "..jpg$" image-request SetEnvIf Request_URI "..png$" image-request S

11.22 访问日志不记录静态文件 11.23 访问日志切割 11.24 静态元素过期时间

[[email protected] ~]# /usr/local/apache2.4/bin/apachectl -tSyntax OK[[email protected] ~]# /usr/local/apache2.4/bin/apachectl graceful jpg的并没有记录在日志 [[email protected] ~]# cd /data/wwwroot/111.com/[[email protected] 111.com]# rz    上传一张图片  we,然后浏览器请求

11.22-11.24访问日志不记录静态文件,访问日志切割,静态元素过期时间

11.22 访问日志不记录静态文件 11.23 访问日志切割 11.24 静态元素过期时间 扩展 apache日志记录代理IP以及真实客户端IP  http://ask.apelearn.com/question/960apache只记录指定URI的日志  http://ask.apelearn.com/question/981apache日志记录客户端请求的域名  http://ask.apelearn.com/question/1037apache 日志切割问题  http://ask.ap

日志系统之基于flume收集docker容器日志

最近我在日志收集的功能中加入了对docker容器日志的支持.这篇文章简单谈谈策略选择和处理方式. 关于docker的容器日志 docker 我就不多说了,这两年火得发烫.最近我也正在把日志系统的一些组件往docker里部署.很显然,组件跑在容器里之后很多东西都会受到容器的制约,比如日志文件就是其中之一. 当一个组件部署到docker中时,你可以通过如下命令在标准输出流(命令行)中查看这个组件的日志: docker logs ${containerName} 日志形如: 但这种方式并不能让你实时获

点滴积累【C#】---使用log4net组件记录错误日志(以文本形式记录)

效果: 描述: 利用log4net组件进行错误日志的记录,log4net记录错误的方式我所了解的有4种,No.1 文本形式记录日志,No.2存储到数据库形式记录日志,No.3控制台控制显示日志,No.4Windows事件日志.本文所采用的是第一种形式------文本形式记录日志. 首先,引用log4net.dll文件,然后创建一个config文件,进行配置日志的相关信息,比如:配置路径,以及错误的显示形式等.然后创建一个Global.asax应用程序文件,用于第一次访问时执行配置文件.然后创建一