在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)); ,但我得到更多有用的信息。 所以目前我认为这个解决方案非常好。

链接地址: http://www.djcxy.com/p/71199.html

上一篇: Getting the stack trace of an error in ExtendScript

下一篇: case performance in ECMAscript