【问题标题】:How do I log exception information to allow troubleshooting?如何记录异常信息以进行故障排除?
【发布时间】:2012-08-07 13:21:42
【问题描述】:

我目前正在对 Windows 服务进行维护,并且在代码中的某些点有一些异常处理(例如,在来自计时器和其他外部事件的回调中):

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

记录异常信息有助于解决问题。但是,有时有趣的信息是内部异常,这使得很难确定问题的根本原因。例如,TypeInitializationException 可能很难理解。

是否有更好的方法来记录异常信息以进行故障排除?

【问题讨论】:

  • 尝试这个“回答你自己的问题”的东西。真正的目的是为了教育,因为我在许多代码库中都看到了这种有点低劣的日志记录风格。

标签: c# .net exception logging


【解决方案1】:

是否有更好的方法来记录异常信息以进行故障排除?

是的,有。不要“聪明”并使用ex.Messageex.StackTrace。只需使用ex.ToString()。它将递归到内部异常(如果需要,可以多级)并显示完整的堆栈跟踪。

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

举一个小例子,如果您创建一个类的实例,该实例在该类的静态构造函数中引发异常,您会得到这样的结果。此异常抛出将被包裹在 TypeInitializationException 中。

之前:

未处理的异常:“SomeClass”的类型初始化程序引发了异常。 在 SomeNamespace.SomeClass..ctor() 在 c:\ExceptionHandlingDemo.cs:line 34 中的 SomeNamespace.Callback()

不是很有帮助。很难确定出了什么问题。

之后:

未处理的异常: System.TypeInitializationException:“SomeClass”的类型初始化程序引发了异常。 ---> System.ArgumentException:已添加具有相同键的项目。 在 System.ThrowHelper.ThrowArgumentException(ExceptionResource 资源) 在 System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) 在 System.Collections.Generic.Dictionary`2.Add(TKey 键,TValue 值) 在 c:\ExceptionHandlingDemo.cs:line 43 中的 SomeNamespace.SomeClass..cctor() --- 内部异常堆栈跟踪结束 --- 在 SomeNamespace.SomeClass..ctor() 在 c:\ExceptionHandlingDemo.cs:line 34 中的 SomeNamespace.Callback()

现在您可以很容易地确定问题的根本原因是字典中的重复键,并将其精确定位到源文件中的第 43 行。

【讨论】:

  • +1:另外,ToString() 对于某些异常类型,包括额外的细节,Message 没有(我认为一些 FileLoadException 左右,包括关于失败的更多细节,但我现在不确定)。
【解决方案2】:

我不知道这是否会有所帮助,或者它的级别是否太高,但是您知道 Microsoft 的企业库吗? (http://msdn.microsoft.com/en-us/library/ff648951.aspx)。

其中有一个日志记录“应用程序块”,它有点像大锤,但最终非常强大/灵活。在完成了我想要的设置(所有配置驱动)的练习之后,这现在是我构建的 exerything 的标准。

特别是在例外情况下,我认为我根本不需要做太多事情来获取有意义的信息。

【讨论】:

    【解决方案3】:

    我不确定这是否会有所帮助。我写了这个 Utility 类来记录异常的所有信息,我使用 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
                        }
        }
    }
    

    【讨论】:

    • 我的意思是你不应该尝试自己格式化异常。而是依赖Exception.ToString(),它将显示有关内部异常、跨远程边界重新抛出的异常等所有必要的详细信息。
    • 很抱歉我没有完全理解这个问题。但就我而言,我必须格式化,因为我使用 Exception.Data 属性来添加对象。这样我就可以从 n 函数堆栈的深处看到所有业务对象。我不确定 Exception.ToString() 是否处理异常类的数据对象
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-22
    • 2010-09-08
    • 2022-06-28
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多