2012-08-10 95 views
3

目前我正在做一個Windows服務,並在代碼中的某些點維修有一些例外(由定時器等外部事件如在回調中)處理:如何登錄異常信息以進行故障排除?

try { 
    ... 
} 
catch (Exception ex) { 
    _logger.Log("Unhandled exception: {0}\r\n{1}", ex.Message, ex.StackTrace); 
    Environment.FailFast("Fatal error."); 
} 

記錄異常的信息有助於排除故障是什麼出錯。然而,有時候有趣的信息是內部的例外,這使得很難確定問題的根本原因。例如TypeInitializationException可能很難理解。

有沒有更好的方法來記錄異常信息以進行故障排除?

+1

試着這個「回答你自己的問題」的事情。目的的確是教育,因爲我在許多代碼庫中看到了這種稍差的日誌記錄風格。 – 2012-08-10 08:57:53

回答

7

有沒有更好的方法來記錄異常信息以進行故障排除?

是的。不要「聰明」,並使用ex.Messageex.StackTrace。只需使用ex.ToString()即可。它會緩存到內部異常(如果需要,可以有多個級別)並顯示完整的堆棧跟蹤。

try { 
    ... 
} 
catch (Exception ex) { 
    _logger.Log("Unhandled exception:\r\n{0}", ex); 
    Environment.FailFast("Fatal error."); 
} 

要提供一個小例子,這是如果你創建拋出在類的靜態構造函數的異常類的實例,你會得到什麼。這個異常拋出將被封裝在TypeInitializationException中。

前:

 
Unhandled exception: The type initializer for 'SomeClass' threw an exception. 
    at SomeNamespace.SomeClass..ctor() 
    at SomeNamespace.Callback() in c:\ExceptionHandlingDemo.cs:line 34 

不是非常有幫助。很難確定哪裏出了問題。

後:

 
Unhandled exception: 
System.TypeInitializationException: The type initializer for 'SomeClass' threw an exception. ---> System.ArgumentException: An item with the same key has already been added. 
    at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) 
    at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) 
    at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) 
    at SomeNamespace.SomeClass..cctor() in c:\ExceptionHandlingDemo.cs:line 43 
    --- End of inner exception stack trace --- 
    at SomeNamespace.SomeClass..ctor() 
    at SomeNamespace.Callback() in c:\ExceptionHandlingDemo.cs:line 34 

現在你可以很容易地確定問題是在字典中重複鍵的根本原因,並找出它的源文件中第43行。

+1

+1:另外,對於某些異常類型,'ToString()'包含了額外的細節,'Message'沒有(我認爲有些FileLoadException左右,包含更多關於失敗的細節,但我現在還不確定) 。 – 2012-08-10 08:54:52

0

