2013-04-24 16 views
7

Po wykryciu błędu w ExtendScript, chciałbym móc zarejestrować jego ślad stosu. Wygląda na to, że błędy nie zawierają śladów stosu w ExtendScript, więc bawię się z pomysłem dodawania śladów stosu do błędów.Uzyskiwanie śladu stosu błędu w ExtendScript

Jedynym sposobem, wiem, aby uzyskać ślad stosu jest $.stack. Pole $.stack zawiera bieżący ślad stosu w momencie uzyskania dostępu do pola.

Moja pierwsza próba polegała na utworzeniu własnego obiektu błędu zawierającego stos. Obiekt Error jest bardzo wyjątkowy, ponieważ może pobrać linię i nazwę pliku kodu, który go utworzył. Na przykład,

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

wypisze:

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

Nie sądzę, że to możliwe, aby stworzyć swój własny obiekt z tej zdolności. Najbliżej mogę dostać to:

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

która drukuje:

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) 

Tutaj widzimy, że tworzę mój własny obiekt o błędzie i wyraźnie przekazując mu nazwę pliku i linii (od MyError nie potrafię tego zrobić samodzielnie). Uwzględniłem także bieżący stos, gdy błąd zostanie utworzony.

Działa to dobrze, gdy zgłoszę mój własny obiekt o błędzie, ale to nie działa, gdy inny kod wywołuje regularne obiekt błędu lub gdy błąd jest generowany automatycznie (na przykład poprzez nielegalny dostęp). Chcę być w stanie uzyskać ślad stosu dowolnego błędu, bez względu na sposób jego generowania.

Inne podejścia to modyfikacja konstruktora Error, modyfikacja prototypu Error lub całkowite zastąpienie obiektu Error. Nie udało mi się uzyskać żadnego z tych podejść do działania.

Innym pomysłem byłoby umieścić blok catch w każdym sposobie mojego kodu i dodać bieżący stos do błędu, jeśli nie masz. Chciałbym omijać tę opcję, jeśli to możliwe.

Brakuje mi pomysłów. Czy istnieje sposób, aby uzyskać ślad stosu błędów?

+0

Byłbym bardzo zainteresowany, gdyby coś działało. Mój największy problem polega na tym, że zaraz po skompilowaniu do formatu jsxbin nie otrzymuję nic użytecznego od błędów. Poszedłem na trasę niesamowitej ilości zdarzeń, więc mogę debugować. –

+0

Personalny sposób użycia instrukcji $ .write lub $ .writeln. Przede wszystkim przyniosą ExtendScript Toolkit z góry, jeśli nie zostaną otwarte. To może być bardzo mylące dla użytkowników końcowych, jeśli nie są oni ostrzeżeni. Również może być naprawdę bardzo wolny, szczególnie w pętlach wewnętrznych. Wolę zapisywać pliki dziennika na dysku. Mam swój własny przepis, ale możesz skorzystać z tej biblioteki: http: //creative-scripts.com/logging-with-a-smile/ – Loic

Odpowiedz

1

Nie jest doskonały, ale znalazłem częściowe rozwiązanie.

Fakt 1: Error.prototype Przedmiotem błędu.

Fakt 2: Metoda Error.prototype.toString nazywa gdy błąd jest tworzony.

Fakt 3: Pole Error.prototype.toString można zmodyfikować.

Metoda ta zazwyczaj po prostu zwraca ciąg znaków „Error”, więc możemy zastąpić go własnym sposobem, który przechowuje stos, a następnie zwraca ciąg znaków „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); 
} 

Wynik:

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

To działa! Jedynym problemem są błędy automatyczne.

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

Wynik:

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

Więc to nie działa na wszystkich błędów, ale jej postęp.

2

Wymyśliłem inne rozwiązanie, ale ten wymaga zmiany części kodu. Zamiast wywoływać metody jak zwykle:

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

Musisz przejść do metod wywołujących tak:

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

Oto pełna przykładów, jak to działa:

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

wyjście wygląda następująco:

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

To nie jest świetne rozwiązanie, ale przynajmniej działa na wszystkie błędy.

0

Jeśli potrzebujesz po prostu pokazać niestandardową wiadomość, napisałem ten kod. Myślę, że rozwiązany, ... dla mnie jest OK.

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

Czy ktoś dostanie coś innego niż 'undefined' dla' myError.stack', które czy chodzi o pytanie PO? –

1

O ile wiem, nie można modyfikować [natywnego kodu] o Error.prototype.toString -function. Więc wpadłem na to rozwiązanie:

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

Zastosowanie:

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

Zanim napisałem tę funkcję często robił coś takiego w bloku catch:

alert(e); 

Teraz "Robię alert(ReturnCustomErrorString(e));, ale dostaję o wiele więcej przydatnych informacji. W tej chwili uważam, że to rozwiązanie jest całkiem dobre.

Powiązane problemy