在ExtendScript中获取错误的堆栈跟踪
当我在ExtendScript中发现错误时,我希望能够记录它的堆栈跟踪。 看起来错误不包含ExtendScript中的堆栈跟踪,所以我在玩堆栈跟踪到错误的想法。
我知道获取堆栈跟踪的唯一方法是$.stack
。 字段$.stack
包含您访问该字段时的当前堆栈跟踪。
我的第一个尝试是创建我自己的包含堆栈的错误对象。 Error
对象非常特别,它可以获取创建它的代码的行和文件名。 例如,
try {
throw new Error("Houston, we have a problem.");
}
catch (e) {
$.writeln("Line: " + e.line);
$.writeln("File: " + e.fileName);
$.writeln("Message: " + e.message);
}
将打印:
Line: 2
File: ~/Desktop/Source1.jsx
Message: Houston, we have a problem.
我不认为有这种能力创建自己的对象是不可能的。 我能得到的最接近的是:
function MyError(msg, file, line) {
this.message = msg;
this.fileName = file;
this.line = line;
this.stack = $.stack;
}
try {
throw new MyError("Houston, we have a problem.", $.fileName, $.line);
}
catch (e) {
$.writeln("Line: " + e.line);
$.writeln("File: " + e.fileName);
$.writeln("Message: " + e.message);
$.writeln("Stack: " + e.stack);
}
打印:
Line: 9
File: ~/Desktop/Source2.jsx
Message: Houston, we have a problem.
Stack: [Source3.jsx]
MyError("Houston, we have a p"...,"~/Desktop/Source2.js"...,9)
在这里我们可以看到,我创建了自己的错误对象,并明确地将它传递给行和文件名(因为MyError无法自行解决这个问题)。 在创建错误时,我还包含了当前的堆栈。
当我调用自己的错误对象时,这可以正常工作,但当其他代码调用常规错误对象或自动生成错误(例如,通过非法访问)时,它不起作用。 我希望能够获得任何错误的堆栈跟踪,不管它是如何生成的。
其他方法可能是修改Error
的构造函数,修改Error
的原型,或完全替换Error
对象。 我还没有能够得到任何这些方法的工作。
另一个想法是在我的代码的每个单一方法中放入一个catch块,并将当前堆栈添加到错误中(如果它没有的话)。 如果可能的话,我想避免这个选项。
我没有想法。 有什么办法来获得错误的堆栈跟踪?
我已经想出了另一种解决方案,虽然这需要您更改一些代码。 不像往常一样调用方法:
myObject.myMethod1("Hello", "world");
你需要切换到这样的调用方法:
myObject.do("myMethod1", "Hello", "world");
以下是它的工作原理的完整示例:
Object.prototype.do = function stackHelper() {
// Convert the arguments into an array.
var argumentArray = Array.prototype.slice.call(arguments);
// Remove the first argument, which is the function's name.
var functionString = argumentArray.shift();
try {
this[functionString].apply(this, argumentArray);
}
catch (e) {
if (typeof e.stack === "undefined" || e.stack === null) {
e.stack = $.stack;
}
throw e;
}
};
var myObject = {
myMethod1: function myMethod1(myArg1, myArg2){
this.do("myMethod2", myArg1, myArg2);
},
myMethod2: function myMethod2(myArg1, myArg2){
this.do("myMethod3", myArg1, myArg2);
},
myMethod3: function myMethod3(myArg1, myArg2){
$.writeln(myArg1 + ", " + myArg2 + "!");
var foo = null;
foo.bar; // Throws an error.
},
};
try {
myObject.do("myMethod1", "Hello", "world");
}
catch (e) {
$.writeln("Stack: " + e.stack);
}
输出如下所示:
Hello, world!
Stack: [do.jsx]
stackHelper("myMethod1","Hello","world")
myMethod1("Hello","world")
stackHelper("myMethod2","Hello","world")
myMethod2("Hello","world")
stackHelper("myMethod3","Hello","world")
这不是一个很好的解决方案,但至少可以解决所有错误。
这并不完美,但我找到了一个部分解决方案。
事实1: Error.prototype
是一个Error对象。
事实2:无论何时创建错误,都会调用Error.prototype.toString
方法。
事实3:可以修改Error.prototype.toString
字段。
该方法通常只返回字符串“Error”,所以我们可以用我们自己的方法来替换它,存储堆栈然后返回字符串“Error”。
Error.prototype.toString = function() {
if (typeof this.stack === "undefined" || this.stack === null) {
this.stack = "placeholder";
// The previous line is needed because the next line may indirectly call this method.
this.stack = $.stack;
}
return "Error";
}
try {
throw new Error("Houston, we have a problem.");
}
catch (e) {
$.writeln("Line: " + e.line);
$.writeln("File: " + e.fileName);
$.writeln("Message: " + e.message);
$.writeln("Stack: " + e.stack);
}
结果:
Line: 11
File: ~/Desktop/Source10.jsx
Message: Houston, we have a problem.
Stack: [Source10.jsx]
toString()
有用! 唯一的问题是自动错误。
Error.prototype.toString = function() {
if (typeof this.stack === "undefined" || this.stack === null) {
this.stack = "placeholder";
// The previous line is needed because the next line may indirectly call this method.
this.stack = $.stack;
}
return "Error";
}
try {
var foo = null;
foo.bar;
}
catch (e) {
$.writeln("Line: " + e.line);
$.writeln("File: " + e.fileName);
$.writeln("Message: " + e.message);
$.writeln("Stack: " + e.stack);
}
结果:
Line: 12
File: ~/Desktop/Source12.jsx
Message: null is not an object
Stack: undefined
所以它不适用于所有的错误,但它的进展。
据我所知,你不能修改Error.prototype.toString
函数的[native code]。 所以我想出了这个解决方案:
function ReturnCustomErrorString(e, additionalMessage)
{
try {
var errorString = e.toString();
errorString = errorString.concat("n", "additionalMessage: " + additionalMessage + "n", "file: " + e.fileName + "n", "line: " + e.line + "n", "stack-trace: n" + $.stack);
return errorString;
}
catch (e) {
alert("Error in : " + ReturnCustomErrorString.name + "(...)n" + e);
exit();
}
}
用法:
try {
// code that does throw an error
} catch (e) {
alert(ReturnCustomErrorString(e));
}
在我写这个函数之前,我经常在catch-block中做这样的事情:
alert(e);
现在我正在做alert(ReturnCustomErrorString(e));
,但我得到更多有用的信息。 所以目前我认为这个解决方案非常好。