使用StackTrace堆棧跟蹤記錄詳細日誌(可獲取行號)

  上一篇咱們提到使用.NET自帶的TraceSource實現簡單的日誌,具體請看《輕鬆背後的N+疲憊——系統日誌》,這一篇注意想講的是日誌的詳細記錄,包含請求開始到結束的過程當中調用的方法鏈以及記錄日誌那一刻的類名,方法名,行號等。html

  其實也就是堆棧的跟蹤了,微軟爲咱們提供了一個對堆棧跟蹤的對象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這個方法ui

 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表示爲獲取當前項目方法的堆棧跟蹤。this

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

下面咱們作個測試:spa

 

        [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中,獲取詳細的堆棧,可是這樣沒法獲取從請求那一刻開始的方法鏈的跟蹤。code

還有一個是乎沒法解決的問題,就是獲取詳細的代碼行,估計微軟也是爲了確保程序的安全性吧,要是一不當心顯示出關鍵代碼被人拿走了就糟糕了,若是有哪位大牛知道怎麼獲取的話,麻煩指點指點!!orm

相關文章
相關標籤/搜索