2009-07-15 2 views
35

Я знаю, как создавать файлы аварийного дампа с помощью ADPlus или DebugDiag, но мне интересно, есть ли способ сделать это на компьютере клиента без установки этих инструментов ... в частности, я бы например, чтобы настроить мое приложение (например, с помощью значения реестра) для создания дампа сбоя в случае критического сбоя. В частности, мне нужно иметь возможность сделать это из приложения C#, но я не против P/Invoke'ing, если это необходимо. Благодаря!Автоматическое создание аварийных отказов .NET

ответ

14

Обратите внимание, что создание мини-накопителя внутри самого «провального» процесса (или даже потока) само по себе не является тривиальным или может быть неточным (также примечания функции MiniDumpWriteDump).

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

«Лучшая вещь», которую вы можете сделать, если вы не можете установить отдельные приложения в системах вашего клиента, - это запустить внешний процесс (который также может произойти в критических ситуациях!), И пусть это создаст аварийный сигнал из вашего текущего процесса (см. Superassert.NET from John Robbins). Вы даже можете зайти так далеко, чтобы поместить внешний двоичный файл в свои ресурсы приложения, извлечь его оттуда при запуске (чтобы минимизировать сбой в критических ситуациях) на диск (если вы посмеете).

+0

Несмотря на то, что мудрость берет на себя заботу о ваших действиях во время сбоя приложения, также хорошо подумать о том, что делает ваше приложение. Если вы находитесь в производстве, будьте ОЧЕНЬ осторожны. Однако, если вы пишете приложение пакетной обработки, вам почти наверняка лучше создать мини-накопитель для целей отладки позже, вместо того, чтобы выполнять много времени. Общий совет: всегда рассматривайте свою ситуацию до принятия проектного решения и будьте осторожны с чрезмерно широкими советами. – jhclark

+0

@jhclark Я полностью не хочу писать мини-свалку; фактически _proper_ dump - лучший инструмент для анализа всплывающих сообщений, который можно запросить. Но дело не в том, чтобы писать это из процесса жертвы. Как правило, это ненадежно. Наличие какого-то внешнего сторожевого процесса - это способ пойти (даже что-то вроде Sysinternals procdump может сделать для внутренних ситуаций). ИМХО, что верно, независимо от вида приложения или того, что пытается выполнить. –

0

В зависимости от того, какую информацию вам нужно, вы можете добавить обработчик для события AppDomain.UnhandledException? (Я знаю, что это не совсем то, что вы ищете, но это определенно доступно на клиентских машинах.)

0

Используете ли вы систему ведения журнала, такую ​​как log4net? Обычно вы отключите сообщения уровня отладки для выпуска. Однако вы можете думать о написании специального приложения, который регистрируется в файле только в определенных случаях (например, сбой). Этот appender сначала записывает в буфер обмена только для памяти, который может быть записан в файл, а позже - вызван, например, обработчиком исключения, например, предложенным 280Z28.

+0

Мини-свалка ** путь ** более полезен, чем лог-файлы. Он фиксирует полное состояние приложения, в то самое время бросается неперехваченное исключение. Вы можете загрузить его в отладчике и получить полную символическую информацию, удобно связанную с исходным кодом, полной трассировкой стека всех потоков, точным местоположением ошибок, информацией о загруженных модулях, памятью и любым количеством пользовательской информации, которую вы хотите добавить , – IInspectable

5

Вы можете P/Invoke dbghelp.dllMiniDumpWriteDump функция в событии AppDomain.UnhandledException.

В этом случае вы можете сбросить журнал данных исключения .NET и записать файл minidump в файл.

Существует также thread on the MSDN forums, который описывает подпись P/Invoke и правильное использование.

+1

