2009-07-15 17 views
35

Wiem, jak generować pliki Crash Dump za pomocą ADPlus lub DebugDiag, ale zastanawiam się, czy istnieje sposób, aby to zrobić na komputerze klienta bez instalowania tych narzędzi ... konkretnie, chciałbym lubię móc skonfigurować moją aplikację (na przykład przy użyciu wartości rejestru), aby wygenerować zrzut awaryjny w przypadku krytycznej awarii. Dokładniej, muszę móc to zrobić z aplikacji C#, ale nie mam nic przeciwko P/Invoke'ing w razie potrzeby. Dzięki!Generowanie automatycznych zrzutów systemu .NET

Odpowiedz

14

Należy pamiętać, że tworzenie minizrzutu z wnętrza procesu "awaryjnego" (lub nawet wątku) nie jest proste lub może być niedokładne (dotyczy również uwag funkcji).

Poza tym, jeśli twój proces jest w takim gniewie, że możesz potrzebować napisać zrzut awaryjny, cała sytuacja jest zazwyczaj tak mocno podświetlona, ​​że ​​nawet próba utworzenia zrzutu awaryjnego może spowodować kolejną awarię (sytuacje takie jak odłożenie na bok - ale te mogą być jeszcze trudniejsze do "złapania" z obecnego procesu).

"Najlepszą rzeczą, którą możesz zrobić, jeśli nie możesz zainstalować oddzielnych aplikacji w systemach klienta, jest uruchomienie zewnętrznego procesu (który może również zawieść w krytycznych sytuacjach!) I niech to spowoduje awarię awarii z twojego obecnego procesu (patrz Superassert.NET from John Robbins). Możesz nawet posunąć się tak daleko, aby umieścić zewnętrzny plik binarny w zasobach aplikacji, rozpakuj go na starcie (aby zminimalizować awarię krytycznych wersji) na dysku (jeśli się odważysz).

+0

Podczas gdy mądrość jest ostrożna w działaniu podczas awarii aplikacji, dobrze jest także pomyśleć o tym, co robi aplikacja. Jeśli jesteś w produkcji, bądź BARDZO ostrożny - jednak, jeśli piszesz aplikację przetwarzania wsadowego, prawie na pewno lepiej jest utworzyć minizrzutu do celów debugowania później zamiast konieczności czasochłonnego repro. Porady ogólne: zawsze rozważ swoją sytuację przed podjęciem decyzji projektowej i bądź ostrożny wobec zbyt szerokiej porady. – jhclark

+0

@jhclark Całkowicie _nie mam nic przeciwko pisaniu mini/crash-dump; w rzeczywistości, _proper_ dump jest najlepszym narzędziem analizy post mortem, o które można prosić. Ale nie chodzi o to, aby zapisać go z procesu ofiary. Ponieważ jest to ogólnie niewiarygodne. Posiadanie jakiegoś zewnętrznego procesu stróżującego jest drogą do zrobienia (nawet coś takiego jak Sysinternals procdump może zrobić w sytuacjach wewnętrznych). IMHO jest prawdziwe bez względu na rodzaj aplikacji lub próbę osiągnięcia. –

0

W zależności od rodzaju potrzebnych informacji można dodać procedurę obsługi zdarzenia AppDomain.UnhandledException? (Wiem, że nie jest to dokładnie to, czego szukasz, ale jest to zdecydowanie dostępne na komputerach klienckich.)

0

Czy korzystasz z systemu logowania, takiego jak log4net? Zwykle wyłączasz komunikaty poziomu debugowania dla wydania. Możesz jednak pomyśleć o napisaniu specjalnego appendera, który loguje się do pliku tylko w niektórych przypadkach (np. Awarii). Ten program zapisuje najpierw w pamięci podręcznej tylko pierścień, który może być zapisany do pliku, później - uruchamiany na przykład przez wyjątek, jak sugeruje 280Z28.

+0

Mini zrzut jest ** sposób ** bardziej pomocny niż logi. Przechwytuje kompletny stan aplikacji, w tym samym momencie, gdy zostanie rzucony nieprzechwycony wyjątek. Możesz go załadować do debuggera i uzyskać pełną symboliczną informację, wygodnie powiązaną z kodem źródłowym, pełną ścieżkę śledzenia wszystkich wątków, dokładną lokalizację usterki, informacje o załadowanych modułach, pamięć i dowolną liczbę niestandardowych informacji, które chcesz dodać . – IInspectable

5

Można wywołać funkcję dbghelp.dll w wydarzeniu AppDomain.UnhandledException.

W tym zdarzeniu można zrzucić dziennik danych wyjątków .NET i zapisać minidump do pliku.

Istnieje również thread on the MSDN forums, który opisuje podpis P/Invoke i właściwe użycie.

+1

Nie, [nie można tego bezpiecznie zrobić] (http://stackoverflow.com/questions/1134048/generating-net-crash-dumps-automatically/1135666#comment57477239_1237097). 'MiniDumpWriteDump' ** musi ** zostać wywołany z oddzielnego procesu. – IInspectable

6

Myślę, że jeśli twoja aplikacja zostanie podtworzona, to równie dobrze możesz zrobić ujęcie w pliku mini zrzutu, a co najgorszego, co się stanie, aplikacja się zawiesi? I tak to się dzieje, więc równie dobrze możesz spróbować.
Kod w urządzeniu MSDN forum mentioned by VoiDed wydaje się dość solidny. Potrzebowałem wersję VB.Net tak oto wersję VB dla każdego, kto może jej potrzebować:

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 

tylko upewnij się solidnie eception obsługiwać połączenia do niego i powinno być stosunkowo bezpieczne.

+2

* "Co najgorszego, co się stanie, twoja aplikacja ulegnie awarii?" * - To nie jest najgorsze, co może się zdarzyć. Znacznie gorszy scenariusz polegałby na tym, że wywołanie 'MiniDumpWriteDump' zakleszczyło twój proces i uniemożliwiło jego zakończenie. Jedną z pierwszych rzeczy, które robi MiniDumpWriteDump, jest zawieszenie wszystkich wątków w procesie. Jeśli nie masz szczęścia, jeden z tych wątków znajdował się w połowie przydzielania pamięci sterty. A gdy 'MiniDumpWriteDump' spróbuje przydzielić pamięć sterty, będzie bez końca czekać na zwolnienie blokady, ale jest trzymane przez zawieszony wątek. Nie możesz bezpiecznie wykonać tego procesu. – IInspectable

+0

Czy możesz zabić proces w tym stanie? Jeśli działa to w 99% wypadków i zakleszczeń w 1%, gdzie wszystko, co musi zrobić użytkownik, to wymuszenie zabójstwa Myślę, że jest to uczciwy handel, zależne od okoliczności. Czy uruchomiłbym nowy proces z powodu awarii procesu? – jcmcbeth

9

Można skonfigurować system Windows Error Reporting (WER), aby utworzyć zrzut awaryjny w określonym katalogu używając następującego skryptu rejestru:

 
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 

Zrzut trafi do katalogu C: \ Zrzuca z nazwą, która odzwierciedla nazwa procesu, który się zawiesił. DumpType = 2 daje pełny zrzut pamięci. DumpType = 1 daje mini zrzut. Na komputerach 64-bitowych nie ma potrzeby umieszczania ich w węzłach Wow32.WER używa tylko klucza rejestru innego niż WOW określonego powyżej.

W zależności od rodzaju awarii ta metoda może nie działać. Muszę jeszcze dowiedzieć się, dlaczego i jakich typów awarii się nie złapie. Ktoś?

+2

Jak wspomniano tutaj (http://msdn.microsoft.com/en-us/library/bb787181(VS.85).aspx) Nie wiem, czy to działa dla kodu zarządzanego. – uli78

+0

"Aplikacje obsługujące własne niestandardowe raporty o awariach, w tym aplikacje .NET, nie są obsługiwane przez tę funkcję" –

+3

Próbowałem tego i ** działa dla kodu zarządzanego ** - w moim przypadku testowym było to framework 4.5 . Ale musiałem użyć następującej instrukcji w mojej aplikacji .net: Application.SetUnhandledExceptionMode (UnhandledExceptionMode.ThrowException); –

Powiązane problemy