拡張機能デバッグインターフェイス

拡張機能開発時によく使うログや表明 (assertion) などのためのインターフェイスのサンプルコードです

var myextension = {
	// debug interface
	debug: {
		// https://developer.mozilla.org/en/NsIConsoleService
		_consoleservice: Components.classes["@mozilla.org/consoleservice;1"].getService(Components.interfaces.nsIConsoleService),
		_Cc_scripterror: Components.classes["@mozilla.org/scripterror;1"],
		_Ci_scripterror: Components.interfaces.nsIScriptError,
		enabled: false, // set true to output
		noFirebug: false, // don't show object in Firebug
		prefix: "",  // prefix string
		createScripterror: function() this._Cc_scripterror.createInstance(this._Ci_scripterror),
		// log for Firebug with existence check
		logFirebug: function(x) this.enabled && !this.noFirebug && Firebug && Firebug.Console && Firebug.Console.log(x),
		logFirebugOnlyObject: function(x) typeof x == "object" && x != null && this.logFirebug(x),
		// log/warn/error in console
		log: function(message) {
			if (this.enabled) {
				this._consoleservice.logStringMessage(this.prefix+message);
				this.logFirebugOnlyObject(message);
			}
		},
		warn: function(message) {
			if (this.enabled) {
				var stack = Components.stack.caller;
				var error = this._Cc_scripterror.createInstance(this._Ci_scripterror);
				error.init(this.prefix+message, stack.filename, null, stack.lineNumber, null, this._Ci_scripterror.warningFlag, null);
				this._consoleservice.logMessage(error);
				this.logFirebugOnlyObject(message);
			}
		},
		error: function(message) {
			if (this.enabled) {
				var stack = Components.stack.caller;
				var error = this._Cc_scripterror.createInstance(this._Ci_scripterror);
				error.init(this.prefix+message, stack.filename, null, stack.lineNumber, null, this._Ci_scripterror.errorFlag, null);
				this._consoleservice.logMessage(error);
				this.logFirebugOnlyObject(message);
			}
		},
		// debug with exception (error objects)
		exception: function(error) {
			if (this.enabled) {
				Components.utils.reportError(error);
				this.logFirebugOnlyObject(error);
			}
		},
		stack: function(error) {
			if (this.enabled) {
				if (error instanceof Error) {
					this._consoleservice.logStringMessage(this.prefix+error.stack);
				}
				else {
					error = new Error();
					var callerstack = error.stack.replace(/^.*\n.*\n/, "");
					this._consoleservice.logStringMessage(this.prefix+callerstack);
				}
				this.logFirebugOnlyObject(error);
			}
		},
		// alert and assert
		alert: function(message) {
			if (this.enabled) {
				window.alert(this.prefix + message);
				this.logFirebugOnlyObject(message);
			}
		},
		assert: function(cond, message) {
			var failed = this.enabled && !cond;
			if (failed) {
				var message = this.prefix+message;
				var stack = Components.stack.caller;
				var error = this._Cc_scripterror.createInstance(this._Ci_scripterror);
				error.init(message, stack.filename, null, stack.lineNumber, null, this._Ci_scripterror.errorFlag, null);
				this._consoleservice.logMessage(error);
				window.alert(message);
				this.logFirebugOnlyObject(message);
			}
			return !failed;
		}
	},
	onLoad: function() {
		this.debug.enabled = true;
		this.debug.prefix = "myextension debug:\n";
		this.debug.log("myextension inited!");
	}
}
window.addEventListener("load", function() { myextension.onLoad() }, false);

debug オブジェクトを自分の拡張機能専用オブジェクトのプロパティとして定義し、debug.log() などのメソッドを使います。debug.prefix に文字列を設定しておけば、コンソールのメッセージすべての先頭にその文字列が表示されるので検索しやすくなります。引数がオブジェクトの場合、Firebug がインストールされていれば Firebug のコンソールにも出力します。

上記の例では直接 true を代入していますが、debug.enabled プロパティはユーザ設定から読み込むようにすれば、開発環境だけでログを出力するといった使い方もできます。

より詳しい解説の追加などはまた後日…