我不知道這是否會有所幫助,或者它是否過高,但您是否知道Microsoft的企業庫? (http://msdn.microsoft.com/en-us/library/ff648951.aspx)。

其中有一個日誌「應用程序塊」,它是一個大錘,但最終非常強大/靈活。經歷了我想要的設置(它的所有配置驅動),現在我已經建立了一些標準。

特別是對於例外情況,我不認爲爲了獲得有意義的信息我不得不做很多事情。

0

我不確定這是否有幫助。我寫了這個工具類記錄異常的所有信息,我用Exception.DataException.Message登錄信息

的東西在這裏共享:https://stackoverflow.com/a/15005319/1060656

public class ExceptionInfoUtil 
{ 
    public static string GetAllExceptionInfo(Exception ex) 
    { 
     StringBuilder sbexception = new StringBuilder(); 

     int i = 1; 
     sbexception.Append(GetExceptionInfo(ex, i)); 

     while (ex.InnerException != null) 
     { 
      i++; 
      ex = ex.InnerException; 
      sbexception.Append(GetExceptionInfo(ex, i)); 
     } 

     return sbexception.ToString(); 
    } 

    private static string GetExceptionInfo(Exception ex, int count) 
    { 
     StringBuilder sbexception = new StringBuilder(); 
     sbexception.AppendLine(string.Format("")); 
     sbexception.AppendLine(string.Format("")); 
     sbexception.AppendLine(string.Format("************************************************")); 
     sbexception.AppendLine(string.Format("************************************************")); 
     sbexception.AppendLine(string.Format(" Inner Exception : No.{0} ", count)); 
     sbexception.AppendLine(string.Format("************************************************")); 
     sbexception.AppendLine(string.Format("==================================================")); 
     sbexception.AppendLine(string.Format(" Error Message : {0} ", ex.Message)); 
     sbexception.AppendLine(string.Format("==================================================")); 
     #region Mine Thru data dictionary 

     try 
     { 
      sbexception.AppendLine(string.Format("==================================================")); 
      sbexception.AppendLine(string.Format(" Data parameters Count at Source :{0}", ex.Data.Count)); 
      sbexception.AppendLine(string.Format("==================================================")); 

      string skey = string.Empty; 
      foreach (object key in ex.Data.Keys) 
      { 
       try 
       { 
        if (key != null) 
        { 
         skey = Convert.ToString(key); 
         sbexception.AppendLine(string.Format(" Key :{0} , Value:{1}", skey, Convert.ToString(ex.Data[key]))); 
        } 
        else 
        { 
         sbexception.AppendLine(string.Format(" Key is null")); 
        } 
       } 
       catch (Exception e1) 
       { 
        sbexception.AppendLine(string.Format("** Exception occurred when writting log *** [{0}] ", e1.Message)); 
       } 
      } 
     } 
     catch (Exception ex1) 
     { 
      sbexception.AppendLine(string.Format("** Exception occurred when writting log *** [{0}] ", ex1.Message)); 
     } 

     #endregion 
     sbexception.AppendLine(string.Format("==================================================")); 
     sbexception.AppendLine(string.Format(" Source : {0} ", ex.Source)); 
     sbexception.AppendLine(string.Format("==================================================")); 
     sbexception.AppendLine(string.Format(" StackTrace : {0} ", ex.StackTrace)); 
     sbexception.AppendLine(string.Format("==================================================")); 
     sbexception.AppendLine(string.Format(" TargetSite : {0} ", ex.TargetSite)); 
     sbexception.AppendLine(string.Format("************************************************")); 
     sbexception.AppendLine(string.Format(" Finished Writting Exception info :{0} ", count)); 
     sbexception.AppendLine(string.Format("************************************************")); 
     sbexception.AppendLine(string.Format("************************************************")); 
     sbexception.AppendLine(string.Format("")); 
     sbexception.AppendLine(string.Format("")); 

     return sbexception.ToString(); 

    } 
} 

下面是示例類它使用這個工具類

[Serializable] 
    public class FlatFileItem 
    { 
     ArrayList errorlist = new ArrayList(); 

     public FlatFileItem() 
     { 
      if (errorlist == null) { errorlist = new ArrayList(); } 
     } 

     //Name of the file 
     public string FileName { get; set; } 
     public override string ToString() 
     { 
      return string.Format(@"FlatFileItem (Unzip FTPLineItem) => FileName:{0}", this.FileName); 
     } 
    } 


public class someclass { 
    public void somemethod(){ 
     try{ 

       //Throw exception code 

     } catch (Exception ex) 
        { 
         ex.Data["flatfile"] = Convert.ToString(flatfile); //Using data property 
         flatfile.HasErrors = true; //not there in above example 
         flatfile.Parent.AddErrorInfo(ex); //not there in above example 
         logger.Error(String.Format(ex.Message)); //not there in above example 

         throw (new Exception ("yourmsg",ex)); //if you want to do this 
        } 
    } 
} 
+0

我的觀點是你不應該嘗試自己格式化異常。而是依靠'Exception.ToString()',它將顯示關於內部異常的所有必要細節,在遠程邊界等處重新生成的異常。 – 2013-02-22 15:44:21

+0

對不起,我沒有完全得到這個問題。但在我的情況下,我不得不格式化,因爲我使用Exception.Data屬性來添加對象。這樣我就可以從深層的函數棧中看到所有的業務對象。我不確定Exception.ToString()是否處理​​異常類的數據對象 – dekdev 2013-02-22 15:48:54