bug 399341 - add crashreporter log file. r=bsmedberg
authorted.mielczarek@gmail.com
Fri, 09 Nov 2007 08:46:34 -0800
changeset 7749 f15ea805174bdcf46bac252f861df7fc5c7ec0e2
parent 7748 26f139687c44ba4bd3c46cffa1b73da14f930eca
child 7750 85d064fbd88c8282363bc13e187d30f2d3ebe8b0
push idunknown
push userunknown
push dateunknown
reviewersbsmedberg
bugs399341
milestone1.9b2pre
bug 399341 - add crashreporter log file. r=bsmedberg
toolkit/crashreporter/client/crashreporter.cpp
toolkit/crashreporter/client/crashreporter.h
toolkit/crashreporter/client/crashreporter_linux.cpp
toolkit/crashreporter/client/crashreporter_osx.mm
toolkit/crashreporter/client/crashreporter_win.cpp
--- a/toolkit/crashreporter/client/crashreporter.cpp
+++ b/toolkit/crashreporter/client/crashreporter.cpp
@@ -41,35 +41,39 @@
 
 #ifdef _MSC_VER
 // Disable exception handler warnings.
 # pragma warning( disable : 4530 )
 #endif
 
 #include <fstream>
 #include <sstream>
+#include <memory>
+#include <time.h>
 
 using std::string;
 using std::istream;
 using std::ifstream;
 using std::istringstream;
 using std::ostringstream;
 using std::ostream;
 using std::ofstream;
 using std::vector;
