附加.net调试器,同时仍然提供有用的死亡日志记录

时间:2008-10-17 10:07:50

标签: c# debugging stack-trace

我想在我的代码的根目录中使用某种catch-all异常机制,因此当应用程序意外终止时,我仍然可以提供一些有用的日志记录。

的内容
static void Main () {
    if (Debugger.IsAttached)
        RunApp();
    else {
        try {
            RunApp();
        }
        catch (Exception e) {
            LogException(e);
            throw;
        }
    }
 }

虽然这一切都运行正常,但问题是我想在引发异常后附加调试器。

由于异常会转义到运行时,因此窗口会提示附加visual studio,但由于已经重新抛出,所以堆栈中的所有本地和参数都已丢失。

是否仍然记录这些异常,同时仍提供附加调试器并保留所有有用信息的方法?

7 个答案:

答案 0 :(得分:15)

正如Paul Betts已经提到的,你可能最好使用AppDomain.UnhandledException事件而不是try / catch块。

在UnhandledException事件处理程序中,您可以记录/显示异常,然后提供调试选项,例如显示一个表单,其中包含要忽略,调试或退出的异常详细信息和按钮。

如果用户选择调试选项,请调用System.Diagnostics.Debugger.Break(),允许用户在完整的调用堆栈仍然可用的情况下附加他们想要的调试器。

显然,你可以为你知道你不会将调试器附加到的任何构建禁用此选项。

class Program
{
    static void Main()
    {
        AppDomain.CurrentDomain.UnhandledException += ExceptionHandler;

        RunApp();
    }

    static void ExceptionHandler(object sender, UnhandledExceptionEventArgs e)
    {
        Console.WriteLine(e.ExceptionObject);
        Console.WriteLine("Do you want to Debug?");
        if (Console.ReadLine().StartsWith("y"))
            Debugger.Break();
    }

    static void RunApp()
    {
        throw new Exception();
    }
}

答案 1 :(得分:2)

可怕的hacky但是没有运行时挂钩(我知道没有)是到达你扔掉的堆栈帧的唯一方法....

所有已知终端抛出的异常都必须在其构造函数中包含以下内容:

#if DEBUG
System.Diagnostics.Debugger.Launch()
#endif

这将提供一个对话框,允许用户提供相关的调试器或选择否,不会发生任何调试(无论哪种方式,异常将完成构建然后抛出。这显然只适用于您控制源的异常。< / p>

我不建议这样做,在附带调试器的调试版本中,您可以选择在异常抛出时获得“First Chance”中断,这通常应该足以满足您的需求。

另一个选择是在异常抛出站点以编程方式开始生成小型转储,然后可以使用像windbg这样的工具检查这些数据,但不会过多地干扰异常展开后异常行为。

异常到达你的所有陷阱的行为正是你不想要的堆栈展开,抱歉。 如果你对C ++感到满意并且喜欢它,那么你可以构建一个小的(但很复杂的)单声道的分支,这会导致所有异常触发调试器。或者只是重建单声道的BCL异常类来执行与上面详述相同的操作。

答案 2 :(得分:1)

为什么不让它崩溃然后注册接收来自Microsoft的Windows错误报告?查看http://msdn.microsoft.com/en-us/isv/bb190483.aspx了解详细信息。

如果您不想这样做,可以使用IsDebuggerPresent函数(http://msdn.microsoft.com/en-us/library/ms680345.aspx),如果结果为False,而不是将代码包装在try-catch中,请添加一个事件处理程序AppDomain.UnhandledException事件(http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

答案 3 :(得分:0)

不应该简单地做一个

Exception e1 = e;
LogException(e);
throw(e1);
在catch内部执行操作(至少可以检查外部异常)?

答案 4 :(得分:0)

如果您严格使用调试模式进行开发和发布模式进行部署,则可以尝试使用System.Diagnostics.Debugger类。

catch (Exception e) {
#if DEBUG
            System.Diagnostics.Debugger.Launch()
#endif
            LogException(e);
            throw;
        }

答案 5 :(得分:0)

您可以通过写入跟踪日志来获取异常信息:

        private static void Main(string[] args)
    {
        try
        {
            // ...
        }
        catch (Exception exception)
        {
            System.Diagnostics.Trace.Write(exception);
            #if DEBUG
            System.Diagnostics.Trace.Write("Waiting 20 seconds for debuggers to attach to process.");
            System.Threading.Thread.Sleep(20000);
            System.Diagnostics.Trace.Write("Continue with process...");
            #endif
            throw;
        }
    }

使用DebugView显示跟踪日志。停止线程几秒钟将使您有时间将调试器附加到进程而不会丢失原始异常。

答案 6 :(得分:0)

如果没有全局事件可以解决,那么您可以尝试将错误捕获放在软件处理的任何事件中。这些的简易性取决于应用程序的复杂性。使用.NET框架编写的许多应用程序都是为处理事件而编写的,无论是传统应用程序还是Web应用程序。通过将钩子放在事件本身中,您应该能够将信息保存在所需的堆栈中。