Skip to content

Commit

Permalink
Adds SSE-based error and debug report sharing with connectors
Browse files Browse the repository at this point in the history
Updates log formatting with headers and JSON formatted system info.

Debug logging options are now toggled globally in the following manner:
- A connector toggling debug logging will toggle Zotero too
- Zotero toggling debug logging will toggle all SSE enabled connectors

Error and debug reports are fetched by the party submitting the log.

Currently uses `report?debug=1` endpoint for both debug logs and reports
because the `report` endpoint does not accept plaintext.
  • Loading branch information
adomasven committed Sep 12, 2017
1 parent 15502d3 commit ddd2a1b
Show file tree
Hide file tree
Showing 15 changed files with 622 additions and 622 deletions.
2 changes: 1 addition & 1 deletion chrome/content/zotero/debugViewer.js
Expand Up @@ -38,7 +38,7 @@ function updateErrors() {
.then(function (sysInfo) {
if (stopping) return;

var errors = Zotero.getErrors(true);
var errors = Zotero.Errors.getErrors(true);
var errorStr = errors.length ? errors.join('\n\n') + '\n\n' : '';

document.getElementById('errors').textContent = errorStr + sysInfo;
Expand Down
90 changes: 10 additions & 80 deletions chrome/content/zotero/errorReport.xul
Expand Up @@ -18,8 +18,6 @@
var Zotero = obj.Zotero;
var data = obj.data;
var msg = data.msg;
var errorData = data.errorData;
var extraData = data.extraData ? data.extraData : '';
var diagnosticInfo = false;
Expand All @@ -29,13 +27,12 @@
continueButton.disabled = true;
diagnosticInfo = yield Zotero.getSystemInfo();
var errorData = Zotero.Errors.getErrors();
var errorDataText = errorData.length
? data.errorData.join('\n\n')
? errorData.join('\n\n')
: Zotero.getString('errorReport.noErrorsLogged', Zotero.appName);
var logText = errorDataText + '\n\n'
+ (extraData !== '' ? extraData + '\n\n' : '')
+ diagnosticInfo;
var logText = diagnosticInfo + '\n\n' + errorDataText;
if (document.getElementById('zotero-failure-message').hasChildNodes()) {
var textNode = document.getElementById('zotero-failure-message').firstChild;
Expand All @@ -57,89 +54,22 @@
var wizard = document.getElementById('zotero-error-report');
var continueButton = wizard.getButton('next');
continueButton.disabled = true;
var parts = {
error: "true",
errorData: errorData.join('\n'),
extraData: extraData,
diagnostic: diagnosticInfo
};
var body = '';
for (var key in parts) {
body += key + '=' + encodeURIComponent(parts[key]) + '&';
}
body = body.substr(0, body.length - 1);
var req = yield Zotero.HTTP.request(
"POST",
ZOTERO_CONFIG.REPOSITORY_URL + "report",
{
body,
successCodes: false,
foreground: true
}
);
_sendErrorReportCallback(req);
});
function _sendErrorReportCallback(xmlhttp) {
var wizard = document.getElementById('zotero-error-report');
if (!wizard) {
return;
}
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
if (!xmlhttp.responseXML){
try {
if (xmlhttp.status>1000){
ps.alert(
null,
Zotero.getString('general.error'),
Zotero.getString('errorReport.noNetworkConnection')
);
}
else {
ps.alert(
null,
Zotero.getString('general.error'),
Zotero.getString('errorReport.invalidResponseRepository')
);
}
}
catch (e){
ps.alert(
null,
Zotero.getString('general.error'),
Zotero.getString('errorReport.repoCannotBeContacted')
);
}
wizard.rewind();
return;
}
var reported = xmlhttp.responseXML.getElementsByTagName('reported');
if (reported.length != 1) {
ps.alert(
null,
Zotero.getString('general.error'),
Zotero.getString('errorReport.invalidResponseRepository')
);
var reportID;
try {
reportID = yield Zotero.Errors.submitToZotero();
} catch (e) {
ps.alert(null, Zotero.getString('general.error'), e.message);
wizard.rewind();
return;
}
wizard.advance();
wizard.getButton('cancel').disabled = true;;
wizard.getButton('cancel').disabled = true;
wizard.canRewind = false;
var reportID = reported[0].getAttribute('reportID');
document.getElementById('zotero-report-id').setAttribute('value', reportID);
document.getElementById('zotero-report-result').hidden = false;
}
});
}
]]>
</script>
Expand Down
99 changes: 11 additions & 88 deletions chrome/content/zotero/standalone/standalone.js
Expand Up @@ -240,7 +240,7 @@ ZoteroStandalone.DebugOutput = {


toggleStore: function () {
Zotero.Debug.setStore(!Zotero.Debug.storing);
Zotero.Debug.setStore(!Zotero.Debug.storing, true);
},


Expand Down Expand Up @@ -268,109 +268,32 @@ ZoteroStandalone.DebugOutput = {


submit: function () {
// 'Zotero' isn't defined yet when this function is created, so do it inline
return Zotero.Promise.coroutine(function* () {
Components.utils.import("resource://zotero/config.js");

var url = ZOTERO_CONFIG.REPOSITORY_URL + "report?debug=1";
var output = yield Zotero.Debug.get(
Zotero.Prefs.get('debug.store.submitSize'),
Zotero.Prefs.get('debug.store.submitLineLength')
);
Zotero.Debug.setStore(false);

var ps = Services.prompt;
try {
var xmlhttp = yield Zotero.HTTP.request(
"POST",
url,
{
compressBody: true,
body: output,
logBodyLength: 30,
timeout: 15000,
requestObserver: function (req) {
// Don't fail during tests, with fake XHR
if (!req.channel) {
return;
}
req.channel.notificationCallbacks = {
onProgress: function (request, context, progress, progressMax) {},

// nsIInterfaceRequestor
getInterface: function (iid) {
try {
return this.QueryInterface(iid);
}
catch (e) {
throw Components.results.NS_NOINTERFACE;
}
},

QueryInterface: function(iid) {
if (iid.equals(Components.interfaces.nsISupports) ||
iid.equals(Components.interfaces.nsIInterfaceRequestor) ||
iid.equals(Components.interfaces.nsIProgressEventSink)) {
return this;
}
throw Components.results.NS_NOINTERFACE;
},

}
}
}
);
}
catch (e) {
Zotero.logError(e);
let title = Zotero.getString('general.error');
let msg;
if (e instanceof Zotero.HTTP.UnexpectedStatusException) {
msg = Zotero.getString('general.invalidResponseServer');
}
else if (e instanceof Zotero.HTTP.BrowserOfflineException) {
msg = Zotero.getString('general.browserIsOffline', Zotero.appName);
}
else {
msg = Zotero.getString('zotero.debugOutputLogging.dialog.error');
}
ps.alert(null, title, msg);
var debugID = yield Zotero.Debug.submitToZotero();
} catch (e) {
ps.alert(null, Zotero.getString('general.error'), e.message);
return false;
}

Zotero.debug(xmlhttp.responseText);

var reported = xmlhttp.responseXML.getElementsByTagName('reported');
if (reported.length != 1) {
ps.alert(
null,
Zotero.getString('general.error'),
Zotero.getString('general.serverError')
);
return false;
}

var reportID = reported[0].getAttribute('reportID');

var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL;
var index = ps.confirmEx(
null,
Zotero.getString('zotero.debugOutputLogging.dialog.title'),
Zotero.getString('zotero.debugOutputLogging.dialog.sent', [ZOTERO_CONFIG.DOMAIN_NAME, reportID]),
Zotero.getString('zotero.debugOutputLogging.dialog.sent', [ZOTERO_CONFIG.DOMAIN_NAME, debugID.substr(1)]),
buttonFlags,
Zotero.getString('general.copyToClipboard'),
null, null, null, {}
);
if (index == 0) {
const helper = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
.getService(Components.interfaces.nsIClipboardHelper);
helper.copyString("D" + reportID);
helper.copyString(debugID);
}

Zotero.Debug.clear();
return true;
}.bind(this))();
}).apply(this, arguments);
},


