зеркало из https://github.com/mozilla/gecko-dev.git
Bug 585956 - Implement console.trace() in web console; f=ddahl r=rcampbell,jonas
This commit is contained in:
Родитель
5e1f6515a2
Коммит
77fc545081
|
@ -21,6 +21,7 @@
|
||||||
* David Dahl <ddahl@mozilla.com> (Original Author)
|
* David Dahl <ddahl@mozilla.com> (Original Author)
|
||||||
* Ryan Flint <rflint@mozilla.com>
|
* Ryan Flint <rflint@mozilla.com>
|
||||||
* Rob Campbell <rcampbell@mozilla.com>
|
* Rob Campbell <rcampbell@mozilla.com>
|
||||||
|
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -79,12 +80,16 @@ ConsoleAPI.prototype = {
|
||||||
debug: function CA_debug() {
|
debug: function CA_debug() {
|
||||||
self.notifyObservers(id, "log", arguments);
|
self.notifyObservers(id, "log", arguments);
|
||||||
},
|
},
|
||||||
|
trace: function CA_trace() {
|
||||||
|
self.notifyObservers(id, "trace", self.getStackTrace());
|
||||||
|
},
|
||||||
__exposedProps__: {
|
__exposedProps__: {
|
||||||
log: "r",
|
log: "r",
|
||||||
info: "r",
|
info: "r",
|
||||||
warn: "r",
|
warn: "r",
|
||||||
error: "r",
|
error: "r",
|
||||||
debug: "r",
|
debug: "r",
|
||||||
|
trace: "r",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -100,6 +105,7 @@ ConsoleAPI.prototype = {
|
||||||
warn: bind.call(x.warn, x),\
|
warn: bind.call(x.warn, x),\
|
||||||
error: bind.call(x.error, x),\
|
error: bind.call(x.error, x),\
|
||||||
debug: bind.call(x.debug, x),\
|
debug: bind.call(x.debug, x),\
|
||||||
|
trace: bind.call(x.trace, x),\
|
||||||
__noSuchMethod__: function() {}\
|
__noSuchMethod__: function() {}\
|
||||||
};\
|
};\
|
||||||
Object.defineProperty(obj, '__mozillaConsole__', { value: true });\
|
Object.defineProperty(obj, '__mozillaConsole__', { value: true });\
|
||||||
|
@ -126,7 +132,32 @@ ConsoleAPI.prototype = {
|
||||||
|
|
||||||
Services.obs.notifyObservers(consoleEvent,
|
Services.obs.notifyObservers(consoleEvent,
|
||||||
"console-api-log-event", aID);
|
"console-api-log-event", aID);
|
||||||
}
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the stacktrace array for the console.trace() call.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* Each element is a stack frame that holds the following properties:
|
||||||
|
* filename, lineNumber, functionName and language.
|
||||||
|
**/
|
||||||
|
getStackTrace: function CA_getStackTrace() {
|
||||||
|
let stack = [];
|
||||||
|
let frame = Components.stack.caller;
|
||||||
|
while (frame = frame.caller) {
|
||||||
|
if (frame.language == Ci.nsIProgrammingLanguage.JAVASCRIPT ||
|
||||||
|
frame.language == Ci.nsIProgrammingLanguage.JAVASCRIPT2) {
|
||||||
|
stack.push({
|
||||||
|
filename: frame.filename,
|
||||||
|
lineNumber: frame.lineNumber,
|
||||||
|
functionName: frame.name,
|
||||||
|
language: frame.language,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let NSGetFactory = XPCOMUtils.generateNSGetFactory([ConsoleAPI]);
|
let NSGetFactory = XPCOMUtils.generateNSGetFactory([ConsoleAPI]);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
* Contributor(s):
|
* Contributor(s):
|
||||||
* David Dahl <ddahl@mozilla.com>
|
* David Dahl <ddahl@mozilla.com>
|
||||||
* Rob Campbell <rcampbell@mozilla.com>
|
* Rob Campbell <rcampbell@mozilla.com>
|
||||||
|
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||||
*
|
*
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
@ -73,15 +74,39 @@ function testConsoleData(aMessageObject) {
|
||||||
is(aMessageObject.level, gLevel, "expected level received");
|
is(aMessageObject.level, gLevel, "expected level received");
|
||||||
ok(aMessageObject.arguments, "we have arguments");
|
ok(aMessageObject.arguments, "we have arguments");
|
||||||
is(aMessageObject.arguments.length, gArgs.length, "arguments.length matches");
|
is(aMessageObject.arguments.length, gArgs.length, "arguments.length matches");
|
||||||
gArgs.forEach(function (a, i) {
|
|
||||||
is(aMessageObject.arguments[i], a, "correct arg " + i);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (aMessageObject.level == "error") {
|
if (gLevel == "trace") {
|
||||||
|
is(aMessageObject.arguments.toSource(), gArgs.toSource(),
|
||||||
|
"stack trace is correct");
|
||||||
|
|
||||||
// Test finished
|
// Test finished
|
||||||
ConsoleObserver.destroy();
|
ConsoleObserver.destroy();
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
gArgs.forEach(function (a, i) {
|
||||||
|
is(aMessageObject.arguments[i], a, "correct arg " + i);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aMessageObject.level == "error") {
|
||||||
|
// Now test console.trace()
|
||||||
|
startTraceTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startTraceTest() {
|
||||||
|
gLevel = "trace";
|
||||||
|
gArgs = [
|
||||||
|
{filename: TEST_URI, lineNumber: 6, functionName: null, language: 2},
|
||||||
|
{filename: TEST_URI, lineNumber: 11, functionName: "foobar585956b", language: 2},
|
||||||
|
{filename: TEST_URI, lineNumber: 15, functionName: "foobar585956a", language: 2},
|
||||||
|
{filename: TEST_URI, lineNumber: 1, functionName: "onclick", language: 2}
|
||||||
|
];
|
||||||
|
|
||||||
|
let button = gWindow.document.getElementById("test-trace");
|
||||||
|
ok(button, "found #test-trace button");
|
||||||
|
EventUtils.synthesizeMouse(button, 2, 2, {}, gWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
var gLevel, gArgs;
|
var gLevel, gArgs;
|
||||||
|
@ -114,6 +139,7 @@ function consoleAPISanityTest() {
|
||||||
ok(win.console.info, "console.info is here");
|
ok(win.console.info, "console.info is here");
|
||||||
ok(win.console.warn, "console.warn is here");
|
ok(win.console.warn, "console.warn is here");
|
||||||
ok(win.console.error, "console.error is here");
|
ok(win.console.error, "console.error is here");
|
||||||
|
ok(win.console.trace, "console.trace is here");
|
||||||
}
|
}
|
||||||
|
|
||||||
var ConsoleObserver = {
|
var ConsoleObserver = {
|
||||||
|
|
|
@ -2,6 +2,19 @@
|
||||||
<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
|
<html dir="ltr" xml:lang="en-US" lang="en-US"><head>
|
||||||
<title>Console API test page</title>
|
<title>Console API test page</title>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
window.foobar585956c = function(a) {
|
||||||
|
console.trace();
|
||||||
|
return a+"c";
|
||||||
|
};
|
||||||
|
|
||||||
|
function foobar585956b(a) {
|
||||||
|
return foobar585956c(a+"b");
|
||||||
|
}
|
||||||
|
|
||||||
|
function foobar585956a(omg) {
|
||||||
|
return foobar585956b(omg + "a");
|
||||||
|
}
|
||||||
|
|
||||||
function test() {
|
function test() {
|
||||||
var str = "Test Message."
|
var str = "Test Message."
|
||||||
console.foobar(str); // if this throws, we don't execute following funcs
|
console.foobar(str); // if this throws, we don't execute following funcs
|
||||||
|
@ -15,5 +28,6 @@
|
||||||
<body>
|
<body>
|
||||||
<h1>Console API Test Page</h1>
|
<h1>Console API Test Page</h1>
|
||||||
<button onclick="test();">Log stuff</button>
|
<button onclick="test();">Log stuff</button>
|
||||||
|
<button id="test-trace" onclick="foobar585956a('omg');">Test trace</button>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -26,6 +26,7 @@ function doTest() {
|
||||||
"warn": "function",
|
"warn": "function",
|
||||||
"error": "function",
|
"error": "function",
|
||||||
"debug": "function",
|
"debug": "function",
|
||||||
|
"trace": "function",
|
||||||
"__noSuchMethod__": "function"
|
"__noSuchMethod__": "function"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,7 @@ const LEVELS = {
|
||||||
warn: SEVERITY_WARNING,
|
warn: SEVERITY_WARNING,
|
||||||
info: SEVERITY_INFO,
|
info: SEVERITY_INFO,
|
||||||
log: SEVERITY_LOG,
|
log: SEVERITY_LOG,
|
||||||
|
trace: SEVERITY_LOG,
|
||||||
};
|
};
|
||||||
|
|
||||||
// The lowest HTTP response code (inclusive) that is considered an error.
|
// The lowest HTTP response code (inclusive) that is considered an error.
|
||||||
|
@ -1981,12 +1982,89 @@ HUD_SERVICE.prototype =
|
||||||
function formatResult(x) {
|
function formatResult(x) {
|
||||||
return (typeof(x) == "string") ? x : hud.jsterm.formatResult(x);
|
return (typeof(x) == "string") ? x : hud.jsterm.formatResult(x);
|
||||||
}
|
}
|
||||||
let mappedArguments = Array.map(aArguments, formatResult);
|
|
||||||
let joinedArguments = Array.join(mappedArguments, " ");
|
let body = null;
|
||||||
|
let clipboardText = null;
|
||||||
|
let sourceURL = null;
|
||||||
|
let sourceLine = 0;
|
||||||
|
|
||||||
|
switch (aLevel) {
|
||||||
|
case "log":
|
||||||
|
case "info":
|
||||||
|
case "warn":
|
||||||
|
case "error":
|
||||||
|
case "debug":
|
||||||
|
let mappedArguments = Array.map(aArguments, formatResult);
|
||||||
|
body = Array.join(mappedArguments, " ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "trace":
|
||||||
|
let filename = ConsoleUtils.abbreviateSourceURL(aArguments[0].filename);
|
||||||
|
let functionName = aArguments[0].functionName ||
|
||||||
|
this.getStr("stacktrace.anonymousFunction");
|
||||||
|
let lineNumber = aArguments[0].lineNumber;
|
||||||
|
|
||||||
|
body = this.getFormatStr("stacktrace.outputMessage",
|
||||||
|
[filename, functionName, lineNumber]);
|
||||||
|
|
||||||
|
sourceURL = aArguments[0].filename;
|
||||||
|
sourceLine = aArguments[0].lineNumber;
|
||||||
|
|
||||||
|
clipboardText = "";
|
||||||
|
|
||||||
|
aArguments.forEach(function(aFrame) {
|
||||||
|
clipboardText += aFrame.filename + " :: " +
|
||||||
|
aFrame.functionName + " :: " +
|
||||||
|
aFrame.lineNumber + "\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
clipboardText = clipboardText.trimRight();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Cu.reportError("Unknown Console API log level: " + aLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let node = ConsoleUtils.createMessageNode(hud.outputNode.ownerDocument,
|
let node = ConsoleUtils.createMessageNode(hud.outputNode.ownerDocument,
|
||||||
CATEGORY_WEBDEV,
|
CATEGORY_WEBDEV,
|
||||||
LEVELS[aLevel],
|
LEVELS[aLevel],
|
||||||
joinedArguments);
|
body,
|
||||||
|
sourceURL,
|
||||||
|
sourceLine,
|
||||||
|
clipboardText);
|
||||||
|
|
||||||
|
// Make the node bring up the property panel, to allow the user to inspect
|
||||||
|
// the stack trace.
|
||||||
|
if (aLevel == "trace") {
|
||||||
|
node._stacktrace = aArguments;
|
||||||
|
|
||||||
|
let linkNode = node.querySelector(".webconsole-msg-body");
|
||||||
|
linkNode.classList.add("hud-clickable");
|
||||||
|
linkNode.setAttribute("aria-haspopup", "true");
|
||||||
|
|
||||||
|
node.addEventListener("mousedown", function(aEvent) {
|
||||||
|
this._startX = aEvent.clientX;
|
||||||
|
this._startY = aEvent.clientY;
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
node.addEventListener("click", function(aEvent) {
|
||||||
|
if (aEvent.detail != 1 || aEvent.button != 0 ||
|
||||||
|
(this._startX != aEvent.clientX &&
|
||||||
|
this._startY != aEvent.clientY)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._panelOpen) {
|
||||||
|
let propPanel = hud.jsterm.openPropertyPanel(null,
|
||||||
|
node._stacktrace,
|
||||||
|
this);
|
||||||
|
propPanel.panel.setAttribute("hudId", aHUDId);
|
||||||
|
this._panelOpen = true;
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
ConsoleUtils.outputMessageNode(node, aHUDId);
|
ConsoleUtils.outputMessageNode(node, aHUDId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,7 @@ _BROWSER_TEST_FILES = \
|
||||||
browser_webconsole_bug_632347_iterators_generators.js \
|
browser_webconsole_bug_632347_iterators_generators.js \
|
||||||
browser_webconsole_bug_642108_refForOutputNode.js \
|
browser_webconsole_bug_642108_refForOutputNode.js \
|
||||||
browser_webconsole_bug_642108_pruneTest.js \
|
browser_webconsole_bug_642108_pruneTest.js \
|
||||||
|
browser_webconsole_bug_585956_console_trace.js \
|
||||||
head.js \
|
head.js \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
@ -199,6 +200,7 @@ _BROWSER_TEST_PAGES = \
|
||||||
test-bug-630733-response-redirect-headers.sjs \
|
test-bug-630733-response-redirect-headers.sjs \
|
||||||
test-bug-621644-jsterm-dollar.html \
|
test-bug-621644-jsterm-dollar.html \
|
||||||
test-bug-632347-iterators-generators.html \
|
test-bug-632347-iterators-generators.html \
|
||||||
|
test-bug-585956-console-trace.html \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
libs:: $(_BROWSER_TEST_FILES)
|
libs:: $(_BROWSER_TEST_FILES)
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||||
|
/* ***** BEGIN LICENSE BLOCK *****
|
||||||
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||||
|
*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||||||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
* http://www.mozilla.org/MPL/
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||||
|
* for the specific language governing rights and limitations under the
|
||||||
|
* License.
|
||||||
|
*
|
||||||
|
* The Original Code is Web Console test suite.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is
|
||||||
|
* The Mozilla Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Mihai Sucan <mihai.sucan@gmail.com>
|
||||||
|
*
|
||||||
|
* Alternatively, the contents of this file may be used under the terms of
|
||||||
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||||
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||||
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||||
|
* of those above. If you wish to allow use of your version of this file only
|
||||||
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||||
|
* use your version of this file under the terms of the MPL, indicate your
|
||||||
|
* decision by deleting the provisions above and replace them with the notice
|
||||||
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||||
|
* the provisions above, a recipient may use your version of this file under
|
||||||
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||||
|
*
|
||||||
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
|
const TEST_URI = "http://example.com/browser/toolkit/components/console/hudservice/tests/browser/test-bug-585956-console-trace.html";
|
||||||
|
|
||||||
|
function test() {
|
||||||
|
addTab(TEST_URI);
|
||||||
|
browser.addEventListener("load", tabLoaded, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tabLoaded() {
|
||||||
|
browser.removeEventListener("load", tabLoaded, true);
|
||||||
|
|
||||||
|
openConsole();
|
||||||
|
|
||||||
|
browser.addEventListener("load", tabReloaded, true);
|
||||||
|
content.location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function tabReloaded() {
|
||||||
|
browser.removeEventListener("load", tabReloaded, true);
|
||||||
|
|
||||||
|
// The expected stack trace object.
|
||||||
|
let stacktrace = [
|
||||||
|
{ filename: TEST_URI, lineNumber: 9, functionName: null, language: 2 },
|
||||||
|
{ filename: TEST_URI, lineNumber: 14, functionName: "foobar585956b", language: 2 },
|
||||||
|
{ filename: TEST_URI, lineNumber: 18, functionName: "foobar585956a", language: 2 },
|
||||||
|
{ filename: TEST_URI, lineNumber: 21, functionName: null, language: 2 }
|
||||||
|
];
|
||||||
|
|
||||||
|
let hudId = HUDService.getHudIdByWindow(content);
|
||||||
|
let HUD = HUDService.hudReferences[hudId];
|
||||||
|
|
||||||
|
let node = HUD.outputNode.querySelector(".hud-log");
|
||||||
|
ok(node, "found trace log node");
|
||||||
|
ok(node._stacktrace, "found stacktrace object");
|
||||||
|
is(node._stacktrace.toSource(), stacktrace.toSource(), "stacktrace is correct");
|
||||||
|
isnot(node.textContent.indexOf("bug-585956"), -1, "found file name");
|
||||||
|
|
||||||
|
finishTest();
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Web Console test for bug 585956 - console.trace()</title>
|
||||||
|
<!-- Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||||
|
<script type="application/javascript">
|
||||||
|
window.foobar585956c = function(a) {
|
||||||
|
console.trace();
|
||||||
|
return a+"c";
|
||||||
|
};
|
||||||
|
|
||||||
|
function foobar585956b(a) {
|
||||||
|
return foobar585956c(a+"b");
|
||||||
|
}
|
||||||
|
|
||||||
|
function foobar585956a(omg) {
|
||||||
|
return foobar585956b(omg + "a");
|
||||||
|
}
|
||||||
|
|
||||||
|
foobar585956a("omg");
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Web Console test for bug 585956 - console.trace().</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -11,7 +11,6 @@
|
||||||
console.clear()
|
console.clear()
|
||||||
console.dir()
|
console.dir()
|
||||||
console.dirxml()
|
console.dirxml()
|
||||||
console.trace()
|
|
||||||
console.group()
|
console.group()
|
||||||
console.groupCollapsed()
|
console.groupCollapsed()
|
||||||
console.groupEnd()
|
console.groupEnd()
|
||||||
|
|
|
@ -114,3 +114,14 @@ NetworkPanel.imageSizeDeltaDurationMS=%Sx%Spx, Δ%Sms
|
||||||
# o music/crescendo
|
# o music/crescendo
|
||||||
NetworkPanel.responseBodyUnableToDisplay.content=Unable to display responses of type "%S"
|
NetworkPanel.responseBodyUnableToDisplay.content=Unable to display responses of type "%S"
|
||||||
ConsoleAPIDisabled=The Web Console logging API (console.log, console.info, console.warn, console.error) has been disabled by a script on this page.
|
ConsoleAPIDisabled=The Web Console logging API (console.log, console.info, console.warn, console.error) has been disabled by a script on this page.
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (stacktrace.anonymousFunction):
|
||||||
|
# This string is used to display JavaScript functions that have no given name -
|
||||||
|
# they are said to be anonymous. See stacktrace.outputMessage.
|
||||||
|
stacktrace.anonymousFunction=<anonymous>
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (stacktrace.outputMessage):
|
||||||
|
# This string is used in the Web Console output to identify a web developer call
|
||||||
|
# to console.trace(). The stack trace of JavaScript function calls is displayed.
|
||||||
|
# In this minimal message we only show the last call.
|
||||||
|
stacktrace.outputMessage=Stack trace from %S, function %S, line %S.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче