没有堆栈跟踪的异常 - 如何?

时间:2014-01-31 12:07:48

标签: c# exception stack-trace unhandled-exception

我们有一项服务会在应用程序域级别(通过Log4net)记录未处理的异常。

我们记录了:

  

2014-01-28 16:49:19,636 ERROR [49] FeedWrapperService - 未处理   System.NullReferenceException:未将对象引用设置为对象的实例。

此异常没有堆栈跟踪。如果不对异常对象做一些疯狂的事情,那怎么可能呢?

我们的处理代码:

AppDomain.CurrentDomain.UnhandledException += LogAnyExceptions;

private void LogAnyExceptions(object sender, UnhandledExceptionEventArgs e)
{
    log.Error("unhandled", (Exception)e.ExceptionObject);
    throw (Exception)e.ExceptionObject;
}

我觉得重新抛出这一点毫无意义,因为AppDomain无论如何都会随着进程而下降,但我认为这不会影响我们的情况。

Windows应用程序事件查看器也只显示此null引用异常且没有跟踪。

我已经测试了异常处理程序日志记录,它成功记录了堆栈跟踪和任何内部异常。如果它被我们的代码抛出,我们会看到堆栈跟踪。如果它被第三方c#库抛出,那么,我们再次看到至少一个方法的堆栈跟踪(无论是否是重新抛出的异常)。在这里,我们看到一个没有堆栈跟踪的托管异常。我不知道这是怎么可能的。

查看反编译的第三方库,它与非托管代码进行对话,并且引发此异常的事件可能在非托管域中,但是如果没有堆栈跟踪,这种情况怎么会导致托管的空引用异常呢?

此问题的原因是间歇性的。我们已经将这段代码在生产中运行了几个月,并且看过它曾经这样做过。这非常怪异。

普遍的共识是,应该将负责此类问题的系统推送到子进程中,这样我们就可以安全自动地处理问题并重新启动,但是知道发生了什么事情会很好。

修改以包含以下评论信息:

我的异常不是标准的重新抛出,因为堆栈跟踪是null或空。它没有重新投掷方法的名称。进一步挖掘,Exception类可以从序列化信息构造,看起来序列化信息可能包含堆栈跟踪的空字符串,并且可能创建它而不会导致其他错误。我想它可能来自那里,但我不知道它是如何起源的。

2 个答案:

答案 0 :(得分:10)

如果您收到异常但没有相应的堆栈跟踪,那么异常处理程序可能会在某个时刻评估异常并重新抛出异常。例如,如果您正在执行throw ex;,那么您将吃掉导致该点的堆栈跟踪。要保留现有的调用堆栈,只需throw; Throwing exceptions best practices

请注意,C#方式与Java语言的约定相反,您应该throw ex; Java引用:Best Practice: Catching and re-throwing Java Exceptions

答案 1 :(得分:5)

我更喜欢使用自定义异常来管理我的异常,如果在您的情况下您使用自己的异常,则可以在定义它们并覆盖堆栈跟踪时使用该类。 e.g:

public class YourCustomException: Exception
{
    public YourCustomException() : base() { } //constructor

    public override string StackTrace 
    {
        get { return "Message instead stacktrace"; }
    }
}