使用StackTrace堆栈跟踪记录详细日志(可获取行号)

  上一篇我们提到使用.NET自带的TraceSource实现简单的日志,具体请看《轻松背后的N+疲惫——系统日志》,这一篇注意想讲的是日志的详细记录,包含请求开始到结束的过程中调用的方法链以及记录日志那一刻的类名,方法名,行号等。

  其实也就是堆栈的跟踪了,微软为我们提供了一个对堆栈跟踪的对象StackTrace,具体信息请看 MSDN-StackTrace类.

  下面是对TraceSourceLogger类的改进:

复制代码
  1     public sealed class TraceSourceLogger
  2         :ILogger
  3     {
  4 
  5         TraceSource _source;
  6 
  7         public TraceSourceLogger()
  8         {
  9             _source = new TraceSource("Bulrush");
 10         }
 11 
 12         public void Fatal(string message, params object[] args)
 13         {
 14             if (String.IsNullOrWhiteSpace(message))
 15                 return;
 16 
 17             string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
 18             TraceStack(TraceEventType.Critical, messageToTrace);
 19         }
 20 
 21         public void Fatal(string message, Exception exception, params object[] args)
 22         {
 23             if (String.IsNullOrWhiteSpace(message) || exception == null)
 24                 return;
 25 
 26             string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
 27             TraceException(TraceEventType.Critical, exception, messageToTrace);
 28         }
 29 
 30         public void Infomation(string message, params object[] args)
 31         {
 32             if (String.IsNullOrWhiteSpace(message))
 33                 return;
 34 
 35             string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
 36             Trace(TraceEventType.Information, messageToTrace);
 37         }
 38 
 39         public void Warning(string message, params object[] args)
 40         {
 41             if (String.IsNullOrWhiteSpace(message))
 42                 return;
 43 
 44             string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
 45             Trace(TraceEventType.Warning, messageToTrace);
 46         }
 47 
 48         public void Error(string message, params object[] args)
 49         {
 50             if (String.IsNullOrWhiteSpace(message))
 51                 return;
 52 
 53             string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
 54             TraceStack(TraceEventType.Error, messageToTrace);
 55         }
 56 
 57         public void Error(string message, Exception exception, params object[] args)
 58         {
 59             if (String.IsNullOrWhiteSpace(message) || exception == null)
 60                 return;
 61 
 62             string messageToTrace = String.Format(CultureInfo.InvariantCulture, message, args);
 63             TraceException(TraceEventType.Error, exception, messageToTrace);
 64         }
 65 
 66         void Trace(TraceEventType eventType, string message)
 67         {
 68             if (_source != null)
 69             {
 70                 try
 71                 {
 72                     _source.TraceEvent(eventType, (int)eventType, message);
 73                 }
 74                 catch (SecurityException)
 75                 {
 76                     //这里处理写入是出现的安全问题,如文件没有写入权限。
 77                 }
 78             }
 79         }
 80 
 81         void TraceStack(TraceEventType eventType, string message)
 82         {
 83             string stackMessage = BuildStackTraceMessage();
 84             string messageToTrace = message + Environment.NewLine + Environment.NewLine + stackMessage;
 85 
 86             Trace(eventType, messageToTrace);
 87         }
 88 
 89         void TraceException(TraceEventType eventType, Exception ex, string message)
 90         {
 91             StringBuilder builder = new StringBuilder();
 92             builder.AppendFormat("错误信息:{0}", message).AppendLine();
 93             builder.AppendFormat("异常信息:{0}", ex.Message).AppendLine();
 94             builder.AppendFormat("异常类型:{0}", ex.GetType().Name).AppendLine();
 95 
 96             string stackMessage = BuildStackTraceMessage();
 97             builder.Append(stackMessage);
 98 
 99             Trace(eventType, builder.ToString());
100         }
101 
102         string BuildStackTraceMessage()
103         {
104             StackTrace trace = new StackTrace(true);
105             return BuildStackTraceMessage(trace);
106         }
107 
108         string BuildStackTraceMessage(StackTrace stackTrace)
109         {
110             if (stackTrace != null)
111             {
112                 var frameList = stackTrace.GetFrames();
113                 var realFrameList = frameList.Where(i => i.GetMethod().DeclaringType != this.GetType() && i.GetFileLineNumber() > 0);
114                 if (realFrameList.Any())
115                 {
116                     StringBuilder builder = new StringBuilder();
117                     realFrameList = realFrameList.Reverse();
118                     var lastFrame = realFrameList.Last();
119                     builder.AppendFormat("源文件:{0}", lastFrame.GetFileName()).AppendLine();
120                     builder.AppendFormat("行号:{0}", lastFrame.GetFileLineNumber()).AppendLine();
121                     builder.AppendFormat("方法名:{0}", lastFrame.GetMethod().ToString()).AppendLine();
122                     builder.AppendLine("堆栈跟踪:");
123                     builder.AppendLine("=================================================================");
124 
125                     MethodBase method;
126                     foreach (var frame in realFrameList)
127                     {
128                         method = frame.GetMethod();
129                         builder.AppendFormat("> {0} 类下的第{1}行 {2} 方法", method.DeclaringType.ToString(), frame.GetFileLineNumber(), method.ToString()).AppendLine();
130                     }
131                     builder.AppendLine("=================================================================");
132                     return builder.ToString();
133                 }
134             }
135             return "没有堆栈信息";
136         }
137     }
复制代码