Expand All @@ -381,21 +304,21 @@ ZoteroStandalone.DebugOutput = {
submitted = true;
});
doc.querySelector('#clear-button').addEventListener('click', function (event) {
Zotero.Debug.clear();
Zotero.Debug.clear(true);
});
// If output has been submitted, disable logging when window is closed
doc.defaultView.addEventListener('unload', function (event) {
if (submitted) {
Zotero.Debug.setStore(false);
Zotero.Debug.clear();
Zotero.Debug.setStore(false, true);
Zotero.Debug.clear(true);
}
});
});
},


clear: function () {
Zotero.Debug.clear();
Zotero.Debug.clear(true);
},


Expand Down
41 changes: 41 additions & 0 deletions chrome/content/zotero/xpcom/connector/server_connector.js
Expand Up @@ -112,6 +112,47 @@ Zotero.Server.Connector.AttachmentProgressManager = new function() {
}
};


Zotero.Server.Connector.Reports = function() {};
Zotero.Server.Connector.Reports.reports = [];
Zotero.Server.Endpoints["/connector/reports"] = Zotero.Server.Connector.Reports;
Zotero.Server.Connector.Reports.prototype = {
supportedMethods: ["POST"],
supportedDataTypes: ["application/json"],
permitBookmarklet: true,

/**
* An endpoint to manage error/debug logging and reporting
*/
init: async function(options) {
let data = options.data;
if ('errors' in data && 'get' in data.errors) {
let sysInfo = await Zotero.getSystemInfo();
let errors = Zotero.Errors.getErrors();
return [200, "text/plain", `${sysInfo}\n\n${errors.join('\n\n')}`]
}
else if ('debug' in data) {
if ('get' in data.debug) {
let debug = await Zotero.Debug.get();
return [200, "text/plain", debug]
}
else if ('store' in data.debug) {
Zotero.Debug.setStore(data.debug.store, false);
}
else if ('clear' in data.debug) {
Zotero.Debug.clear(false);
}
return 200;
} else if ('report' in data) {
Zotero.Server.Connector.Reports.reports.push(data.report);
return 200;
}

return 400;
}
};


/**
* Lists all available translators, including code for translators that should be run on every page
*
Expand Down

0 comments on commit ddd2a1b

Please sign in to comment.