From 923827966c33c20f9ca9206ae202cf78e0f3f912 Mon Sep 17 00:00:00 2001 From: Leland Lucius Date: Sat, 18 Apr 2015 05:06:28 -0500 Subject: [PATCH] Add debug report (crash report) to Help menu This captures crashes on Windows along with the stack backtrace. On Linux (fedora 21 at least), the necessary function to enable capture is not included in the system wx libs. But, a self built version works fine and capture the backtrace, so I'm assuming other distros will probably work as well. On OSX, the crashes are caught, but it does not include the backtrace. But, really, the backtraces aren't all that useful in a release build since we don't ship with debug symbols and optimization plays havoc with proper backtraces anyway. The real benefit will be for the support folks as they can now get consistent info from user by asking the to generate a report from the "Help->Generate Support Data" menu item. --- src/AudacityApp.cpp | 71 ++++++++++++++++++++++++++++++++++++++++-- src/AudacityApp.h | 9 ++++++ src/AudacityLogger.cpp | 7 +++++ src/AudacityLogger.h | 6 ++++ src/Experimental.h | 7 +++++ src/Menus.cpp | 21 +++++++++++++ src/Menus.h | 3 ++ 7 files changed, 122 insertions(+), 2 deletions(-) diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp index fe88e468c..9787629c5 100644 --- a/src/AudacityApp.cpp +++ b/src/AudacityApp.cpp @@ -99,6 +99,12 @@ It handles initialization and termination by subclassing wxApp. #include "import/Import.h" +#if defined(EXPERIMENTAL_CRASH_REPORT) +#include +#include +#include +#endif + #ifdef EXPERIMENTAL_SCOREALIGN #include "effects/ScoreAlignDialog.h" #endif @@ -184,6 +190,13 @@ It handles initialization and termination by subclassing wxApp. # pragma comment(lib, "libvamp") # endif +# if defined(EXPERIMENTAL_CRASH_REPORT) +# if defined(__WXDEBUG__) +# pragma comment(lib, "wxmsw28ud_qa") +# else +# pragma comment(lib, "wxmsw28u_qa") +# endif +# endif #endif //(__WXMSW__) #include "../images/AudacityLogoWithName.xpm" @@ -925,7 +938,9 @@ bool AudacityApp::ShouldShowMissingAliasedFileWarning() AudacityLogger *AudacityApp::GetLogger() { - return static_cast(wxLog::GetActiveTarget()); + // Use dynamic_cast so that we get a NULL ptr if we haven't yet + // setup our logger. + return dynamic_cast(wxLog::GetActiveTarget()); } void AudacityApp::InitLang( const wxString & lang ) @@ -984,12 +999,55 @@ void AudacityApp::InitLang( const wxString & lang ) Internat::Init(); } -// Only used when checking plugins void AudacityApp::OnFatalException() { +#if defined(EXPERIMENTAL_CRASH_REPORT) + GenerateCrashReport(wxDebugReport::Context_Exception); +#endif + exit(-1); } +#if defined(EXPERIMENTAL_CRASH_REPORT) +void AudacityApp::GenerateCrashReport(wxDebugReport::Context ctx) +{ + wxDebugReportCompress rpt; + rpt.AddAll(ctx); + + wxFileName fn(FileNames::DataDir(), wxT("audacity.cfg")); + rpt.AddFile(fn.GetFullPath(), wxT("Audacity Configuration")); + rpt.AddFile(FileNames::PluginRegistry(), wxT("Plugin Registry")); + rpt.AddFile(FileNames::PluginSettings(), wxT("Plugin Settings")); + + AudacityLogger *logger = GetLogger(); + if (logger) + { + rpt.AddText(wxT("log.txt"), logger->GetLog(), wxT("Audacity Log")); + } + + bool ok = wxDebugReportPreviewStd().Show(rpt); + +#if defined(__WXMSW__) + wxEventLoop::SetCriticalWindow(NULL); +#endif + + if (ok && rpt.Process()) + { + wxTextEntryDialog dlg(NULL, + _("Report generated to:"), + _("Audacity Support Data"), + rpt.GetCompressedFileName(), + wxOK | wxCENTER); + dlg.ShowModal(); + + wxLogMessage(wxT("Report generated to: %s"), + rpt.GetCompressedFileName().c_str()); + + rpt.Reset(); + } +} +#endif + #if defined(__WXGTK__) // On wxGTK, there's a focus issue where dialogs do not automatically pass focus // to the first child. This means that you can use the keyboard to navigate within @@ -1014,6 +1072,15 @@ int AudacityApp::FilterEvent(wxEvent & event) } #endif +AudacityApp::AudacityApp() +{ +#if defined(EXPERIMENTAL_CRASH_REPORT) +#if defined(wxUSE_ON_FATAL_EXCEPTION) && wxUSE_ON_FATAL_EXCEPTION + wxHandleFatalExceptions(); +#endif +#endif +} + // The `main program' equivalent, creating the windows and returning the // main frame bool AudacityApp::OnInit() diff --git a/src/AudacityApp.h b/src/AudacityApp.h index b7898d57c..0dd78a5c8 100644 --- a/src/AudacityApp.h +++ b/src/AudacityApp.h @@ -31,6 +31,10 @@ #include "ondemand/ODTaskThread.h" #include "Experimental.h" +#if defined(EXPERIMENTAL_CRASH_REPORT) +#include +#endif + class IPCServ; class Importer; class CommandHandler; @@ -98,6 +102,7 @@ class BlockFile; class AudacityApp:public wxApp { public: + AudacityApp(); virtual bool OnInit(void); void FinishInits(); #if wxCHECK_VERSION(3, 0, 0) @@ -201,6 +206,10 @@ class AudacityApp:public wxApp { AudacityLogger *GetLogger(); +#if defined(EXPERIMENTAL_CRASH_REPORT) + void GenerateCrashReport(wxDebugReport::Context ctx); +#endif + #if defined(__WXGTK__) /** \brief This flag is set true when in a keyboard event handler. * Used to work around a hang issue with ibus (bug 154) */ diff --git a/src/AudacityLogger.cpp b/src/AudacityLogger.cpp index 08eebe677..3f64bb2e6 100644 --- a/src/AudacityLogger.cpp +++ b/src/AudacityLogger.cpp @@ -259,6 +259,13 @@ void AudacityLogger::Show(bool show) Flush(); } +#if defined(EXPERIMENTAL_CRASH_REPORT) +wxString AudacityLogger::GetLog() +{ + return mBuffer; +} +#endif + void AudacityLogger::OnCloseWindow(wxCloseEvent & WXUNUSED(e)) { #if defined(__WXMAC__) diff --git a/src/AudacityLogger.h b/src/AudacityLogger.h index 4301864dc..cc77de235 100644 --- a/src/AudacityLogger.h +++ b/src/AudacityLogger.h @@ -22,6 +22,8 @@ #include #include +#include "Experimental.h" + class AudacityLogger:public wxEvtHandler, public wxLog { public: AudacityLogger(); @@ -30,6 +32,10 @@ class AudacityLogger:public wxEvtHandler, public wxLog { void Show(bool show = true); void Destroy(); +#if defined(EXPERIMENTAL_CRASH_REPORT) + wxString GetLog(); +#endif + protected: virtual void Flush(); virtual void DoLogString(const wxChar *szString, time_t t); diff --git a/src/Experimental.h b/src/Experimental.h index 67b04ea34..62a0b70b2 100644 --- a/src/Experimental.h +++ b/src/Experimental.h @@ -178,4 +178,11 @@ // You must define EXPERIMENTAL_SCRUBBING_BASIC if you enable this: #define EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL + +// Define to include crash reporting +#define EXPERIMENTAL_CRASH_REPORT +#if !defined(wxUSE_DEBUGREPORT) || !wxUSE_DEBUGREPORT +#undef EXPERIMENTAL_CRASH_REPORT +#endif + #endif diff --git a/src/Menus.cpp b/src/Menus.cpp index b247cf3a1..7dadfaf14 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -36,6 +36,7 @@ simplifies construction of menu items. #include #include + #include #include #include @@ -117,6 +118,10 @@ simplifies construction of menu items. #include "CaptureEvents.h" #include "Snap.h" +#if defined(EXPERIMENTAL_CRASH_REPORT) +#include +#endif + #ifdef EXPERIMENTAL_SCOREALIGN #include "effects/ScoreAlignDialog.h" #include "audioreader.h" @@ -1061,6 +1066,10 @@ void AudacityProject::CreateMenusAndCommands() c->AddItem(wxT("Log"), _("Show &Log..."), FN(OnShowLog)); +#if defined(EXPERIMENTAL_CRASH_REPORT) + c->AddItem(wxT("CrashReport"), _("&Generate Support Data..."), FN(OnCrashReport)); +#endif + #ifndef __WXMAC__ c->AddSeparator(); #endif @@ -6175,6 +6184,18 @@ void AudacityProject::OnBenchmark() ::RunBenchmark(this); } +#if defined(EXPERIMENTAL_CRASH_REPORT) +void AudacityProject::OnCrashReport() +{ +// Change to "1" to test a real crash +#if 0 + char *p = 0; + *p = 1234; +#endif + wxGetApp().GenerateCrashReport(wxDebugReport::Context_Current); +} +#endif + void AudacityProject::OnScreenshot() { ::OpenScreenshotTools(); diff --git a/src/Menus.h b/src/Menus.h index 874011ce9..fef154b35 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -372,6 +372,9 @@ void OnManual(); void OnShowLog(); void OnHelpWelcome(); void OnBenchmark(); +#if defined(EXPERIMENTAL_CRASH_REPORT) +void OnCrashReport(); +#endif void OnScreenshot(); void OnAudioDeviceInfo();