網頁

2011年11月21日 星期一

使用NLog - Advanced .NET Logging (6)


 

記錄Exception的內容

使用NLog的最大一個功能就是要去捕捉並且記錄下發生Exception的訊息與內容,

而在有關「使用NLog - Advanced .NET Logging 」系列的文章中都有說明到如何記錄以及記錄哪些資料,

NLog有提供很多的Layout Renderer可以使用,而Exception Layout Renderer更是要好好的來仔細整理一下,


首先看一下在「使用NLog - Advanced .NET Logging (1)」中有介紹的一個方法「LogUtility.BuildExceptionMessage()」

public class LogUtility
{
  /// <summary>
  /// Builds the exception message.
  /// </summary>
  /// <param name="x">The x.</param>
  /// <returns></returns>
  public static string BuildExceptionMessage(Exception x)
  {
    Exception logException = x;
    if (x.InnerException != null)
    {
      logException = x.InnerException;
    }
    StringBuilder message = new StringBuilder();
    message.AppendLine();
    message.AppendLine("Error in Path : " + System.Web.HttpContext.Current.Request.Path);
    // Get the QueryString along with the Virtual Path
    message.AppendLine("Raw Url : " + System.Web.HttpContext.Current.Request.RawUrl);
    // Type of Exception
    message.AppendLine("Type of Exception : " + logException.GetType().Name);
    // Get the error message
    message.AppendLine("Message : " + logException.Message);
    // Source of the message
    message.AppendLine("Source : " + logException.Source);
    
    // Stack Trace of the error
    message.AppendLine("Stack Trace : " + logException.StackTrace);
    // Method where the error occurred
    message.AppendLine("TargetSite : " + logException.TargetSite);
    return message.ToString();
  }
}

這邊稍微修改 NLog.Config 裡 Fatal Target 的設定

  <target name="FatalFile" xsi:type="File"
    fileName="${basedir}/App_Data/Logs/${shortdate}/FatalFile.txt"
    layout="
====================================================================================================
${newline}
發生時間:${longdate} ${newline}${newline}
Log等級:${level:uppercase=true} ${newline}${newline}
Logger:${logger} ${newline}${newline}
Source:${callsite:className=true} ${newline}${newline}
錯誤訊息:${message} ${newline}${newline}
====================================================================================================
${newline}
"
      />

然後在程式中實際應用

    public ActionResult About()
    {
      try
      {
        int a = 6;
        int b = 0;
        int result = a / b;
      }
      catch (Exception ex)
      {
        logger.Fatal(LogUtility.BuildExceptionMessage(ex));
      }
      
      return View();
    }

最後得到的記錄結果

 ==================================================================================================== 
 發生時間:2011-11-21 21:52:05.1874 
 Log等級:FATAL 
 Logger:Test.Web.Controllers.HomeController 
 Source:Test.Web.Controllers.HomeController.About 
 錯誤訊息:
Error in Path : /Home/About
Raw Url : /Home/About
Type of Exception : DivideByZeroException
Message : 嘗試以零除。
Source : Test.Web
StackTrace :    於 Test.Web.Controllers.HomeController.About() 於 D:\Develope\Lab\Lab_Of_NLog\Test.Web\Controllers\HomeController.cs: 行 27
TargetSite : System.Web.Mvc.ActionResult About()
 
 ==================================================================================================== 

 

但如果想要記錄到Exception裡更詳細的InnerException內容時,那是必要去修改以上的「LogUtility.BuildExceptionMessage()」

但其實不用自己來寫,因為NLog有提供Layout Renderer的設定

NLog - Exception logging enhancements

依據文件中所提供的內容,我們對Fatal Taeget做了修改:

  <target name="FatalFile" xsi:type="File"
    fileName="${basedir}/App_Data/Logs/${shortdate}/FatalFile.txt"
    layout="
====================================================================================================
${newline}
發生時間:${longdate} ${newline}${newline}
Log等級:${level:uppercase=true} ${newline}${newline}
Logger:${logger} ${newline}${newline}
Source:${callsite:className=true} ${newline}${newline}
錯誤訊息:${message} ${newline}${newline}
StackTrace:${newline}${exception:format=stacktrace}${newline}${newline}
Exception類別:${exception:format=type} ${newline}${newline}
Exception訊息:${exception:format=message} ${newline}${newline}
${newline}
InnerException Detail:${newline}${onexception:EXCEPTION OCCURRED\:${exception:format=type,message,method:maxInnerExceptionLevel=5:innerFormat=shortType,message,method}}${newline}
====================================================================================================
${newline}
"
      />