+using std::auto_ptr;
 
 namespace CrashReporter {
 
 StringTable  gStrings;
 string       gSettingsPath;
 int          gArgc;
 char**       gArgv;
 
-static string       gDumpFile;
-static string       gExtraFile;
+static auto_ptr<ofstream> gLogStream(NULL);
+static string             gDumpFile;
+static string             gExtraFile;
 
 static string kExtraDataExtension = ".extra";
 
 void UIError(const string& message)
 {
   string errorMessage;
   if (!gStrings[ST_CRASHREPORTERERROR].empty()) {
     char buf[2048];
@@ -194,16 +198,34 @@ bool WriteStringsToFile(const string& pa
     success = WriteStrings(*f, header, strings, escape);
     f->close();
   }
 
   delete f;
   return success;
 }
 
+void LogMessage(const std::string& message)
+{
+  if (gLogStream.get()) {
+    char date[64];
+    time_t tm;
+    time(&tm);
+    if (strftime(date, sizeof(date) - 1, "%c", localtime(&tm)) == 0)
+        date[0] = '\0';
+    (*gLogStream) << "[" << date << "] " << message << std::endl;
+  }
+}
+
+static void OpenLogFile()
+{
+  string logPath = gSettingsPath + UI_DIR_SEPARATOR + "submit.log";
+  gLogStream.reset(UIOpenWrite(logPath.c_str(), true));
+}
+
 static bool ReadConfig()
 {
   string iniPath;
   if (!UIGetIniPath(iniPath))
     return false;
 
   if (!ReadStringsFromFile(iniPath, gStrings, true))
     return false;
@@ -428,16 +450,18 @@ int main(int argc, char** argv)
       }
     }
 
     if (gSettingsPath.empty() || !UIEnsurePathExists(gSettingsPath)) {
       UIError(gStrings[ST_ERROR_NOSETTINGSPATH]);
       return 0;
     }
 
+    OpenLogFile();
+
     if (!UIFileExists(gDumpFile)) {
       UIError(gStrings[ST_ERROR_DUMPFILEEXISTS]);
       return 0;
     }
 
     string pendingDir = gSettingsPath + UI_DIR_SEPARATOR + "pending";
     if (!MoveCrashData(pendingDir, gDumpFile, gExtraFile)) {
       return 0;
--- a/toolkit/crashreporter/client/crashreporter.h
+++ b/toolkit/crashreporter/client/crashreporter.h
@@ -83,17 +83,17 @@ namespace CrashReporter {
   bool WriteStrings(std::ostream& out,
                     const std::string& header,
                     StringTable& strings,
                     bool escape);
   bool WriteStringsToFile(const std::string& path,
                           const std::string& header,
                           StringTable& strings,
                           bool escape);
-
+  void LogMessage(const std::string& message);
 }
 
 //=============================================================================
 // implemented in the platform-specific files
 //=============================================================================
 
 bool UIInit();
 void UIShutdown();
@@ -113,15 +113,15 @@ bool UIGetIniPath(std::string& path);
 bool UIGetSettingsPath(const std::string& vendor,
                        const std::string& product,
                        std::string& settingsPath);
 bool UIEnsurePathExists(const std::string& path);
 bool UIFileExists(const std::string& path);
 bool UIMoveFile(const std::string& oldfile, const std::string& newfile);
 bool UIDeleteFile(const std::string& oldfile);
 std::ifstream* UIOpenRead(const std::string& filename);
-std::ofstream* UIOpenWrite(const std::string& filename);
+std::ofstream* UIOpenWrite(const std::string& filename, bool append=false);
 
 #ifdef _MSC_VER
 # pragma warning( pop )
 #endif
 
 #endif
--- a/toolkit/crashreporter/client/crashreporter_linux.cpp
+++ b/toolkit/crashreporter/client/crashreporter_linux.cpp
@@ -144,16 +144,24 @@ static gboolean SendReportIdle(gpointer 
   string response;
   bool success = google_breakpad::HTTPUpload::SendRequest
     (gSendURL,
      gQueryParameters,
      gDumpFile,
      "upload_file_minidump",
      "", "",
      &response);
+  if (success) {
+    LogMessage("Crash report submitted successfully");
+  }
+  else {
+    //XXX: HTTPUpload::SendRequest eats the curl error code, filed
+    // http://code.google.com/p/google-breakpad/issues/detail?id=221
+    LogMessage("Crash report submission failed");
+  }
   SendCompleted(success, response);
 
   if (!success) {
     GtkWidget* errorDialog =
       gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
                              GTK_MESSAGE_ERROR,
                              GTK_BUTTONS_CLOSE,
                              "%s", gStrings[ST_SUBMITFAILED].c_str());
@@ -529,12 +537,14 @@ bool UIDeleteFile(const string& file)
   return (unlink(file.c_str()) != -1);
 }
 
 std::ifstream* UIOpenRead(const string& filename)
 {
   return new std::ifstream(filename.c_str(), std::ios::in);
 }
 
-std::ofstream* UIOpenWrite(const string& filename)
+std::ofstream* UIOpenWrite(const string& filename, bool append) // append=false
 {
-  return new std::ofstream(filename.c_str(), std::ios::out);
+  return new std::ofstream(filename.c_str(),
+                           append ? std::ios::out | std::ios::app
+                                  : std::ios::out);
 }
--- a/toolkit/crashreporter/client/crashreporter_osx.mm
+++ b/toolkit/crashreporter/client/crashreporter_osx.mm
@@ -38,19 +38,21 @@
 
 #import <Cocoa/Cocoa.h>
 #import <CoreFoundation/CoreFoundation.h>
 #include "crashreporter.h"
 #include "crashreporter_osx.h"
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <fcntl.h>
+#include <sstream>
 
 using std::string;
 using std::vector;
+using std::ostringstream;
 
 using namespace CrashReporter;
 
 static NSAutoreleasePool* gMainPool;
 static CrashReporterUI* gUI = 0;
 static string gDumpFile;
 static StringTable gQueryParameters;
 static string gSendURL;
@@ -374,18 +376,27 @@ static bool RestartApplication()
 {
   NSHTTPURLResponse* response = [mPost response];
 
   bool success;
   string reply;
   if (!data || !response || [response statusCode] != 200) {
     success = false;
     reply = "";
+
+    // if data is nil, we probably logged an error in uploadThread
+    if (data != nil && response != nil) {
+      ostringstream message;
+      message << "Crash report submission failed: server returned status "
+              << [response statusCode];
+      LogMessage(message.str());
+    }
   } else {
     success = true;
+    LogMessage("Crash report submitted successfully");
 
     NSString* encodingName = [response textEncodingName];
     NSStringEncoding encoding;
     if (encodingName) {
       encoding = CFStringConvertEncodingToNSStringEncoding(
         CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName));
     } else {
       encoding = NSISOLatin1StringEncoding;
@@ -403,18 +414,22 @@ static bool RestartApplication()
   }
 }
 
 -(void)uploadThread:(id)post
 {
   NSAutoreleasePool* autoreleasepool = [[NSAutoreleasePool alloc] init];
   NSError* error = nil;
   NSData* data = [post send: &error];
-  if (error)
+  if (error) {
     data = nil;
+    NSString* errorDesc = [error localizedDescription];
+    string message = [errorDesc UTF8String];
+    LogMessage("Crash report submission failed: " + message);
+  }
 
   [self performSelectorOnMainThread: @selector(uploadComplete:)
         withObject: data
         waitUntilDone: YES];
 
   [autoreleasepool release];
 }
 
@@ -537,12 +552,14 @@ bool UIDeleteFile(const string& file)
   return (unlink(file.c_str()) != -1);
 }
 
 std::ifstream* UIOpenRead(const string& filename)
 {
   return new std::ifstream(filename.c_str(), std::ios::in);
 }
 
-std::ofstream* UIOpenWrite(const string& filename)
+std::ofstream* UIOpenWrite(const string& filename, bool append) // append=false
 {
-  return new std::ofstream(filename.c_str(), std::ios::out);
+  return new std::ofstream(filename.c_str(),
+                           append ? std::ios::out | std::ios::app
+                                  : std::ios::out);
 }
--- a/toolkit/crashreporter/client/crashreporter_win.cpp
+++ b/toolkit/crashreporter/client/crashreporter_win.cpp
@@ -220,16 +220,48 @@ static void SetStringKey(const wchar_t* 
   if (RegCreateKey(HKEY_CURRENT_USER, key, &hRegKey) == ERROR_SUCCESS) {
     RegSetValueEx(hRegKey, valueName, 0, REG_SZ,
                   (LPBYTE)value.c_str(),
                   (value.length() + 1) * sizeof(wchar_t));
     RegCloseKey(hRegKey);
   }
 }
 
+static string FormatLastError()
+{
+  DWORD err = GetLastError();
+  LPWSTR s;
+  string message = "Crash report submision failed: ";
+  // odds are it's a WinInet error
+  HANDLE hInetModule = GetModuleHandle(L"WinInet.dll");
+  if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                   FORMAT_MESSAGE_FROM_SYSTEM |
+                   FORMAT_MESSAGE_FROM_HMODULE,
+                   hInetModule,
+                   err,
+                   0,
+                   (LPWSTR)&s,
+                   0,
+                   NULL) != 0) {
+    message += WideToUTF8(s, NULL);
+    LocalFree(s);
+    // strip off any trailing newlines
+    string::size_type n = message.find_last_not_of("\r\n");
+    if (n < message.size() - 1) {
+      message.erase(n+1);
+    }
+  }
+  else {
+    char buf[64];
+    sprintf(buf, "Unknown error, error code: 0x%08x", err);
+    message += buf;
+  }
+  return message;
+}
+
 // Gets the position of a window relative to another window's client area
 static void GetRelativeRect(HWND hwnd, HWND hwndParent, RECT* r)
 {
   GetWindowRect(hwnd, r);
   ScreenToClient(hwndParent, (POINT*)&(r->left));
   ScreenToClient(hwndParent, (POINT*)&(r->right));
 }
 
