Merge pull request #9053 from electron/enable-crash-reporter-upload-windows
Pass `uploadToServer` option to windows crash reporter
This commit is contained in:
		
				commit
				
					
						8a01ebef63
					
				
			
		
					 6 changed files with 109 additions and 10 deletions
				
			
		| 
						 | 
				
			
			@ -179,7 +179,7 @@ void CrashReporterWin::InitBreakpad(const std::string& product_name,
 | 
			
		|||
      google_breakpad::ExceptionHandler::HANDLER_ALL,
 | 
			
		||||
      kSmallDumpType,
 | 
			
		||||
      pipe_name.c_str(),
 | 
			
		||||
      GetCustomInfo(product_name, version, company_name)));
 | 
			
		||||
      GetCustomInfo(product_name, version, company_name, upload_to_server)));
 | 
			
		||||
 | 
			
		||||
  if (!breakpad_->IsOutOfProcess())
 | 
			
		||||
    LOG(ERROR) << "Cannot initialize out-of-process crash handler";
 | 
			
		||||
| 
						 | 
				
			
			@ -238,14 +238,19 @@ bool CrashReporterWin::MinidumpCallback(const wchar_t* dump_path,
 | 
			
		|||
google_breakpad::CustomClientInfo* CrashReporterWin::GetCustomInfo(
 | 
			
		||||
    const std::string& product_name,
 | 
			
		||||
    const std::string& version,
 | 
			
		||||
    const std::string& company_name) {
 | 
			
		||||
    const std::string& company_name,
 | 
			
		||||
    bool upload_to_server) {
 | 
			
		||||
  custom_info_entries_.clear();
 | 
			
		||||
  custom_info_entries_.reserve(2 + upload_parameters_.size());
 | 
			
		||||
  custom_info_entries_.reserve(3 + upload_parameters_.size());
 | 
			
		||||
 | 
			
		||||
  custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
 | 
			
		||||
      L"prod", L"Electron"));
 | 
			
		||||
  custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
 | 
			
		||||
      L"ver", base::UTF8ToWide(version).c_str()));
 | 
			
		||||
  if (!upload_to_server) {
 | 
			
		||||
    custom_info_entries_.push_back(google_breakpad::CustomInfoEntry(
 | 
			
		||||
        L"skip_upload", L"1"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  for (StringMap::const_iterator iter = upload_parameters_.begin();
 | 
			
		||||
       iter != upload_parameters_.end(); ++iter) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,8 @@ class CrashReporterWin : public CrashReporter {
 | 
			
		|||
  google_breakpad::CustomClientInfo* GetCustomInfo(
 | 
			
		||||
      const std::string& product_name,
 | 
			
		||||
      const std::string& version,
 | 
			
		||||
      const std::string& company_name);
 | 
			
		||||
      const std::string& company_name,
 | 
			
		||||
      bool upload_to_server);
 | 
			
		||||
 | 
			
		||||
  // Custom information to be passed to crash handler.
 | 
			
		||||
  std::vector<google_breakpad::CustomInfoEntry> custom_info_entries_;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -391,7 +391,7 @@ void CrashService::OnClientDumpRequest(void* context,
 | 
			
		|||
    LOG(ERROR) << "could not write custom info file";
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (!self->sender_)
 | 
			
		||||
  if (!self->sender_ || map.find(L"skip_upload") != map.end())
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
  // Send the crash dump using a worker thread. This operation has retry
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,7 @@ The `crashReporter` module has the following methods:
 | 
			
		|||
  * `companyName` String (optional)
 | 
			
		||||
  * `submitURL` String - URL that crash reports will be sent to as POST.
 | 
			
		||||
  * `productName` String (optional) - Defaults to `app.getName()`.
 | 
			
		||||
  * `uploadToServer` Boolean (optional) _Linux_ _macOS_ - Whether crash reports should be sent to the server
 | 
			
		||||
  * `uploadToServer` Boolean (optional) - Whether crash reports should be sent to the server
 | 
			
		||||
    Default is `true`.
 | 
			
		||||
  * `ignoreSystemCrashHandler` Boolean (optional) - Default is `false`.
 | 
			
		||||
  * `extra` Object (optional) - An object you can define that will be sent along with the
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
const assert = require('assert')
 | 
			
		||||
const childProcess = require('child_process')
 | 
			
		||||
const fs = require('fs')
 | 
			
		||||
const http = require('http')
 | 
			
		||||
const multiparty = require('multiparty')
 | 
			
		||||
const path = require('path')
 | 
			
		||||
| 
						 | 
				
			
			@ -73,6 +74,93 @@ describe('crashReporter module', function () {
 | 
			
		|||
        })
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      it('should not send minidump if uploadToServer is false', function (done) {
 | 
			
		||||
        this.timeout(120000)
 | 
			
		||||
 | 
			
		||||
        if (process.platform === 'darwin') {
 | 
			
		||||
          crashReporter.setUploadToServer(false)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let server
 | 
			
		||||
        let dumpFile
 | 
			
		||||
        let crashesDir
 | 
			
		||||
        const testDone = (uploaded) => {
 | 
			
		||||
          if (uploaded) {
 | 
			
		||||
            return done(new Error('fail'))
 | 
			
		||||
          }
 | 
			
		||||
          server.close()
 | 
			
		||||
          if (process.platform === 'darwin') {
 | 
			
		||||
            crashReporter.setUploadToServer(true)
 | 
			
		||||
          }
 | 
			
		||||
          assert(fs.existsSync(dumpFile))
 | 
			
		||||
          fs.unlinkSync(dumpFile)
 | 
			
		||||
          done()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let pollInterval
 | 
			
		||||
        const pollDumpFile = () => {
 | 
			
		||||
          fs.readdir(crashesDir, (err, files) => {
 | 
			
		||||
            if (err) {
 | 
			
		||||
              return
 | 
			
		||||
            }
 | 
			
		||||
            const dumps = files.filter((file) => /\.dmp$/.test(file))
 | 
			
		||||
            if (!dumps.length) {
 | 
			
		||||
              return
 | 
			
		||||
            }
 | 
			
		||||
            assert.equal(1, dumps.length)
 | 
			
		||||
            dumpFile = path.join(crashesDir, dumps[0])
 | 
			
		||||
            clearInterval(pollInterval)
 | 
			
		||||
            // dump file should not be deleted when not uploading, so we wait
 | 
			
		||||
            // 500 ms and assert it still exists in `testDone`
 | 
			
		||||
            setTimeout(testDone, 500)
 | 
			
		||||
          })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        remote.ipcMain.once('set-crash-directory', (event, dir) => {
 | 
			
		||||
          if (process.platform === 'linux') {
 | 
			
		||||
            crashesDir = dir
 | 
			
		||||
          } else {
 | 
			
		||||
            crashesDir = crashReporter.getCrashesDirectory()
 | 
			
		||||
            if (process.platform === 'darwin') {
 | 
			
		||||
              // crashpad uses an extra subdirectory
 | 
			
		||||
              crashesDir = path.join(crashesDir, 'completed')
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
          // Before starting, remove all dump files in the crash directory.
 | 
			
		||||
          // This is required because:
 | 
			
		||||
          // - mac crashpad not seem to allow changing the crash directory after
 | 
			
		||||
          //   the first "start" call.
 | 
			
		||||
          // - Other tests in this suite may leave dumps there.
 | 
			
		||||
          // - We want to verify in `testDone` that a dump file is created and
 | 
			
		||||
          //   not deleted.
 | 
			
		||||
          fs.readdir(crashesDir, (err, files) => {
 | 
			
		||||
            if (!err) {
 | 
			
		||||
              for (const file of files) {
 | 
			
		||||
                if (/\.dmp$/.test(file)) {
 | 
			
		||||
                  fs.unlinkSync(path.join(crashesDir, file))
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            event.returnValue = null  // allow the renderer to crash
 | 
			
		||||
            pollInterval = setInterval(pollDumpFile, 100)
 | 
			
		||||
          })
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
        server = startServer({
 | 
			
		||||
          callback (port) {
 | 
			
		||||
            const crashUrl = url.format({
 | 
			
		||||
              protocol: 'file',
 | 
			
		||||
              pathname: path.join(fixtures, 'api', 'crash.html'),
 | 
			
		||||
              search: `?port=${port}&skipUpload=1`
 | 
			
		||||
            })
 | 
			
		||||
            w.loadURL(crashUrl)
 | 
			
		||||
          },
 | 
			
		||||
          processType: 'renderer',
 | 
			
		||||
          done: testDone.bind(null, true)
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      it('should send minidump with updated extra parameters', function (done) {
 | 
			
		||||
        if (process.env.APPVEYOR === 'True') return done()
 | 
			
		||||
        if (process.env.TRAVIS === 'true') return done()
 | 
			
		||||
| 
						 | 
				
			
			@ -215,4 +303,5 @@ const startServer = ({callback, processType, done}) => {
 | 
			
		|||
    }
 | 
			
		||||
    callback(port)
 | 
			
		||||
  })
 | 
			
		||||
  return server
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								spec/fixtures/api/crash.html
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								spec/fixtures/api/crash.html
									
										
									
									
										vendored
									
									
								
							| 
						 | 
				
			
			@ -1,20 +1,24 @@
 | 
			
		|||
<html>
 | 
			
		||||
<body>
 | 
			
		||||
<script type="text/javascript" charset="utf-8">
 | 
			
		||||
var port = require('url').parse(window.location.href, true).query.port;
 | 
			
		||||
var crashReporter = require('electron').crashReporter;
 | 
			
		||||
var url = require('url').parse(window.location.href, true);
 | 
			
		||||
var uploadToServer = !url.query.skipUpload;
 | 
			
		||||
var port = url.query.port;
 | 
			
		||||
var {crashReporter, ipcRenderer} = require('electron');
 | 
			
		||||
crashReporter.start({
 | 
			
		||||
  productName: 'Zombies',
 | 
			
		||||
  companyName: 'Umbrella Corporation',
 | 
			
		||||
  submitURL: 'http://127.0.0.1:' + port,
 | 
			
		||||
  uploadToServer: true,
 | 
			
		||||
  uploadToServer: uploadToServer,
 | 
			
		||||
  ignoreSystemCrashHandler: true,
 | 
			
		||||
  extra: {
 | 
			
		||||
    'extra1': 'extra1',
 | 
			
		||||
    'extra2': 'extra2',
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
if (!uploadToServer) {
 | 
			
		||||
  ipcRenderer.sendSync('set-crash-directory', crashReporter.getCrashesDirectory())
 | 
			
		||||
}
 | 
			
		||||
setImmediate(function() { process.crash(); });
 | 
			
		||||
</script>
 | 
			
		||||
</body>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue