Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting the stack trace of an error in ExtendScript

When I catch an error in ExtendScript, I would like to be able to log its stack trace. It appears that errors do not contain stack traces in ExtendScript, so I'm playing around with the idea of adding stack traces to errors.

The only way I know of to get a stack trace is $.stack. The field $.stack contains the current stack trace at the moment that you access the field.

My first attempt was to create my own error object that includes the stack. The Error object is very special in that it can get the line and filename of the code that created it. For example,

try {
    throw new Error("Houston, we have a problem.");
}
catch (e) {
    $.writeln("Line: " + e.line);
    $.writeln("File: " + e.fileName);
    $.writeln("Message: " + e.message);
}

Will print:

Line: 2
File: ~/Desktop/Source1.jsx
Message: Houston, we have a problem.

I don't think it's possible to create your own object with this ability. The closest I can get is this:

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);
}

Which prints:

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)

Here we can see that I'm creating my own error object and explicitly passing it the line and file name (since MyError can't figure that out on its own). I've also included the current stack when the error gets created.

This works fine when I call my own error object, but it doesn't work when other code calls the regular Error object or when an error is generated automatically (e.g. by illegal access). I want to be able to get the stack trace of any error, no matter how it is generated.

Other approaches might be to modify Error's constructor, modify Error's prototype, or replace the Error object entirely. I haven't been able to get any of these approaches to work.

Another idea would be to put a catch block in every single method of my code and add the current stack to the error if it doesn't already have one. I would like to avoid this option if possible.

I'm out of ideas. Is there any way to get the stack trace of errors?

like image 716
dln385 Avatar asked Apr 24 '13 20:04

dln385


People also ask

How do I get an error stack?

Use the console. trace() method to get the stack trace from an error. The console. trace() method outputs the stack trace and shows the call path taken to reach the point at which the method was called.

What is stack trace of error?

Stack trace error is a generic term frequently associated with long error messages. The stack trace information identifies where in the program the error occurs and is helpful to programmers. For users, the long stack track information may not be very useful for troubleshooting web errors.

How can I check my browser stack trace?

You can easily see the stack trace in JavaScript by adding the following into your code: console. trace(); And you'll get an outputted stack trace.

What is error stack in JavaScript?

The non-standard stack property of Error objects offer a trace of which functions were called, in what order, from which line and file, and with what arguments. The stack string proceeds from the most recent calls to earlier ones, leading back to the original global scope call.


1 Answers

It isn't perfect, but I found a partial solution.

Fact 1: Error.prototype is an Error object.

Fact 2: The method Error.prototype.toString is called whenever an error is created.

Fact 3: The field Error.prototype.toString can be modified.

That method typically just returns the string "Error", so we can replace it with our own method that stores the stack and then returns the string "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);
}

Result:

Line: 11
File: ~/Desktop/Source10.jsx
Message: Houston, we have a problem.
Stack: [Source10.jsx]
toString()

It works! The only problem is automatic errors.

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);
}

Result:

Line: 12
File: ~/Desktop/Source12.jsx
Message: null is not an object
Stack: undefined

So it doesn't work on all errors, but its progress.

like image 114
dln385 Avatar answered Sep 20 '22 22:09

dln385