最主要的部分在于BuildStackTraceMessage这个方法

复制代码
 1     string BuildStackTraceMessage(StackTrace stackTrace)
 2         {
 3             if (stackTrace != null)
 4             {
 5                 var frameList = stackTrace.GetFrames();
 6                 var realFrameList = frameList.Where(i => i.GetMethod().DeclaringType != this.GetType() && i.GetFileLineNumber() > 0);
 7                 if (realFrameList.Any())
 8                 {
 9                     StringBuilder builder = new StringBuilder();
10                     realFrameList = realFrameList.Reverse();
11                     var lastFrame = realFrameList.Last();
12                     builder.AppendFormat("源文件:{0}", lastFrame.GetFileName()).AppendLine();
13                     builder.AppendFormat("行号:{0}", lastFrame.GetFileLineNumber()).AppendLine();
14                     builder.AppendFormat("方法名:{0}", lastFrame.GetMethod().ToString()).AppendLine();
15                     builder.AppendLine("堆栈跟踪:");
16                     builder.AppendLine("=================================================================");
17 
18                     MethodBase method;
19                     foreach (var frame in realFrameList)
20                     {
21                         method = frame.GetMethod();
22                         builder.AppendFormat("> {0} 类下的第{1}行 {2} 方法", method.DeclaringType.ToString(), frame.GetFileLineNumber(), method.ToString()).AppendLine();
23                     }
24                     builder.AppendLine("=================================================================");
25                     return builder.ToString();
26                 }
27             }
28             return "没有堆栈信息";
29         }
复制代码

下面这句代码是为了去除.NET FrameWork方法的堆栈跟踪和当前记录日志方法的跟踪,i.GetFileLineNumber() > 0行号大于0表示为获取当前项目方法的堆栈跟踪。

1 var realFrameList = frameList.Where(i => i.GetMethod().DeclaringType != this.GetType() && i.GetFileLineNumber() > 0);

下面我们做个测试:

复制代码
        [TestMethod]
        public void TestTraceSourceLogger()
        {
            GetMyNumber();
        }

        private int GetMyNumber()
        {
            ILoggerFactory factory = new TraceSourceLoggerFactory();
            LoggerContext.SetCurrent(factory);


            try
            {
                var number = int.Parse("我要转成Int32类型");
                return number;
            }
            catch (FormatException)
            {
                LoggerContext.CreateLog().Error("字符串无法转换为Int32类型");
            }
            return 0;
        }
复制代码

日志的记录结果如下:

当然也可以将异常的直接扔到StackTrace中,获取详细的堆栈,但是这样无法获取从请求那一刻开始的方法链的跟踪。

还有一个是乎无法解决的问题,就是获取详细的代码行,估计微软也是为了确保程序的安全性吧,要是一不小心显示出关键代码被人拿走了就糟糕了,如果有哪位大牛知道怎么获取的话,麻烦指点指点!!

出处:http://www.cnblogs.com/zcylife/p/3690300.html

原文地址:https://www.cnblogs.com/mq0036/p/6540516.html