Прикрепление отладчика .net при сохранении полезного ведения журнала при смерти - PullRequest
6 голосов
/ 17 октября 2008

Я бы хотел, чтобы в корне моего кода был какой-то механизм всеохватывающих исключений, поэтому, когда приложение неожиданно завершает работу, я все равно могу предоставить некоторую полезную запись в журнал.

Что-то вроде

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

Хотя все это работает нормально, моя проблема заключается в том, что я хочу подключить отладчик после возникновения исключения.

Поскольку исключение уходит в среду выполнения, Windows предложит подключить Visual Studio, за исключением того, что, поскольку оно было переброшено, все локальные объекты и параметры, расположенные дальше по стеку, были потеряны.

Есть ли возможность регистрировать эти исключения, в то же время предоставляя способ присоединить отладчик и сохранить всю полезную информацию?

Ответы [ 7 ]

15 голосов
/ 13 февраля 2009

Как уже упоминал Пол Беттс, вам лучше использовать событие 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();
    }
}
2 голосов
/ 12 февраля 2009

Ужасно хаки, но без хуков времени выполнения (я не знаю ни одного), единственный способ добраться до фрейма стека, куда вы бросаете из ....

Все исключения, о которых известно, что они генерируются терминалом, должны иметь в своем конструкторе следующее:

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

Это приведет к диалоговому окну, позволяющему пользователю либо указать соответствующий отладчик, либо выбрать «нет», и отладка не произойдет (в любом случае исключение будет завершено, а затем будет сгенерировано. Это очевидно работает только для исключений, источником которых вы управляете.

Я не рекомендую этого, в отладочной сборке с подключенным отладчиком вы можете просто выбрать «Первый шанс» на разрыв при исключении, который обычно должен быть достаточным для ваших нужд.

Другой вариант - начать программно генерировать мини-дампы на сайтах сгенерированных исключений, затем такие данные можно будет проверить позже с помощью такого инструмента, как windbg, но не слишком сильно повлиять на требуемое поведение исключения, разматывающего стек после.

Исключением, попадающим в ловушку, является именно тот стек, который вам не нужен, извините. Если вы знакомы с C ++ и хотите, вы можете создать небольшую (но сложную для понимания) форк моно, которая вызовет все исключения для запуска отладчика. В качестве альтернативы просто пересоберите исключительный класс BCL моно, чтобы сделать то же самое, что описано выше ..

1 голос
/ 12 февраля 2009

Почему бы просто не дать ему произойти сбой, а затем зарегистрироваться, чтобы получать отчеты об ошибках Windows от Microsoft? Проверьте 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)

0 голосов
/ 13 февраля 2009

Если ни одно из глобальных событий не сработает, то вы можете попробовать перехватить ошибку в любых событиях, которые обрабатывает ваша программа. Простота этого зависит от сложности ваших приложений. Многие приложения, написанные с использованием .NET Framework, предназначены для обработки событий, будь то традиционное приложение или веб-приложение. Поместив хуки в сами события, вы сможете сохранить информацию в нужном вам стеке.

0 голосов
/ 11 февраля 2009

Вы можете получить информацию об исключении, записав в журнал трассировки:

        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 для отображения журнала трассировки. Остановка потока на несколько секунд даст вам некоторое время, чтобы подключить отладчик к процессу без потери исходного исключения.

0 голосов
/ 17 октября 2008

Если вы строго используете режим отладки для разработки и режим выпуска для развертывания, вы можете попробовать использовать класс System.Diagnostics.Debugger.

catch (Exception e) {
#if DEBUG
            System.Diagnostics.Debugger.Launch()
#endif
            LogException(e);
            throw;
        }
0 голосов
/ 17 октября 2008

Не должно просто сделать

Exception e1 = e;
LogException(e);
throw(e1);

внутри уловка делает трюк (по крайней мере, вы можете изучить внешнее исключение)?

...