2013-04-24 18 views
7

Quando rilevo un errore in ExtendScript, vorrei poter registrare la traccia dello stack. Sembra che gli errori non contengano tracce di stack in ExtendScript, quindi mi sto prendendo gioco dell'idea di aggiungere tracce di stack agli errori.Come ottenere la traccia dello stack di un errore in ExtendScript

L'unico modo che conosco per ottenere una traccia stack è $.stack. Il campo $.stack contiene la traccia dello stack corrente nel momento in cui si accede al campo.

Il mio primo tentativo è stato creare il mio oggetto errore che includesse lo stack. L'oggetto Error è molto speciale in quanto può ottenere la riga e il nome file del codice che lo ha creato. Ad esempio,

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

stamperà:

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

non credo sia possibile creare il proprio oggetto con questa capacità. Il più vicino che posso ottenere è questo:

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

che stampa:

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) 

Qui possiamo vedere che sto creando il mio proprio oggetto di errore e in modo esplicito passandogli il nome della linea e il file (dal MyError non riesco a capirlo da solo). Ho anche incluso lo stack corrente quando viene creato l'errore.

Questo funziona correttamente quando chiamo il mio oggetto errore, ma non funziona quando un altro codice chiama l'oggetto Error normale o quando viene generato automaticamente un errore (ad esempio tramite accesso illegale). Voglio essere in grado di ottenere la traccia dello stack di qualsiasi errore, indipendentemente da come viene generato.

Altri approcci potrebbero essere modificare il costruttore di Error, modificare il prototipo di Error o sostituire interamente l'oggetto Error. Non sono stato in grado di far funzionare nessuno di questi approcci.

Un'altra idea sarebbe quella di mettere un blocco catch in ogni singolo metodo del mio codice e aggiungere lo stack corrente all'errore se non ne ha già uno. Vorrei evitare questa opzione se possibile.

Sono fuori di idee. C'è un modo per ottenere la traccia dello stack di errori?

+0

Sarei davvero interessato se si ottiene qualcosa di lavoro. Il mio problema più grande è che non appena compilo in un formato jsxbin non ottengo nulla di utile dagli errori. Ho seguito il percorso di un'incredibile quantità di registrazione, quindi posso eseguire il debug di questo. –

+0

Personnaly Non ho usato le istruzioni $ .write o $ .writeln. Prima di tutto porteranno in anticipo il Toolkit di ExtendScript se non lo hai aperto. Questo può davvero confondere gli utenti finali se non non sono avvertiti. Inoltre può essere davvero molto lento, specialmente all'interno dei loop. Preferisco scrivere file di registro sul disco. Ho la mia ricetta ma puoi approfittare di questa libreria: http: //creative-scripts.com/logging-with-a-smile/ – Loic

risposta

1

Non è perfetto, ma ho trovato una soluzione parziale.

Fact 1: Error.prototype è un oggetto Error.

Fatto 2: Il metodo Error.prototype.toString viene chiamato ogni volta che viene creato un errore.

Fatto 3: Il campo Error.prototype.toString può essere modificato.

Questo metodo in genere restituisce la stringa "Errore", quindi è possibile sostituirlo con il nostro metodo che memorizza lo stack e restituisce la stringa "Errore".

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

Risultato:

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

funziona! L'unico problema sono gli errori automatici.

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

Risultato:

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

Così non funziona su tutti gli errori, ma il suo progresso.

2

Ho trovato un'altra soluzione, anche se questa richiede di modificare parte del codice. Invece di chiamare i metodi come al solito:

myObject.myMethod1("Hello", "world"); 

Avrai bisogno di passare a metodi di chiamata in questo modo:

myObject.do("myMethod1", "Hello", "world"); 

Ecco un esempio completo di come funziona:

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

Il l'output è il seguente:

Hello, world! 
Stack: [do.jsx] 
stackHelper("myMethod1","Hello","world") 
myMethod1("Hello","world") 
stackHelper("myMethod2","Hello","world") 
myMethod2("Hello","world") 
stackHelper("myMethod3","Hello","world") 

Non è un'ottima soluzione, ma almeno funziona su tutti gli errori.

0

Se è necessario mostrare semplicemente un messaggio personalizzato, ho scritto questo codice. Penso che abbia risolto, ... per me va bene.

try 
{ 
    app.selection[0].contents = 1 
} 
catch (myError) 
{ 
    alert(myError.number); // For check the number error 
    if (myError.number == 30477) 
    { 
     alert("Mensagem Edu\n" + "Line: " + myError.line + "\n" + "File: " + myError.fileName + "\n" + "Message: " + myError.message + "\n" + "Stack: " + myError.stack); 
     exit(); 
    } 
    else (myError); 
    {} 
    exit(); 
} 
+0

Qualcuno ottiene qualcosa di diverso da 'undefined' per' myError.stack', che è il punto della domanda dell'OP? –

1

Per quanto ne so, non è possibile modificare il [codice nativo] del Error.prototype.toString -funzione. Così mi si avvicinò con questa soluzione:

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

Usage:

try { 
    // code that does throw an error 
} catch (e) { 
    alert(ReturnCustomErrorString(e)); 
} 

Prima di scrivere questa funzione facevo spesso qualcosa di simile nella cattura-block:

alert(e); 

Ora Sto facendo alert(ReturnCustomErrorString(e));, ma ottengo molte più informazioni utili. Quindi al momento penso che questa soluzione sia abbastanza buona.

Problemi correlati