Нет, [вы не можете смело сделать это] (http://stackoverflow.com/questions/1134048/generating-net-crash-dumps-automatic/1135666#comment57477239_1237097). 'MiniDumpWriteDump' ** должен быть вызван из отдельного процесса. – IInspectable

6

Я думаю, что если ваше приложение закрыто, вы можете также сделать снимок при создании файла мини-дампа, что самое худшее из того, что произойдет, ваше приложение потерпит крах? Это все равно, так что вы можете попробовать.
Код в MSDN forum mentioned by VoiDed кажется довольно прочным. Мне нужна была версия VB.Net так вот версия VB для тех, кто может понадобиться:

Friend Class MiniDump 
    'Code converted from C# code found here: http://social.msdn.microsoft.com/Forums/en-US/clr/thread/6c8d3529-a493-49b9-93d7-07a3a2d715dc 

    Private Enum MINIDUMP_TYPE 
     MiniDumpNormal = 0 
     MiniDumpWithDataSegs = 1 
     MiniDumpWithFullMemory = 2 
     MiniDumpWithHandleData = 4 
     MiniDumpFilterMemory = 8 
     MiniDumpScanMemory = 10 
     MiniDumpWithUnloadedModules = 20 
     MiniDumpWithIndirectlyReferencedMemory = 40 
     MiniDumpFilterModulePaths = 80 
     MiniDumpWithProcessThreadData = 100 
     MiniDumpWithPrivateReadWriteMemory = 200 
     MiniDumpWithoutOptionalData = 400 
     MiniDumpWithFullMemoryInfo = 800 
     MiniDumpWithThreadInfo = 1000 
     MiniDumpWithCodeSegs = 2000 
    End Enum 

    <Runtime.InteropServices.DllImport("dbghelp.dll")> _ 
    Private Shared Function MiniDumpWriteDump(_ 
     ByVal hProcess As IntPtr, _ 
     ByVal ProcessId As Int32, _ 
     ByVal hFile As IntPtr, _ 
     ByVal DumpType As MINIDUMP_TYPE, _ 
     ByVal ExceptionParam As IntPtr, _ 
     ByVal UserStreamParam As IntPtr, _ 
     ByVal CallackParam As IntPtr) As Boolean 
    End Function 

    Friend Shared Sub MiniDumpToFile(ByVal fileToDump As String) 
     Dim fsToDump As IO.FileStream = Nothing 

     If (IO.File.Exists(fileToDump)) Then 
      fsToDump = IO.File.Open(fileToDump, IO.FileMode.Append) 
     Else 
      fsToDump = IO.File.Create(fileToDump) 
     End If 

     Dim thisProcess As Process = Process.GetCurrentProcess() 
     MiniDumpWriteDump(thisProcess.Handle, _ 
          thisProcess.Id, _ 
          fsToDump.SafeFileHandle.DangerousGetHandle(), _ 
          MINIDUMP_TYPE.MiniDumpNormal, _ 
          IntPtr.Zero, _ 
          IntPtr.Zero, _ 
          IntPtr.Zero) 
     fsToDump.Close() 
    End Sub 
End Class 

Просто убедитесь, что вы твердо eception обрабатывать вызовы к нему, и вы должны быть относительно безопасным.

+2

* «Что будет хуже всего, ваше приложение потерпит крах?» * - Это не самое худшее, что могло случиться. Еще хуже сценарий заключается в том, что вызов 'MiniDumpWriteDump' блокирует ваш процесс и предотвращает его завершение. Одна из первых вещей, которые MiniDumpWriteDump делает, - это приостановить все потоки в этом процессе. Если вам не повезло, один из этих потоков был посреди выделения памяти кучи. И когда 'MiniDumpWriteDump' пытается выделить кучную память, он будет бесконечно ждать, пока блокировка будет выпущена, но удерживается приостановленным потоком. Вы не можете безопасно делать это в процессе. – IInspectable

+0

Не могли бы вы убить процесс в этом состоянии? Если это работает в 99% случаев сбоев и тупиков в 1%, когда все, что нужно сделать пользователю, это принудительное убийство, я думаю, что это справедливый компромисс, зависящий от условий. Запустил бы новый процесс из разбившегося процесса? – jcmcbeth

9

Вы можете настроить Windows, отчетов об ошибках (WER), чтобы создать аварийный дамп в определенной директории, используя следующий сценарий реестра:

 
Windows Registry Editor Version 5.00 
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps] 
"DumpFolder"="C:\\Dumps" 
"DumpCount"=dword:00000064 
"DumpType"=dword:00000002 
"CustomDumpFlags"=dword:00000000 

Свалка войдет в C: \ Сплин с именем, которое отражает имя разбившегося процесса. DumpType = 2 дает полный дамп памяти. DumpType = 1 дает мини-свалку. На 64-битных машинах вам не нужно размещать их под узлами Wow32.WER использует только указанный выше раздел реестра не-WOW.

В зависимости от типа аварии этот способ может не работать. Мне еще предстоит выяснить, почему или какие типы сбоев он не улавливает. Кто угодно?

+2

Как упоминалось здесь (http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx) Я не уверен, что это работает для управляемого кода. – uli78

+0

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

+3

Я пробовал это, и это ** работает для управляемого кода ** - в моем тестовом случае это была рамка 4.5 , Но я должен был использовать следующий оператор в моем .net приложении: Application.SetUnhandledExceptionMode (UnhandledExceptionMode.ThrowException); –

Смежные вопросы