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?

 

以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。