In-memory debug logging, configurable in Advanced pane of preferences, with ability to send output to zotero.org
This commit is contained in:
parent
75fd0b4448
commit
5f9e39f959
7 changed files with 402 additions and 46 deletions
|
@ -26,6 +26,14 @@ var proxies;
|
|||
var charsets;
|
||||
var _io = {};
|
||||
|
||||
|
||||
var Zotero_Preferences = {
|
||||
|
||||
onClose: function () {
|
||||
Zotero_Preferences.DebugOutput.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
// Display the appropriate modifier keys for the platform
|
||||
|
@ -40,6 +48,7 @@ function init()
|
|||
populateQuickCopyList();
|
||||
updateQuickCopyInstructions();
|
||||
initSearchPane();
|
||||
Zotero_Preferences.Debug_Output.init();
|
||||
|
||||
var charsetMenu = document.getElementById("zotero-import-charsetMenu");
|
||||
var charsetMap = Zotero_Charset_Menu.populate(charsetMenu, false);
|
||||
|
@ -1206,6 +1215,239 @@ function resetStyles() {
|
|||
}
|
||||
|
||||
|
||||
Zotero_Preferences.Debug_Output = {
|
||||
_timer: null,
|
||||
|
||||
init: function () {
|
||||
var storing = Zotero.Debug.storing;
|
||||
this._updateButton();
|
||||
this.updateLines();
|
||||
if (storing) {
|
||||
this._initTimer();
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
toggleStore: function () {
|
||||
var storing = Zotero.Debug.storing;
|
||||
Zotero.Debug.setStore(!storing);
|
||||
if (!storing) {
|
||||
this._initTimer();
|
||||
}
|
||||
else {
|
||||
if (this._timerID) {
|
||||
this._timer.cancel();
|
||||
this._timerID = null;
|
||||
}
|
||||
}
|
||||
this._updateButton();
|
||||
this.updateLines();
|
||||
},
|
||||
|
||||
|
||||
view: function () {
|
||||
var uri = "zotero://debug/";
|
||||
var features = "menubar=yes,toolbar=no,location=no,scrollbars,centerscreen,resizable";
|
||||
|
||||
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
var win = wm.getMostRecentWindow("navigator:browser");
|
||||
if (win) {
|
||||
win.open(uri, null, features);
|
||||
}
|
||||
else {
|
||||
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
|
||||
.getService(Components.interfaces.nsIWindowWatcher);
|
||||
var win = ww.openWindow(null, uri, null, features + ",width=775,height=575", null);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
// TODO: localize
|
||||
submit: function () {
|
||||
document.getElementById('debug-output-submit').disabled = true;
|
||||
document.getElementById('debug-output-submit-progress').hidden = false;
|
||||
|
||||
var url = "http://www.zotero.org/utils/dev/repo/report?debug=1";
|
||||
var output = Zotero.Debug.get();
|
||||
|
||||
var uploadCallback = function (xmlhttp) {
|
||||
document.getElementById('debug-output-submit').disabled = false;
|
||||
document.getElementById('debug-output-submit-progress').hidden = true;
|
||||
|
||||
Zotero.debug(xmlhttp.responseText);
|
||||
|
||||
var pr = Components.classes["@mozilla.org/network/default-prompt;1"]
|
||||
.getService(Components.interfaces.nsIPrompt);
|
||||
|
||||
if (!xmlhttp.responseXML) {
|
||||
pr.alert(
|
||||
Zotero.getString('general.error'),
|
||||
'Invalid response from server'
|
||||
);
|
||||
return;
|
||||
}
|
||||
var reported = xmlhttp.responseXML.getElementsByTagName('reported');
|
||||
if (reported.length != 1) {
|
||||
pr.alert(
|
||||
Zotero.getString('general.error'),
|
||||
'The server returned an error. Please try again.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var reportID = reported[0].getAttribute('reportID');
|
||||
pr.alert(
|
||||
"Submitted",
|
||||
"Debug output has been sent to the Zotero server.\n\n"
|
||||
+ "The Report ID is D" + reportID + "."
|
||||
);
|
||||
}
|
||||
|
||||
var bufferUploader = function (data) {
|
||||
var pr = Components.classes["@mozilla.org/network/default-prompt;1"]
|
||||
.getService(Components.interfaces.nsIPrompt);
|
||||
|
||||
var oldLen = output.length;
|
||||
var newLen = data.length;
|
||||
var savings = Math.round(((oldLen - newLen) / oldLen) * 100)
|
||||
Zotero.debug("HTTP POST " + newLen + " bytes to " + url
|
||||
+ " (gzipped from " + oldLen + " bytes; "
|
||||
+ savings + "% savings)");
|
||||
|
||||
if (Zotero.Utilities.HTTP.browserIsOffline()) {
|
||||
pr.alert(
|
||||
Zotero.getString(
|
||||
'general.error',
|
||||
Zotero.appName + " is in offline mode."
|
||||
)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
var req =
|
||||
Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].
|
||||
createInstance();
|
||||
req.open('POST', url, true);
|
||||
req.setRequestHeader('Content-Type', "application/octet-stream");
|
||||
req.setRequestHeader('Content-Encoding', 'gzip');
|
||||
|
||||
req.channel.notificationCallbacks = {
|
||||
onProgress: function (request, context, progress, progressMax) {
|
||||
var pm = document.getElementById('debug-output-submit-progress');
|
||||
pm.mode = 'determined'
|
||||
pm.value = progress;
|
||||
pm.max = 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;
|
||||
},
|
||||
|
||||
}
|
||||
req.onreadystatechange = function () {
|
||||
if (req.readyState == 4) {
|
||||
uploadCallback(req);
|
||||
}
|
||||
};
|
||||
try {
|
||||
req.sendAsBinary(data);
|
||||
}
|
||||
catch (e) {
|
||||
pr.alert(
|
||||
Zotero.getString('general.error'),
|
||||
"An error occurred sending debug output."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Get input stream from debug output data
|
||||
var unicodeConverter =
|
||||
Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
|
||||
unicodeConverter.charset = "UTF-8";
|
||||
var bodyStream = unicodeConverter.convertToInputStream(output);
|
||||
|
||||
// Get listener for when compression is done
|
||||
var listener = new Zotero.BufferedInputListener(bufferUploader);
|
||||
|
||||
// Initialize stream converter
|
||||
var converter =
|
||||
Components.classes["@mozilla.org/streamconv;1?from=uncompressed&to=gzip"]
|
||||
.createInstance(Components.interfaces.nsIStreamConverter);
|
||||
converter.asyncConvertData("uncompressed", "gzip", listener, null);
|
||||
|
||||
// Send input stream to stream converter
|
||||
var pump = Components.classes["@mozilla.org/network/input-stream-pump;1"].
|
||||
createInstance(Components.interfaces.nsIInputStreamPump);
|
||||
pump.init(bodyStream, -1, -1, 0, 0, true);
|
||||
pump.asyncRead(converter, null);
|
||||
},
|
||||
|
||||
|
||||
clear: function () {
|
||||
Zotero.Debug.clear();
|
||||
this.updateLines();
|
||||
},
|
||||
|
||||
|
||||
updateLines: function () {
|
||||
var lines = Zotero.Debug.count();
|
||||
document.getElementById('debug-output-lines').value = lines;
|
||||
var empty = lines == 0;
|
||||
document.getElementById('debug-output-view').disabled = empty;
|
||||
document.getElementById('debug-output-clear').disabled = empty;
|
||||
document.getElementById('debug-output-submit').disabled = empty;
|
||||
},
|
||||
|
||||
|
||||
_initTimer: function () {
|
||||
this._timer = Components.classes["@mozilla.org/timer;1"].
|
||||
createInstance(Components.interfaces.nsITimer);
|
||||
this._timer.initWithCallback({
|
||||
notify: function() {
|
||||
Zotero_Preferences.Debug_Output.updateLines();
|
||||
}
|
||||
}, 10000, Components.interfaces.nsITimer.TYPE_REPEATING_SLACK);
|
||||
},
|
||||
|
||||
|
||||
_updateButton: function () {
|
||||
var storing = Zotero.Debug.storing
|
||||
|
||||
var button = document.getElementById('debug-output-enable');
|
||||
// TODO: localize
|
||||
if (storing) {
|
||||
button.label = "Disable";
|
||||
}
|
||||
else {
|
||||
button.label = "Enable";
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
onClose: function () {
|
||||
if (this._timer) {
|
||||
this._timer.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onOpenURLSelected()
|
||||
{
|
||||
var openURLMenu = document.getElementById('openURLMenu');
|
||||
|
|
|
@ -37,8 +37,9 @@ To add a new preference:
|
|||
in Zotero.Prefs.observe()
|
||||
|
||||
-->
|
||||
<prefwindow id="zotero-prefs" title="&zotero.preferences.title;" onload="moveToAlertPosition(); init()"
|
||||
windowtype="zotero:pref" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<prefwindow id="zotero-prefs" title="&zotero.preferences.title;" onload="moveToAlertPosition(); init()" onclose="Zotero_Preferences.onClose()"
|
||||
windowtype="zotero:pref" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
>
|
||||
|
||||
<prefpane id="zotero-prefpane-general"
|
||||
label="&zotero.preferences.prefpane.general;"
|
||||
|
@ -724,6 +725,7 @@ To add a new preference:
|
|||
<preference id="pref-useDataDir" name="extensions.zotero.useDataDir" type="bool"/>
|
||||
<preference id="pref-dataDir" name="extensions.zotero.dataDir" type="string"/>
|
||||
<preference id="pref-export-displayCharsetOption" name="extensions.zotero.export.displayCharsetOption" type="bool"/>
|
||||
<preference id="pref-debug-output-enableAfterRestart" name="extensions.zotero.debug.store" type="bool"/>
|
||||
<preference id="pref-import-charset" name="extensions.zotero.import.charset" type="string"/>
|
||||
</preferences>
|
||||
|
||||
|
@ -756,6 +758,30 @@ To add a new preference:
|
|||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<groupbox>
|
||||
<!-- TODO: localize -->
|
||||
<caption label="Debug Output Logging"/>
|
||||
|
||||
<!-- This doesn't wrap without an explicit width -->
|
||||
<vbox>
|
||||
<description width="45em">Debug output can help Zotero developers diagnose problems in Zotero. Debug logging will slow down Zotero, so you should generally leave it disabled unless a Zotero developer requests debug output.</description>
|
||||
</vbox>
|
||||
|
||||
<hbox align="center">
|
||||
<button id="debug-output-enable" oncommand="Zotero_Preferences.Debug_Output.toggleStore()"/>
|
||||
<label id="debug-output-lines" style="margin-right: 0"/>
|
||||
<label value="lines logged"/>
|
||||
<checkbox preference="pref-debug-output-enableAfterRestart" label="Enable after restart" style="margin-left: 1.5em"/>
|
||||
</hbox>
|
||||
|
||||
<hbox align="center">
|
||||
<button id="debug-output-view" label="View Output" oncommand="Zotero_Preferences.Debug_Output.view()"/>
|
||||
<button id="debug-output-clear" label="Clear Output" oncommand="Zotero_Preferences.Debug_Output.clear()"/>
|
||||
<button id="debug-output-submit" label="Submit to Zotero Server" oncommand="Zotero_Preferences.Debug_Output.submit()"/>
|
||||
<progressmeter id="debug-output-submit-progress" mode="undetermined" hidden="true"/>
|
||||
</hbox>
|
||||
</groupbox>
|
||||
|
||||
<groupbox>
|
||||
<caption label="&zotero.preferences.charset;"/>
|
||||
|
||||
|
|
91
chrome/content/zotero/xpcom/debug.js
Normal file
91
chrome/content/zotero/xpcom/debug.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
// TODO: license
|
||||
|
||||
Zotero.Debug = new function () {
|
||||
this.__defineGetter__('storing', function () _store);
|
||||
|
||||
var _console;
|
||||
var _store;
|
||||
var _level;
|
||||
var _time;
|
||||
var _lastTime;
|
||||
var _output = [];
|
||||
|
||||
|
||||
this.init = function () {
|
||||
_console = Zotero.Prefs.get('debug.log');
|
||||
_store = Zotero.Prefs.get('debug.store');
|
||||
_level = Zotero.Prefs.get('debug.level');
|
||||
_time = Zotero.Prefs.get('debug.time');
|
||||
}
|
||||
|
||||
this.log = function (message, level) {
|
||||
if (!_console && !_store) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof message != 'string') {
|
||||
message = Zotero.varDump(message);
|
||||
}
|
||||
|
||||
if (!level) {
|
||||
level = 3;
|
||||
}
|
||||
|
||||
// If level above debug.level value, don't display
|
||||
if (level > _level) {
|
||||
return;
|
||||
}
|
||||
|
||||
var deltaStr = '';
|
||||
if (_time || _store) {
|
||||
var delta = 0;
|
||||
var d = new Date();
|
||||
if (_lastTime) {
|
||||
delta = d - _lastTime;
|
||||
}
|
||||
_lastTime = d;
|
||||
|
||||
while (("" + delta).length < 7) {
|
||||
delta = '0' + delta;
|
||||
}
|
||||
|
||||
deltaStr = '(+' + delta + ')';
|
||||
}
|
||||
|
||||
if (_console) {
|
||||
dump('zotero(' + level + ')' + (_time ? deltaStr : '') + ': ' + message + "\n\n");
|
||||
}
|
||||
if (_store) {
|
||||
if (Zotero.Utilities.prototype.probability(1000)) {
|
||||
// Remove initial lines if over limit
|
||||
var overage = this.count() - Zotero.Prefs.get('debug.store.limit');
|
||||
if (overage > 0) {
|
||||
_output.splice(0, Math.abs(overage));
|
||||
}
|
||||
}
|
||||
_output.push('(' + level + ')' + deltaStr + ': ' + message);
|
||||
}
|
||||
}
|
||||
|
||||
this.get = function () {
|
||||
return _output.join('\n\n');
|
||||
}
|
||||
|
||||
|
||||
this.setStore = function (enable) {
|
||||
if (enable) {
|
||||
this.clear();
|
||||
}
|
||||
_store = enable;
|
||||
}
|
||||
|
||||
|
||||
this.count = function () {
|
||||
return _output.length;
|
||||
}
|
||||
|
||||
|
||||
this.clear = function () {
|
||||
_output = [];
|
||||
}
|
||||
}
|
|
@ -135,10 +135,6 @@ var Zotero = new function(){
|
|||
var _startupError;
|
||||
var _startupErrorHandler;
|
||||
var _zoteroDirectory = false;
|
||||
var _debugLogging;
|
||||
var _debugLevel;
|
||||
var _debugTime;
|
||||
var _debugLastTime;
|
||||
var _localizedStringBundle;
|
||||
var _localUserKey;
|
||||
var _waiting;
|
||||
|
@ -167,9 +163,7 @@ var Zotero = new function(){
|
|||
// Load in the preferences branch for the extension
|
||||
Zotero.Prefs.init();
|
||||
|
||||
_debugLogging = Zotero.Prefs.get('debug.log');
|
||||
_debugLevel = Zotero.Prefs.get('debug.level');
|
||||
_debugTime = Zotero.Prefs.get('debug.time');
|
||||
Zotero.Debug.init();
|
||||
|
||||
this.mainThread = Components.classes["@mozilla.org/thread-manager;1"].getService().mainThread;
|
||||
|
||||
|
@ -606,41 +600,7 @@ var Zotero = new function(){
|
|||
* Defaults to log level 3 if level not provided
|
||||
*/
|
||||
function debug(message, level) {
|
||||
if (!_debugLogging){
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof message!='string'){
|
||||
message = Zotero.varDump(message);
|
||||
}
|
||||
|
||||
if (!level){
|
||||
level = 3;
|
||||
}
|
||||
|
||||
// If level above debug.level value, don't display
|
||||
if (level > _debugLevel){
|
||||
return false;
|
||||
}
|
||||
|
||||
var deltaStr = '';
|
||||
if (_debugTime) {
|
||||
var delta = 0;
|
||||
var d = new Date();
|
||||
if (_debugLastTime) {
|
||||
delta = d - _debugLastTime;
|
||||
}
|
||||
_debugLastTime = d;
|
||||
|
||||
while (("" + delta).length < 7) {
|
||||
delta = '0' + delta;
|
||||
}
|
||||
|
||||
deltaStr = '(+' + delta + ')';
|
||||
}
|
||||
|
||||
dump('zotero(' + level + ')' + deltaStr + ': ' + message + "\n\n");
|
||||
return true;
|
||||
Zotero.Debug.log(message, level);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -808,11 +808,42 @@ function ChromeExtensionHandler() {
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
zotero://debug/
|
||||
*/
|
||||
var DebugExtension = new function() {
|
||||
this.newChannel = newChannel;
|
||||
|
||||
this.__defineGetter__('loadAsChrome', function () { return false; });
|
||||
|
||||
function newChannel(uri) {
|
||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
|
||||
var Zotero = Components.classes["@zotero.org/Zotero;1"]
|
||||
.getService(Components.interfaces.nsISupports)
|
||||
.wrappedJSObject;
|
||||
|
||||
try {
|
||||
var output = Zotero.Debug.get();
|
||||
|
||||
var uriStr = 'data:text/plain,' + encodeURIComponent(output);
|
||||
var extURI = ioService.newURI(uriStr, null, null);
|
||||
return ioService.newChannelFromURI(extURI);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug(e);
|
||||
throw (e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var ReportExtensionSpec = ZOTERO_SCHEME + "://report"
|
||||
this._extensions[ReportExtensionSpec] = ReportExtension;
|
||||
|
||||
|
||||
var TimelineExtensionSpec = ZOTERO_SCHEME + "://timeline"
|
||||
this._extensions[TimelineExtensionSpec] = TimelineExtension;
|
||||
|
||||
|
@ -824,6 +855,9 @@ function ChromeExtensionHandler() {
|
|||
|
||||
var FullscreenExtensionSpec = ZOTERO_SCHEME + "://fullscreen"
|
||||
this._extensions[FullscreenExtensionSpec] = FullscreenExtension;
|
||||
|
||||
var DebugExtensionSpec = ZOTERO_SCHEME + "://debug"
|
||||
this._extensions[DebugExtensionSpec] = DebugExtension;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ var xpcomFiles = [
|
|||
'data/tag',
|
||||
'data/tags',
|
||||
'db',
|
||||
'debug',
|
||||
'duplicate',
|
||||
'enstyle',
|
||||
'error',
|
||||
|
|
|
@ -11,6 +11,8 @@ pref("extensions.zotero.dataDir", '');
|
|||
pref("extensions.zotero.lastDataDir", '');
|
||||
pref("extensions.zotero.dbLockExclusive", true);
|
||||
pref("extensions.zotero.debug.log",false);
|
||||
pref("extensions.zotero.debug.store",false);
|
||||
pref("extensions.zotero.debug.store.limit",750000);
|
||||
pref("extensions.zotero.debug.level",5);
|
||||
pref("extensions.zotero.debug.time", false);
|
||||
pref("extensions.zotero.automaticScraperUpdates",true);
|
||||
|
|
Loading…
Reference in a new issue