這邊要特別提到的是「${exception:maxInnerExceptionLevel=N}」,

因為Exception發生時,其InnerException有可能會有包相當多層,

所以我們可以藉由這一個設定去讓NLog記錄到說多少層的InnerException內容,如此一來我們就不必去勞師動眾的改寫程式。

 

改好Fatal Target之後,我們將實際執行的程式再去做個修改:

    public ActionResult About()
    {
      try
      {
        int a = 6;
        int b = 0;
        int result = a / b;
      }
      catch (Exception ex)
      {
        logger.Fatal(ex);
      }
      
      return View();
    }

直接使用 logger.Fatal(ex) 的方式來記錄Exception內容,而得到的 Log資料如下:

 ==================================================================================================== 
 發生時間:2011-11-21 22:05:59.0481 
 Log等級:FATAL 
 Logger:Test.Web.Controllers.HomeController 
 Source:Test.Web.Controllers.HomeController.About 
 錯誤訊息:System.DivideByZeroException: 嘗試以零除。
   於 Test.Web.Controllers.HomeController.About() 於 D:\Develope\Lab\Lab_Of_NLog\Test.Web\Controllers\HomeController.cs: 行 27 
 StackTrace:
 Exception類別: 
 Exception訊息: 
 
 InnerException Detail:
 ==================================================================================================== 

上面的Log資訊怎麼好像看起來不是我們所想要的…

其實NLog這邊對於Exception的紀錄方式有提供了一組方法,可以讓Nlog正確的記錄Exception內容

  • TraceException()
  • DebugException()
  • InfoException()
  • WarnException()
  • ErrorException()
  • FatalException()
  • LogException() – takes log level as a parameter

所以我們去修改一下程式的內容也順便修改一下Fatal Target的內容:

  <target name="FatalFile" xsi:type="File"
    fileName="${basedir}/App_Data/Logs/${shortdate}/FatalFile.txt"
    layout="
====================================================================================================
${newline}
發生時間:${longdate} ${newline}${newline}
Log等級:${level:uppercase=true} ${newline}${newline}
Logger:${logger} ${newline}${newline}
Source:${callsite:className=true} ${newline}${newline}
錯誤訊息:${message} ${newline}${newline}
StackTrace:${newline}${exception:format=stacktrace}${newline}${newline}
Exception類別:${exception:format=type} ${newline}${newline}
Exception訊息:${exception:format=message} ${newline}${newline}
EXCEPTION OCCURRED:${newline}
${exception:format=type,message,method:maxInnerExceptionLevel=5:innerFormat=shortType,message,method}${newline}
====================================================================================================
${newline}
"
      />
    public ActionResult About()
    {
      try
      {
        int a = 6;
        int b = 0;
        int result = a / b;
      }
      catch (Exception ex)
      {
        logger.FatalException("刻意產生的異常 ", ex);
      }
      
      return View();
    }

改用 logger.FatalException() 方法來記錄 Exception內容,而NLog所記錄的log內容如下:

 ==================================================================================================== 
 發生時間:2011-11-21 22:19:55.2339 
 Log等級:FATAL 
 Logger:Test.Web.Controllers.HomeController 
 Source:Test.Web.Controllers.HomeController.About 
 錯誤訊息:刻意產生的異常  
 StackTrace:
   於 Test.Web.Controllers.HomeController.About() 於 D:\Develope\Lab\Lab_Of_NLog\Test.Web\Controllers\HomeController.cs: 行 27
 Exception類別:System.DivideByZeroException 
 Exception訊息:嘗試以零除。 
 EXCEPTION OCCURRED:
 System.DivideByZeroException 嘗試以零除。 System.Web.Mvc.ActionResult About()
 ==================================================================================================== 
 

就log記錄的內容而言,都有正確的記錄到Exception的詳細內容。

 

這一邊簡單的說明一下如何使用NLog所提供的方法去正確的紀錄Exception內容,更清楚了解程式問題發生的原因。

 

參考連結:

NLog - Exception layout renderer

NLog - Exception logging enhancements

NLog - How to properly log exceptions?

 

以上

沒有留言:

張貼留言