web-dev-qa-db-fra.com

Comment puis-je obtenir une trace de pile JavaScript lorsque je lève une exception?

Si je jette moi-même une exception JavaScript (par exemple, throw "AArrggg"), comment puis-je obtenir la trace de la pile (dans Firebug ou autrement)? En ce moment je viens de recevoir le message.

edit: Comme beaucoup de personnes ci-dessous ont posté, il est possible d’obtenir une trace de pile pour une exception JavaScript mais je souhaite obtenir une trace de pile pour mes exceptions. Par exemple:

function foo() {
    bar(2);
}
function bar(n) {
    if (n < 2)
        throw "Oh no! 'n' is too small!"
    bar(n-1);
}

Lorsque foo est appelé, je souhaite obtenir une trace de pile comprenant les appels à foo, bar, bar.

466
David Wolever

Éditer 2 (2017):

Dans tous les navigateurs modernes, vous pouvez simplement appeler: console.trace();(Référence MDN)

Éditer 1 (2013):

Une solution meilleure (et plus simple) comme indiqué dans les commentaires sur la question initiale consiste à utiliser la propriété stack d'un objet Error comme suit:

function stackTrace() {
    var err = new Error();
    return err.stack;
}

Cela générera une sortie comme ceci:

DBX.Utils.stackTrace@http://localhost:49573/assets/js/scripts.js:44
DBX.Console.Debug@http://localhost:49573/assets/js/scripts.js:9
.success@http://localhost:49573/:462
x.Callbacks/c@http://localhost:49573/assets/js/jquery-1.10.2.min.js:4
x.Callbacks/p.fireWith@http://localhost:49573/assets/js/jquery-1.10.2.min.js:4
k@http://localhost:49573/assets/js/jquery-1.10.2.min.js:6
.send/r@http://localhost:49573/assets/js/jquery-1.10.2.min.js:6

Donner le nom de la fonction appelante avec l'URL, sa fonction appelante, etc.

Original (2009):

Une version modifiée de cet extrait peut aider quelque peu:

function stacktrace() { 
  function st2(f) {
    return !f ? [] : 
        st2(f.caller).concat([f.toString().split('(')[0].substring(9) + '(' + f.arguments.join(',') + ')']);
  }
  return st2(arguments.callee.caller);
}
670
Eugene Morozov

Notez que chrome/chrome (autres navigateurs utilisant V8) et Firefox ont une interface pratique pour obtenir une trace de pile via une propriété stack sur Erreur objets.

try {
   // Code throwing an exception
} catch(e) {
  console.log(e.stack);
}

Cela s'applique aussi bien aux exceptions de base que pour celles que vous lancez. (Considéré que vous utilisez la classe Error, ce qui est quand même une bonne pratique).

Voir les détails sur documentation V8

175
Jocelyn delalande

Dans Firefox, il semble que vous n’ayez pas besoin de lancer l’exception. Il suffit de faire

e = new Error();
console.log(e.stack);
76
Justin L.

Si vous avez firebug, il y a une option de rupture de toutes les erreurs dans l'onglet de script. Une fois que le script a atteint votre point d'arrêt, vous pouvez regarder la fenêtre de pile de firebug:

screenshot

25
Helephant

Une bonne (et simple) solution, comme indiqué dans les commentaires sur la question initiale, consiste à utiliser la propriété stack d'un objet Error de la manière suivante:

function stackTrace() {
    var err = new Error();
    return err.stack;
}

Cela générera une sortie comme ceci:

DBX.Utils.stackTrace@http://localhost:49573/assets/js/scripts.js:44
DBX.Console.Debug@http://localhost:49573/assets/js/scripts.js:9
.success@http://localhost:49573/:462
x.Callbacks/c@http://localhost:49573/assets/js/jquery-1.10.2.min.js:4
x.Callbacks/p.fireWith@http://localhost:49573/assets/js/jquery-1.10.2.min.js:4
k@http://localhost:49573/assets/js/jquery-1.10.2.min.js:6
.send/r@http://localhost:49573/assets/js/jquery-1.10.2.min.js:6

Donner le nom de la fonction appelante avec l'URL et le numéro de ligne, sa fonction appelante, etc.

J'ai une solution très élaborée et jolie que j'ai conçue pour un projet sur lequel je travaille actuellement et que j'ai extraite et retravaillée un peu pour la généraliser. C'est ici:

(function(context){
    // Only global namespace.
    var Console = {
        //Settings
        settings: {
            debug: {
                alwaysShowURL: false,
                enabled: true,
                showInfo: true
            },
            stackTrace: {
                enabled: true,
                collapsed: true,
                ignoreDebugFuncs: true,
                spacing: false
            }
        }
    };

    // String formatting prototype function.
    if (!String.prototype.format) {
        String.prototype.format = function () {
            var s = this.toString(),
                args = typeof arguments[0],
                args = (("string" == args || "number" == args) ? arguments : arguments[0]);
            if (!arguments.length)
                return s;
            for (arg in args)
                s = s.replace(RegExp("\\{" + arg + "\\}", "gi"), args[arg]);
            return s;
        }
    }

    // String repeating prototype function.
    if (!String.prototype.times) {
        String.prototype.times = function () {
            var s = this.toString(),
                tempStr = "",
                times = arguments[0];
            if (!arguments.length)
                return s;
            for (var i = 0; i < times; i++)
                tempStr += s;
            return tempStr;
        }
    }

    // Commonly used functions
    Console.debug = function () {
        if (Console.settings.debug.enabled) {
            var args = ((typeof arguments !== 'undefined') ? Array.prototype.slice.call(arguments, 0) : []),
                sUA = navigator.userAgent,
                currentBrowser = {
                    firefox: /firefox/gi.test(sUA),
                    webkit: /webkit/gi.test(sUA),
                },
                aLines = Console.stackTrace().split("\n"),
                aCurrentLine,
                iCurrIndex = ((currentBrowser.webkit) ? 3 : 2),
                sCssBlack = "color:black;",
                sCssFormat = "color:{0}; font-weight:bold;",
                sLines = "";

            if (currentBrowser.firefox)
                aCurrentLine = aLines[iCurrIndex].replace(/(.*):/, "$1@").split("@");
            else if (currentBrowser.webkit)
                aCurrentLine = aLines[iCurrIndex].replace("at ", "").replace(")", "").replace(/( \()/gi, "@").replace(/(.*):(\d*):(\d*)/, "$1@$2@$3").split("@");

            // Show info if the setting is true and there's no extra trace (would be kind of pointless).
            if (Console.settings.debug.showInfo && !Console.settings.stackTrace.enabled) {
                var sFunc = aCurrentLine[0].trim(),
                    sURL = aCurrentLine[1].trim(),
                    sURL = ((!Console.settings.debug.alwaysShowURL && context.location.href == sURL) ? "this page" : sURL),
                    sLine = aCurrentLine[2].trim(),
                    sCol;

                if (currentBrowser.webkit)
                    sCol = aCurrentLine[3].trim();

                console.info("%cOn line %c{0}%c{1}%c{2}%c of %c{3}%c inside the %c{4}%c function:".format(sLine, ((currentBrowser.webkit) ? ", column " : ""), ((currentBrowser.webkit) ? sCol : ""), sURL, sFunc),
                             sCssBlack, sCssFormat.format("red"),
                             sCssBlack, sCssFormat.format("purple"),
                             sCssBlack, sCssFormat.format("green"),
                             sCssBlack, sCssFormat.format("blue"),
                             sCssBlack);
            }

            // If the setting permits, get rid of the two obvious debug functions (Console.debug and Console.stackTrace).
            if (Console.settings.stackTrace.ignoreDebugFuncs) {
                // In WebKit (Chrome at least), there's an extra line at the top that says "Error" so adjust for this.
                if (currentBrowser.webkit)
                    aLines.shift();
                aLines.shift();
                aLines.shift();
            }

            sLines = aLines.join(((Console.settings.stackTrace.spacing) ? "\n\n" : "\n")).trim();

            trace = typeof trace !== 'undefined' ? trace : true;
            if (typeof console !== "undefined") {
                for (var arg in args)
                    console.debug(args[arg]);

                if (Console.settings.stackTrace.enabled) {
                    var sCss = "color:red; font-weight: bold;",
                        sTitle = "%c Stack Trace" + " ".times(70);

                    if (Console.settings.stackTrace.collapsed)
                        console.groupCollapsed(sTitle, sCss);
                    else
                        console.group(sTitle, sCss);

                    console.debug("%c" + sLines, "color: #666666; font-style: italic;");

                    console.groupEnd();
                }
            }
        }
    }
    Console.stackTrace = function () {
        var err = new Error();
        return err.stack;
    }

    context.Console = Console;
})(window);

Découvrez-le sur GitHub (actuellement v1.2)! Vous pouvez l’utiliser comme Console.debug("Whatever"); et, selon les réglages de Console, il imprimera le résultat et une trace de pile (ou simplement de simples informations/rien d’extraordinaire). Voici un exemple:

Console.js

Assurez-vous de jouer avec les réglages dans l'objet Console! Vous pouvez ajouter un espacement entre les lignes du tracé et le désactiver complètement. Le voici avec Console.trace réglé sur false:

No trace

Vous pouvez même désactiver le premier bit d’information affiché (définir Console.settings.debug.showInfo sur false) ou désactiver complètement le débogage (définir Console.settings.debug.enabled sur false) afin de ne jamais avoir à commenter. une déclaration de débogage à nouveau! Il suffit de les laisser et cela ne fera rien.

11
Gabriel Nahmias

Je ne pense pas que vous puissiez utiliser quoi que ce soit d'autre, mais j'ai trouvé beaucoup d'exemples de personnes qui se sont lancées.

10
Mark Biek

Vous pouvez accéder aux propriétés stack (stacktrace dans Opera) d'une instance Error même si vous l'avez lancée. Le fait est que vous devez vous assurer que vous utilisez throw new Error(string) (n'oubliez pas le nouvea au lieu de throw string.

Exemple:

try {
    0++;
} catch (e) {
    var myStackTrace = e.stack || e.stacktrace || "";
}
7
Eli Grey

Avec le navigateur Chrome, vous pouvez utiliser la méthode console.trace: https://developer.chrome.com/devtools/docs/console-api#consoletraceobject

7
sbr

Mise à jour de la réponse d'Eugene: l'objet erreur doit être lancé pour que IE (versions spécifiques?) Remplisse la propriété stack. Ce qui suit devrait fonctionner mieux que son exemple actuel et éviter de renvoyer undefined dans IE.

function stackTrace() {
  try {
    var err = new Error();
    throw err;
  } catch (err) {
    return err.stack;
  }
}

Note 1: Ce genre de chose ne devrait être fait que lors du débogage et désactivé en direct, en particulier s'il est appelé fréquemment. Note 2: Cela peut ne pas fonctionner dans tous les navigateurs, mais semble fonctionner en FF et IE 11, ce qui convient parfaitement à mes besoins.

6
Patrick Seymour

une façon d'obtenir une trace de pile réelle sur Firebug est de créer une erreur réelle, comme appeler une fonction non définie:

function foo(b){
  if (typeof b !== 'string'){
    // undefined Error type to get the call stack
    throw new ChuckNorrisError("Chuck Norris catches you.");
  }
}

function bar(a){
  foo(a);
}

foo(123);

Ou utilisez console.error() suivi d'une instruction throw puisque console.error() affiche la trace de la pile.

6
Miller Medeiros

Cela donnera une trace de pile (sous forme de tableau de chaînes) pour Chrome, Opera, Firefox et IE10 + modernes.

function getStackTrace () {

  var stack;

  try {
    throw new Error('');
  }
  catch (error) {
    stack = error.stack || '';
  }

  stack = stack.split('\n').map(function (line) { return line.trim(); });
  return stack.splice(stack[0] == 'Error' ? 2 : 1);
}

Usage:

console.log(getStackTrace().join('\n'));

Il exclut de la pile son propre appel ainsi que le titre "Erreur" utilisé par Chrome et Firefox (mais pas par IE).

Il ne devrait pas planter sur les anciens navigateurs, mais simplement renvoyer un tableau vide. Si vous avez besoin d'une solution plus universelle, regardez stacktrace.js . Sa liste de navigateurs pris en charge est vraiment impressionnante, mais à mon sens, elle est très volumineuse pour cette petite tâche à laquelle elle est destinée: 37 Ko de texte minifié, y compris toutes les dépendances.

6

Dans Google Chrome (version 19.0 et les versions ultérieures), le simple lancement d'une exception fonctionne parfaitement. Par exemple:

/* file: code.js, line numbers shown */

188: function fa() {
189:    console.log('executing fa...');
190:    fb();
191: }
192:
193: function fb() {
194:    console.log('executing fb...');
195:    fc()
196: }
197:
198: function fc() {
199:    console.log('executing fc...');
200:    throw 'error in fc...'
201: }
202:
203: fa();

affichera la trace de la pile à la sortie de la console du navigateur:

executing fa...                         code.js:189
executing fb...                         code.js:194
executing fc...                         cdoe.js:199
/* this is your stack trace */
Uncaught error in fc...                 code.js:200
    fc                                  code.js:200
    fb                                  code.js:195
    fa                                  code.js:190
    (anonymous function)                code.js:203

J'espère que cette aide.

3
Rabih Kodeih

une fonction:

function print_call_stack(err) {
    var stack = err.stack;
    console.error(stack);
}

cas d'utilisation:

     try{
         aaa.bbb;//error throw here
     }
     catch (err){
         print_call_stack(err); 
     }
2
Jaskey
<script type="text/javascript"
src="https://rawgithub.com/stacktracejs/stacktrace.js/master/stacktrace.js"></script>
<script type="text/javascript">
    try {
        // error producing code
    } catch(e) {
        var trace = printStackTrace({e: e});
        alert('Error!\n' + 'Message: ' + e.message + '\nStack trace:\n' + trace.join('\n'));
        // do something else with error
    }
</script>

ce script montrera l'erreur

2
Amir Buzo

Ce code polyfill fonctionnant dans les navigateurs modernes (2017) (IE11, Opera, Chrome, FireFox, Yandex):

printStackTrace: function () {
    var err = new Error();
    var stack = err.stack || /*old opera*/ err.stacktrace || ( /*IE11*/ console.trace ? console.trace() : "no stack info");
    return stack;
}

Autres réponses:

function stackTrace() {
  var err = new Error();
  return err.stack;
}

ne fonctionne pas dans IE 11!

Utilisation de arguments.callee.caller - ne fonctionne pas en mode strict dans aucun navigateur!

2
Petr Varyagin

Un peu en retard pour le parti, mais voici une autre solution, qui détecte automatiquement si arguments.callee est disponible, et utilise la nouvelle erreur (). Stack si ne pas. Testé en chrome, safari et firefox.

2 variantes - stackFN (n) vous donne le nom de la fonction n loin de l'appelant immédiat, et stackArray () vous donne un tableau, stackArray () [0] étant l'appelant immédiat.

Essayez-le à http://jsfiddle.net/qcP9y/6/

// returns the name of the function at caller-N
// stackFN()  = the immediate caller to stackFN
// stackFN(0) = the immediate caller to stackFN
// stackFN(1) = the caller to stackFN's caller
// stackFN(2) = and so on
// eg console.log(stackFN(),JSON.stringify(arguments),"called by",stackFN(1),"returns",retval);
function stackFN(n) {
    var r = n ? n : 0, f = arguments.callee,avail=typeof f === "function",
        s2,s = avail ? false : new Error().stack;
    if (s) {
        var tl=function(x) { s = s.substr(s.indexOf(x) + x.length);},
        tr = function (x) {s = s.substr(0, s.indexOf(x) - x.length);};
        while (r-- >= 0) {
            tl(")");
        }
        tl(" at ");
        tr("(");
        return s;
    } else {
        if (!avail) return null;
        s = "f = arguments.callee"
        while (r>=0) {
            s+=".caller";
            r--;   
        }
        eval(s);
        return f.toString().split("(")[0].trim().split(" ")[1];
    }
}
// same as stackFN() but returns an array so you can work iterate or whatever.
function stackArray() {
    var res=[],f = arguments.callee,avail=typeof f === "function",
        s2,s = avail ? false : new Error().stack;
    if (s) {
        var tl=function(x) { s = s.substr(s.indexOf(x) + x.length);},
        tr = function (x) {s = s.substr(0, s.indexOf(x) - x.length);};
        while (s.indexOf(")")>=0) {
            tl(")");
            s2= ""+s;
            tl(" at ");
            tr("(");
            res.Push(s);
            s=""+s2;
        }
    } else {
        if (!avail) return null;
        s = "f = arguments.callee.caller"
        eval(s);
        while (f) {
            res.Push(f.toString().split("(")[0].trim().split(" ")[1]);
            s+=".caller";
            eval(s);
        }
    }
    return res;
}


function Apple_makes_stuff() {
    var retval = "iPhones";
    var stk = stackArray();

    console.log("function ",stk[0]+"() was called by",stk[1]+"()");
    console.log(stk);
    console.log(stackFN(),JSON.stringify(arguments),"called by",stackFN(1),"returns",retval);
    return retval;
}



function Apple_makes (){
    return Apple_makes_stuff("really Nice stuff");
}

function Apple () {
    return Apple_makes();
}

   Apple();
1
unsynchronized

Vous pouvez utiliser cette bibliothèque http://www.stacktracejs.com/ . C'est très bien

De la documentation

Vous pouvez également transmettre votre propre erreur pour obtenir un stacktrace non disponible dans IE ou Safari 5-

<script type="text/javascript" src="https://rawgithub.com/stacktracejs/stacktrace.js/master/stacktrace.js"></script>
<script type="text/javascript">
    try {
        // error producing code
    } catch(e) {
        var trace = printStackTrace({e: e});
        alert('Error!\n' + 'Message: ' + e.message + '\nStack trace:\n' + trace.join('\n'));
        // do something else with error
    }
</script>
1
Doua Beri

Voici une réponse qui vous donne les performances maximales (IE 6+) et la compatibilité maximale. Compatible avec IE 6!

    function stacktrace( log_result ) {
        var trace_result;
    // IE 6 through 9 compatibility
    // this is NOT an all-around solution because
    // the callee property of arguments is depredicated
    /*@cc_on
        // theese fancy conditinals make this code only run in IE
        trace_result = (function st2(fTmp) {
                // credit to Eugene for this part of the code
                return !fTmp ? [] :
                        st2(fTmp.caller).concat([fTmp.toString().split('(')[0].substring(9) + '(' + fTmp.arguments.join(',') + ')']);
        })(arguments.callee.caller);
        if (log_result) // the ancient way to log to the console
                Debug.write( trace_result );
        return trace_result;
    @*/
        console = console || Console;   // just in case
        if (!(console && console.trace) || !log_result){
                // for better performance in IE 10
                var STerror=new Error();
                var unformated=(STerror.stack || STerror.stacktrace);
                trace_result = "\u25BC console.trace" + unformated.substring(unformated.indexOf('\n',unformated.indexOf('\n'))); 
        } else {
                // IE 11+ and everyone else compatibility
                trace_result = console.trace();
        }
        if (log_result)
                console.log( trace_result );
        
        return trace_result;
    }
// test code
(function testfunc(){
        document.write( "<pre>" + stacktrace( false ) + "</pre>" );
})();
1
Jack Giffin
function stacktrace(){
  return (new Error()).stack.split('\n').reverse().slice(0,-2).reverse().join('\n');
}
1
user2223787

Juste essayer

throw new Error('some error here')

Cela fonctionne plutôt bien pour le chrome:

enter image description here

0
Anthony Zhan

Je devais étudier une récursion sans fin dans smartgwt avec IE11, donc pour approfondir, il me fallait une trace de pile. Le problème était que je ne pouvais pas utiliser la console de développement, car la reproduction était plus difficile de cette façon.
Utilisez les éléments suivants dans une méthode javascript:

try{ null.toString(); } catch(e) { alert(e.stack); }
0
kirilv

Il est plus facile d’obtenir une trace de pile sur Firefox que sur IE, mais voici ce que vous voulez faire:

Enveloppez le morceau de code "problématique" dans un bloc try/catch:

try {
    // some code that doesn't work
    var t = null;
    var n = t.not_a_value;
}
    catch(e) {
}

Si vous voulez examiner le contenu de l'objet "error", il contient les champs suivants:

e.fileName: fichier/page source d'où provient le problème e.lineNumber: numéro de la ligne dans le fichier/page où le problème est survenu e.message: un simple message décrivant le type d'erreur survenu. e.name: type d'erreur ci-dessus, il doit s'agir de 'TypeError' e.stack: contient la trace de pile qui a provoqué l'exception

J'espère que cela vous aide.

0
Michael

Wow - Je ne vois pas une seule personne sur 6 ans suggérer de vérifier d'abord si stack est disponible avant de l'utiliser! La pire chose à faire dans un gestionnaire d'erreurs est de lancer une erreur car elle appelle quelque chose qui n'existe pas.

Comme d'autres l'ont dit, bien que stack puisse être utilisé en toute sécurité, il n'est plus pris en charge par IE9 ou une version antérieure.

Je me connecte mes erreurs inattendues et une trace de la pile est assez essentielle. Pour un soutien maximal, je vérifie d’abord si Error.prototype.stack existe et est une fonction. Si c'est le cas, il est prudent d'utiliser error.stack.

        window.onerror = function (message: string, filename?: string, line?: number, 
                                   col?: number, error?: Error)
        {
            // always wrap error handling in a try catch
            try 
            {
                // get the stack trace, and if not supported make our own the best we can
                var msg = (typeof Error.prototype.stack == 'function') ? error.stack : 
                          "NO-STACK " + filename + ' ' + line + ':' + col + ' + message;

                // log errors here or whatever you're planning on doing
                alert(msg);
            }
            catch (err)
            {

            }
        };

Edit: Il apparaît que, puisque stack est une propriété et non une méthode, vous pouvez l'appeler en toute sécurité même sur des navigateurs plus anciens. Je suis toujours perplexe, car j’étais à peu près sûr de vérifier Error.prototype a déjà fonctionné pour moi auparavant, mais c’est maintenant le cas - je ne suis donc pas sûr de ce qui se passe.

0
Simon_Weaver

Utilisation de console.error(e.stack) Firefox ne montre que la trace de pile dans les journaux, Chrome affiche également le message. Cela peut être une mauvaise surprise si le message contient des informations vitales. Toujours connecter les deux.

0
Christophe Roussy