@@ -287,23 +319,33 @@ static void ReflowDialog(HWND hwndDlg, i
 
 static DWORD WINAPI SendThreadProc(LPVOID param)
 {
   bool finishedOk;
   SendThreadData* td = (SendThreadData*)param;
 
   if (td->sendURL.empty()) {
     finishedOk = false;
+    LogMessage("No server URL, not sending report");
   } else {
     google_breakpad::CrashReportSender sender(L"");
     finishedOk = (sender.SendCrashReport(td->sendURL,
                                          td->queryParameters,
                                          td->dumpFile,
                                          &td->serverResponse)
                   == google_breakpad::RESULT_SUCCEEDED);
+    if (finishedOk) {
+      LogMessage("Crash report submitted successfully");
+    }
+    else {
+      // get an error string and print it to the log
+      //XXX: would be nice to get the HTTP status code here, filed:
+      // http://code.google.com/p/google-breakpad/issues/detail?id=220
+      LogMessage(FormatLastError());
+    }
   }
 
   PostMessage(td->hDlg, WM_UPLOADCOMPLETE, finishedOk ? 1 : 0, 0);
 
   return 0;
 }
 
 static void EndCrashReporterDialog(HWND hwndDlg, int code)
@@ -834,25 +876,27 @@ ifstream* UIOpenRead(const string& filen
   file->open(UTF8ToWide(filename).c_str(), ios::in);
 #else  // _MSC_VER >= 1400
   ifstream* file = new ifstream(_wfopen(UTF8ToWide(filename).c_str(), L"r"));
 #endif  // _MSC_VER >= 1400
 
   return file;
 }
 
-ofstream* UIOpenWrite(const string& filename)
+ofstream* UIOpenWrite(const string& filename, bool append) // append=false
 {
   // adapted from breakpad's src/common/windows/http_upload.cc
 
   // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a
   // wchar_t* filename, so use _wfopen directly in that case.  For VC8 and
   // later, _wfopen has been deprecated in favor of _wfopen_s, which does
   // not exist in earlier versions, so let the ifstream open the file itself.
 #if _MSC_VER >= 1400  // MSVC 2005/8
   ofstream* file = new ofstream();
-  file->open(UTF8ToWide(filename).c_str(), ios::out);
+  file->open(UTF8ToWide(filename).c_str(), append ? ios::out | ios::app
+                                                  : ios::out);
 #else  // _MSC_VER >= 1400
-  ofstream* file = new ofstream(_wfopen(UTF8ToWide(filename).c_str(), L"w"));
+  ofstream* file = new ofstream(_wfopen(UTF8ToWide(filename).c_str(),
+                                        append ? L"a" : L"w"));
 #endif  // _MSC_VER >= 1400
 
   return file;
 }