上一篇咱們提到使用.NET自帶的TraceSource實現簡單的日誌,具體請看《輕鬆背後的N+疲憊——系統日誌》,這一篇注意想講的是日誌的詳細記錄,包含請求開始到結束的過程當中調用的方法鏈以及記錄日誌那一刻的類名,方法名,行號等。html
其實也就是堆棧的跟蹤了,微軟爲咱們提供了一個對堆棧跟蹤的對象StackTrace,具體信息請看 MSDN-StackTrace類.安全
下面是對TraceSourceLogger類的改進:post
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表示爲獲取當前項目方法的堆棧跟蹤。ui
1 var realFrameList = frameList.Where(i => i.GetMethod().DeclaringType != this.GetType() && i.GetFileLineNumber() > 0);
下面咱們作個測試:this
[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; }
日誌的記錄結果以下:spa
固然也能夠將異常的直接扔到StackTrace中,獲取詳細的堆棧,可是這樣沒法獲取從請求那一刻開始的方法鏈的跟蹤。日誌
還有一個是乎沒法解決的問題,就是獲取詳細的代碼行,估計微軟也是爲了確保程序的安全性吧,要是一不當心顯示出關鍵代碼被人拿走了就糟糕了,若是有哪位大牛知道怎麼獲取的話,麻煩指點指點!!code
出處:http://www.cnblogs.com/zcylife/p/3690300.htmlorm