debugrpt.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name: debugrpt.cpp
  3. // Purpose: minimal sample showing wxDebugReport and related classes
  4. // Author: Vadim Zeitlin
  5. // Modified by:
  6. // Created: 2005-01-20
  7. // Copyright: (c) 2005 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
  8. // Licence: wxWindows licence
  9. ///////////////////////////////////////////////////////////////////////////////
  10. // ----------------------------------------------------------------------------
  11. // headers
  12. // ----------------------------------------------------------------------------
  13. #include "wx/app.h"
  14. #include "wx/log.h"
  15. #include "wx/frame.h"
  16. #include "wx/icon.h"
  17. #include "wx/menu.h"
  18. #include "wx/msgdlg.h"
  19. #include "wx/button.h"
  20. #include "wx/dcclient.h"
  21. #include "wx/datetime.h"
  22. #include "wx/ffile.h"
  23. #include "wx/filename.h"
  24. #include "wx/debugrpt.h"
  25. #if !wxUSE_DEBUGREPORT
  26. #error "This sample can't be built without wxUSE_DEBUGREPORT"
  27. #endif // wxUSE_DEBUGREPORT
  28. #if !wxUSE_ON_FATAL_EXCEPTION
  29. #error "This sample can't be built without wxUSE_ON_FATAL_EXCEPTION"
  30. #endif // wxUSE_ON_FATAL_EXCEPTION
  31. #ifndef wxHAS_IMAGES_IN_RESOURCES
  32. #include "../sample.xpm"
  33. #endif
  34. // ----------------------------------------------------------------------------
  35. // custom debug reporting class
  36. // ----------------------------------------------------------------------------
  37. // this is your custom debug reporter: it will use curl program (which should
  38. // be available) to upload the crash report to the given URL (which should be
  39. // set up by you)
  40. class MyDebugReport : public wxDebugReportUpload
  41. {
  42. public:
  43. MyDebugReport() : wxDebugReportUpload
  44. (
  45. wxT("http://your.url.here/"),
  46. wxT("report:file"),
  47. wxT("action")
  48. )
  49. {
  50. }
  51. protected:
  52. // this is called with the contents of the server response: you will
  53. // probably want to parse the XML document in OnServerReply() instead of
  54. // just dumping it as I do
  55. virtual bool OnServerReply(const wxArrayString& reply)
  56. {
  57. if ( reply.IsEmpty() )
  58. {
  59. wxLogError(wxT("Didn't receive the expected server reply."));
  60. return false;
  61. }
  62. wxString s(wxT("Server replied:\n"));
  63. const size_t count = reply.GetCount();
  64. for ( size_t n = 0; n < count; n++ )
  65. {
  66. s << wxT('\t') << reply[n] << wxT('\n');
  67. }
  68. wxLogMessage(wxT("%s"), s.c_str());
  69. return true;
  70. }
  71. };
  72. // another possibility would be to build email library from contrib and use
  73. // this class, after uncommenting it:
  74. #if 0
  75. #include "wx/net/email.h"
  76. class MyDebugReport : public wxDebugReportCompress
  77. {
  78. public:
  79. virtual bool DoProcess()
  80. {
  81. if ( !wxDebugReportCompress::DoProcess() )
  82. return false;
  83. wxMailMessage msg(GetReportName() + wxT(" crash report"),
  84. wxT("vadim@wxwindows.org"),
  85. wxEmptyString, // mail body
  86. wxEmptyString, // from address
  87. GetCompressedFileName(),
  88. wxT("crashreport.zip"));
  89. return wxEmail::Send(msg);
  90. }
  91. };
  92. #endif // 0
  93. // ----------------------------------------------------------------------------
  94. // helper functions
  95. // ----------------------------------------------------------------------------
  96. // just some functions to get a slightly deeper stack trace
  97. static void bar(const char *p)
  98. {
  99. char *pc = 0;
  100. *pc = *p;
  101. printf("bar: %s\n", p);
  102. }
  103. void baz(const wxString& s)
  104. {
  105. printf("baz: %s\n", (const char*)s.c_str());
  106. }
  107. void foo(int n)
  108. {
  109. if ( n % 2 )
  110. baz("odd");
  111. else
  112. bar("even");
  113. }
  114. // ----------------------------------------------------------------------------
  115. // main window
  116. // ----------------------------------------------------------------------------
  117. enum
  118. {
  119. DebugRpt_Quit = wxID_EXIT,
  120. DebugRpt_Crash = 100,
  121. DebugRpt_Current,
  122. DebugRpt_Paint,
  123. DebugRpt_Upload,
  124. DebugRpt_About = wxID_ABOUT
  125. };
  126. class MyFrame : public wxFrame
  127. {
  128. public:
  129. MyFrame();
  130. private:
  131. void OnQuit(wxCommandEvent& event);
  132. void OnReportForCrash(wxCommandEvent& event);
  133. void OnReportForCurrent(wxCommandEvent& event);
  134. void OnReportPaint(wxCommandEvent& event);
  135. void OnReportUpload(wxCommandEvent& event);
  136. void OnAbout(wxCommandEvent& event);
  137. void OnPaint(wxPaintEvent& event);
  138. // number of lines drawn in OnPaint()
  139. int m_numLines;
  140. wxDECLARE_NO_COPY_CLASS(MyFrame);
  141. wxDECLARE_EVENT_TABLE();
  142. };
  143. // ----------------------------------------------------------------------------
  144. // application class
  145. // ----------------------------------------------------------------------------
  146. // this is a usual application class modified to work with debug reporter
  147. //
  148. // basically just 2 things are necessary: call wxHandleFatalExceptions() as
  149. // early as possible and override OnFatalException() to create the report there
  150. class MyApp : public wxApp
  151. {
  152. public:
  153. // call wxHandleFatalExceptions here
  154. MyApp();
  155. // create our main window here
  156. virtual bool OnInit();
  157. // called when a crash occurs in this application
  158. virtual void OnFatalException();
  159. // this is where we really generate the debug report
  160. void GenerateReport(wxDebugReport::Context ctx);
  161. // if this function is called, we'll use MyDebugReport which would try to
  162. // upload the (next) generated debug report to its URL, otherwise we just
  163. // generate the debug report and leave it in a local file
  164. void UploadReport(bool doIt) { m_uploadReport = doIt; }
  165. private:
  166. bool m_uploadReport;
  167. wxDECLARE_NO_COPY_CLASS(MyApp);
  168. };
  169. IMPLEMENT_APP(MyApp)
  170. // ============================================================================
  171. // implementation
  172. // ============================================================================
  173. // ----------------------------------------------------------------------------
  174. // MyFrame
  175. // ----------------------------------------------------------------------------
  176. wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
  177. EVT_MENU(DebugRpt_Quit, MyFrame::OnQuit)
  178. EVT_MENU(DebugRpt_Crash, MyFrame::OnReportForCrash)
  179. EVT_MENU(DebugRpt_Current, MyFrame::OnReportForCurrent)
  180. EVT_MENU(DebugRpt_Paint, MyFrame::OnReportPaint)
  181. EVT_MENU(DebugRpt_Upload, MyFrame::OnReportUpload)
  182. EVT_MENU(DebugRpt_About, MyFrame::OnAbout)
  183. EVT_PAINT(MyFrame::OnPaint)
  184. wxEND_EVENT_TABLE()
  185. MyFrame::MyFrame()
  186. : wxFrame(NULL, wxID_ANY, wxT("wxWidgets Debug Report Sample"),
  187. wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE|wxDEFAULT_FRAME_STYLE)
  188. {
  189. m_numLines = 10;
  190. SetIcon(wxICON(sample));
  191. wxMenu *menuFile = new wxMenu;
  192. menuFile->Append(DebugRpt_Quit, wxT("E&xit\tAlt-X"));
  193. wxMenu *menuReport = new wxMenu;
  194. menuReport->Append(DebugRpt_Crash, wxT("Report for &crash\tCtrl-C"),
  195. wxT("Provoke a crash inside the program and create report for it"));
  196. menuReport->Append(DebugRpt_Current, wxT("Report for c&urrent context\tCtrl-U"),
  197. wxT("Create report for the current program context"));
  198. menuReport->Append(DebugRpt_Paint, wxT("Report for &paint handler\tCtrl-P"),
  199. wxT("Provoke a repeatable crash in wxEVT_PAINT handler"));
  200. menuReport->AppendSeparator();
  201. menuReport->AppendCheckItem(DebugRpt_Upload, wxT("Up&load debug report"),
  202. wxT("You need to configure a web server accepting debug report uploads to use this function"));
  203. wxMenu *menuHelp = new wxMenu;
  204. menuHelp->Append(DebugRpt_About, wxT("&About\tF1"));
  205. wxMenuBar *mbar = new wxMenuBar();
  206. mbar->Append(menuFile, wxT("&File"));
  207. mbar->Append(menuReport, wxT("&Report"));
  208. mbar->Append(menuHelp, wxT("&Help"));
  209. SetMenuBar(mbar);
  210. CreateStatusBar();
  211. Show();
  212. }
  213. void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
  214. {
  215. Close(true);
  216. }
  217. void MyFrame::OnReportForCrash(wxCommandEvent& WXUNUSED(event))
  218. {
  219. // this call is going to crash
  220. foo(32);
  221. foo(17);
  222. }
  223. void MyFrame::OnReportForCurrent(wxCommandEvent& WXUNUSED(event))
  224. {
  225. // example of manually generated report, this could be also
  226. // used in wxApp::OnAssert()
  227. wxGetApp().GenerateReport(wxDebugReport::Context_Current);
  228. }
  229. void MyFrame::OnReportPaint(wxCommandEvent& WXUNUSED(event))
  230. {
  231. // this will result in a crash in OnPaint()
  232. m_numLines = 0;
  233. // ensure it's called immediately
  234. Refresh();
  235. }
  236. void MyFrame::OnReportUpload(wxCommandEvent& event)
  237. {
  238. wxGetApp().UploadReport(event.IsChecked());
  239. }
  240. void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
  241. {
  242. wxMessageBox
  243. (
  244. wxT("wxDebugReport sample\n(c) 2005 Vadim Zeitlin <vadim@wxwindows.org>"),
  245. wxT("wxWidgets Debug Report Sample"),
  246. wxOK | wxICON_INFORMATION,
  247. this
  248. );
  249. }
  250. void MyFrame::OnPaint(wxPaintEvent& WXUNUSED(event))
  251. {
  252. wxPaintDC dc(this);
  253. const wxSize size = GetClientSize();
  254. for ( wxCoord x = 0; x < size.x; x += size.x/m_numLines )
  255. dc.DrawLine(x, 0, x, size.y);
  256. }
  257. // ----------------------------------------------------------------------------
  258. // MyApp
  259. // ----------------------------------------------------------------------------
  260. MyApp::MyApp()
  261. {
  262. // user needs to explicitly enable this
  263. m_uploadReport = false;
  264. // call this to tell the library to call our OnFatalException()
  265. wxHandleFatalExceptions();
  266. }
  267. bool MyApp::OnInit()
  268. {
  269. if ( !wxApp::OnInit() )
  270. return false;
  271. new MyFrame;
  272. return true;
  273. }
  274. void MyApp::OnFatalException()
  275. {
  276. GenerateReport(wxDebugReport::Context_Exception);
  277. }
  278. void MyApp::GenerateReport(wxDebugReport::Context ctx)
  279. {
  280. wxDebugReportCompress *report = m_uploadReport ? new MyDebugReport
  281. : new wxDebugReportCompress;
  282. // add all standard files: currently this means just a minidump and an
  283. // XML file with system info and stack trace
  284. report->AddAll(ctx);
  285. // you can also call report->AddFile(...) with your own log files, files
  286. // created using wxRegKey::Export() and so on, here we just add a test
  287. // file containing the date of the crash
  288. wxFileName fn(report->GetDirectory(), wxT("timestamp.my"));
  289. wxFFile file(fn.GetFullPath(), wxT("w"));
  290. if ( file.IsOpened() )
  291. {
  292. wxDateTime dt = wxDateTime::Now();
  293. file.Write(dt.FormatISODate() + wxT(' ') + dt.FormatISOTime());
  294. file.Close();
  295. }
  296. report->AddFile(fn.GetFullName(), wxT("timestamp of this report"));
  297. // can also add an existing file directly, it will be copied
  298. // automatically
  299. #ifdef __WXMSW__
  300. report->AddFile(wxT("c:\\autoexec.bat"), wxT("DOS startup file"));
  301. #else
  302. report->AddFile(wxT("/etc/motd"), wxT("Message of the day"));
  303. #endif
  304. // calling Show() is not mandatory, but is more polite
  305. if ( wxDebugReportPreviewStd().Show(*report) )
  306. {
  307. if ( report->Process() )
  308. {
  309. if ( m_uploadReport )
  310. {
  311. wxLogMessage(wxT("Report successfully uploaded."));
  312. }
  313. else
  314. {
  315. wxLogMessage(wxT("Report generated in \"%s\"."),
  316. report->GetCompressedFileName().c_str());
  317. report->Reset();
  318. }
  319. }
  320. }
  321. //else: user cancelled the report
  322. delete report;
  323. }