Un wrapper approprié pour console.log avec le numéro de ligne correct?


132

Je développe actuellement une application et place un isDebugcommutateur global . Je voudrais envelopper console.logpour une utilisation plus pratique.

//isDebug controls the entire site.
var isDebug = true;

//debug.js
function debug(msg, level){
    var Global = this;
    if(!(Global.isDebug && Global.console && Global.console.log)){
        return;
    }
    level = level||'info';
    Global.console.log(level + ': '+ msg);
}

//main.js
debug('Here is a msg.');

Ensuite, j'obtiens ce résultat dans la console Firefox.

info: Here is a msg.                       debug.js (line 8)

Et si je veux me connecter avec le numéro de ligne où debug()est appelé, comme info: Here is a msg. main.js (line 2)?


Vous pouvez utiliser console.logpour info, console.warnpour avertissement et console.errorpour erreur, au lieu d'ajouter quelque chose console.logvia une fonction wrapper.
Alvin Wong du

2
@AlvinWong Oui, je le sais, mais le problème est que j'ai besoin d'un commutateur de débogage global, qui contrôle s'il consoledoit être utilisé. Pour atteindre un tel objectif, un wrapper semble être le seul moyen?
Rufus

Pour Google Chrome, consultez stackoverflow.com/a/25729203/1429301 Dans votre cas, le modèle serait debug.js
Frison Alexander

Réponses:


117

C'est une vieille question et toutes les réponses fournies sont trop piratées, ont des problèmes MAJEURS entre navigateurs et ne fournissent rien de super utile. Cette solution fonctionne dans chaque navigateur et signale toutes les données de la console exactement comme il se doit. Aucun piratage requis et une ligne de code Vérifiez le codepen .

var debug = console.log.bind(window.console)

Créez le commutateur comme ceci:

isDebug = true // toggle this to turn on / off for global controll

if (isDebug) var debug = console.log.bind(window.console)
else var debug = function(){}

Ensuite, appelez simplement comme suit:

debug('This is happening.')

Vous pouvez même prendre en charge le console.log avec un commutateur comme celui-ci:

if (!isDebug) console.log = function(){}

Si vous voulez faire quelque chose d'utile avec ça ... Vous pouvez ajouter toutes les méthodes de la console et les encapsuler dans une fonction réutilisable qui donne non seulement un contrôle global, mais également au niveau de la classe:

var Debugger = function(gState, klass) {

  this.debug = {}

  if (gState && klass.isDebug) {
    for (var m in console)
      if (typeof console[m] == 'function')
        this.debug[m] = console[m].bind(window.console, klass.toString()+": ")
  }else{
    for (var m in console)
      if (typeof console[m] == 'function')
        this.debug[m] = function(){}
  }
  return this.debug
}

isDebug = true //global debug state

debug = Debugger(isDebug, this)

debug.log('Hello log!')
debug.trace('Hello trace!')

Vous pouvez maintenant l'ajouter à vos cours:

var MyClass = function() {
  this.isDebug = true //local state
  this.debug = Debugger(isDebug, this)
  this.debug.warn('It works in classses')
}

16
Corrigez-moi si je me trompe, mais cela ne vous permet pas d'ajouter des fonctionnalités supplémentaires, n'est-ce pas? Vous aliasez essentiellement uniquement l'objet console? Un exemple grossier - il n'y a aucun moyen de console.log () l'événement deux fois pour chaque debug.log ()?
AB Carroll

3
@ABCarroll Vous pouvez le faire console.logdeux fois en liant une log()fonction personnalisée contenant deux appels à console.log, mais les numéros de ligne refléteraient la ligne sur laquelle console.logse trouve réellement, pas où debug.logest appelée. Cependant, vous pouvez faire des choses comme ajouter des préfixes / suffixes dynamiques, etc. Il existe également des moyens de compenser le problème du numéro de ligne, mais c'est une autre question que je pense. Consultez ce projet pour un exemple: github.com/arctelix/iDebugConsole/blob/master/README.md
arctelix

2
Cette méthode ne fonctionne pas dans Firefox de la version 47 à 49 inclus. Et a été corrigé uniquement dans la version 50.0a2. Eh bien FF50 sortira dans 2 semaines, mais je passe plusieurs heures à comprendre pourquoi ça ne marche pas. Je pense donc que cette information peut être utile pour quelqu'un. lien
Vladimir Liubimov

Je crois que ce que @ABCarroll voulait dire, c'est que tout ce qui se trouve dans l'instance ne peut pas être utilisé à l'exécution. pour une autre instance, l'état global ne peut être défini que dans l'instanciation, donc si vous changez ultérieurement this.isDebugen false, cela n'aura pas d'importance. Je ne sais juste pas s'il existe un moyen de contourner cela, peut-être que c'est par conception. En ce sens, le isDebugest un assez trompeur varet devrait être un à la constplace.
cregox

2
Cela ne répond pas à la question "Et si je veux me connecter avec le numéro de ligne où debug () est appelé?"
technomage

24

J'ai aimé la réponse de @ fredrik , alors je l'ai enroulée avec une autre réponse qui divise le stacktrace de Webkit , et l' ai fusionnée avec le wrapper sécurisé console.log de @ PaulIrish . "Standardise" le filename:lineen un "objet spécial" pour qu'il se démarque et se présente pratiquement de la même manière dans FF et Chrome.

Test en violon: http://jsfiddle.net/drzaus/pWe6W/

_log = (function (undefined) {
    var Log = Error; // does this do anything?  proper inheritance...?
    Log.prototype.write = function (args) {
        /// <summary>
        /// Paulirish-like console.log wrapper.  Includes stack trace via @fredrik SO suggestion (see remarks for sources).
        /// </summary>
        /// <param name="args" type="Array">list of details to log, as provided by `arguments`</param>
        /// <remarks>Includes line numbers by calling Error object -- see
        /// * http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
        /// * /programming/13815640/a-proper-wrapper-for-console-log-with-correct-line-number
        /// * https://stackoverflow.com/a/3806596/1037948
        /// </remarks>

        // via @fredrik SO trace suggestion; wrapping in special construct so it stands out
        var suffix = {
            "@": (this.lineNumber
                    ? this.fileName + ':' + this.lineNumber + ":1" // add arbitrary column value for chrome linking
                    : extractLineNumberFromStack(this.stack)
            )
        };

        args = args.concat([suffix]);
        // via @paulirish console wrapper
        if (console && console.log) {
            if (console.log.apply) { console.log.apply(console, args); } else { console.log(args); } // nicer display in some browsers
        }
    };
    var extractLineNumberFromStack = function (stack) {
        /// <summary>
        /// Get the line/filename detail from a Webkit stack trace.  See https://stackoverflow.com/a/3806596/1037948
        /// </summary>
        /// <param name="stack" type="String">the stack string</param>

        if(!stack) return '?'; // fix undefined issue reported by @sigod

        // correct line number according to how Log().write implemented
        var line = stack.split('\n')[2];
        // fix for various display text
        line = (line.indexOf(' (') >= 0
            ? line.split(' (')[1].substring(0, line.length - 1)
            : line.split('at ')[1]
            );
        return line;
    };

    return function (params) {
        /// <summary>
        /// Paulirish-like console.log wrapper
        /// </summary>
        /// <param name="params" type="[...]">list your logging parameters</param>

        // only if explicitly true somewhere
        if (typeof DEBUGMODE === typeof undefined || !DEBUGMODE) return;

        // call handler extension which provides stack trace
        Log().write(Array.prototype.slice.call(arguments, 0)); // turn into proper array
    };//--  fn  returned

})();//--- _log

Cela fonctionne également dans node, et vous pouvez le tester avec:

// no debug mode
_log('this should not appear');

// turn it on
DEBUGMODE = true;

_log('you should', 'see this', {a:1, b:2, c:3});
console.log('--- regular log ---');
_log('you should', 'also see this', {a:4, b:8, c:16});

// turn it off
DEBUGMODE = false;

_log('disabled, should not appear');
console.log('--- regular log2 ---');

une réponse un peu plus avancés pour expliquer les supplémentaires des consoleméthodes telles que warn, error, etc - stackoverflow.com/a/14842659/1037948
drzaus

1
var line = stack.split('\n')[2];-'undefined' is not an object
sigod

@sigod - dépend probablement du navigateur, ou que j'ai écrit ceci il y a 2 ans et que le (s) navigateur (s) ont changé. quel est votre scénario?
drzaus

1
un de mes collègues a copié-collé votre code dans notre projet. Il a cassé le site dans IE11 et Safari 5. Je ne suis pas sûr des autres versions de ce navigateur. Peut-être que vous ajouterez un chèque pour les futurs copieurs-colleurs?
sigod

1
@sigod et maintenant? ajouté if(!stack) return '?'à la méthode qui échoue, plutôt que là où elle est appelée (donc si quelqu'un utilise la méthode elle-même, ils sont également "protégés")
drzaus

18

Vous pouvez gérer les numéros de ligne et afficher le niveau de journalisation avec une utilisation intelligente de Function.prototype.bind:

function setDebug(isDebug) {
  if (window.isDebug) {
    window.debug = window.console.log.bind(window.console, '%s: %s');
  } else {
    window.debug = function() {};
  }
}

setDebug(true);

// ...

debug('level', 'This is my message.'); // --> level: This is my message. (line X)

Pour aller plus loin, vous pouvez utiliser les consoledistinctions erreur / avertissement / info de l 'et toujours avoir des niveaux personnalisés. Essayez-le!

function setDebug(isDebug) {
  if (isDebug) {
    window.debug = {
      log: window.console.log.bind(window.console, '%s: %s'),
      error: window.console.error.bind(window.console, 'error: %s'),
      info: window.console.info.bind(window.console, 'info: %s'),
      warn: window.console.warn.bind(window.console, 'warn: %s')
    };
  } else {
    var __no_op = function() {};

    window.debug = {
      log: __no_op,
      error: __no_op,
      warn: __no_op,
      info: __no_op
    }
  }
}

setDebug(true);

// ...

debug.log('wat', 'Yay custom levels.'); // -> wat: Yay custom levels.    (line X)
debug.info('This is info.');            // -> info: This is info.        (line Y)
debug.error('Bad stuff happened.');     // -> error: Bad stuff happened. (line Z)

1
J'essaie depuis un moment maintenant de préfixer automatiquement la sortie de console.debug(...)avec function nameet arguments- des pensées sur la façon de faire cela?
Daniel Sokolowski

3
J'ai regardé la multitude de wrappers / shims / etc de console. et c'est le premier que j'ai rencontré qui combine la préservation des numéros de ligne avec la personnalisation de la sortie. C'est une utilisation intelligente du fait que .bind fait également du curry pour vous, vous pouvez lier un ou plusieurs arguments en plus du contexte . Vous pouvez aller plus loin et lui passer une fonction noop avec une méthode .toString qui pourrait exécuter du code lorsque la méthode log est appelée! Voir ce jsfiddle
Sam Hasler

2
Peut-être pas dans tous les navigateurs (je ne l'ai pas regardé), mais remplacer le %spar %odans Chrome imprimera les paramètres de la manière attendue (les objets sont extensibles, les nombres et les chaînes sont colorés, etc.).
anson

J'adore cette solution. J'ai apporté quelques modifications qui fonctionnent mieux pour mon application, mais la majeure partie est toujours intacte et fonctionne parfaitement. Merci
Ward

9

De: Comment obtenir le numéro de ligne de fonction de l'appelant JavaScript? Comment obtenir l'URL de la source de l'appelant JavaScript? l' Errorobjet a une propriété de numéro de ligne (en FF). Donc, quelque chose comme ça devrait fonctionner:

var err = new Error();
Global.console.log(level + ': '+ msg + 'file: ' + err.fileName + ' line:' + err.lineNumber);

Dans le navigateur Webkit, vous avez err.stackune chaîne représentant la pile d'appels actuelle. Il affichera le numéro de ligne actuel et plus d'informations.

METTRE À JOUR

Pour obtenir le numéro de lin correct, vous devez invoquer l'erreur sur cette ligne. Quelque chose comme:

var Log = Error;
Log.prototype.write = function () {
    var args = Array.prototype.slice.call(arguments, 0),
        suffix = this.lineNumber ? 'line: '  + this.lineNumber : 'stack: ' + this.stack;

    console.log.apply(console, args.concat([suffix]));
};

var a = Log().write('monkey' + 1, 'test: ' + 2);

var b = Log().write('hello' + 3, 'test: ' + 4);

1
new Error();me donne le contexte dans lequel il s'exécute, si je le mets debug.js, alors j'obtiendrai info: Here is a msg. file: http://localhost/js/debug.js line:7.
Rufus

1
À quoi ça sert Log = Error? Vous modifiez toujours la classe Error, non?
drzaus

Combiné votre réponse avec quelques autres - voir ci-dessous stackoverflow.com/a/14841411/1037948
drzaus

8

Un moyen de conserver le numéro de ligne est ici: https://gist.github.com/bgrins/5108712 . Cela se résume plus ou moins à ceci:

if (Function.prototype.bind) {
    window.log = Function.prototype.bind.call(console.log, console);
}
else {
    window.log = function() { 
        Function.prototype.apply.call(console.log, console, arguments);
    };
}

Vous pouvez encapsuler cela avec isDebuget définir window.logsur function() { }si vous ne déboguez pas.


7

Vous pouvez transmettre le numéro de ligne à votre méthode de débogage, comme ceci:

//main.js
debug('Here is a msg.', (new Error).lineNumber);

Ici, (new Error).lineNumbervous donnerait le numéro de ligne actuel dans votre javascriptcode.


2
Un peu verbeux, n'est-ce pas?
Rufus

2
Je pense que cela suffit pour répondre à votre question. :)
Subodh

1
la propriété lineNumber n'est pas standard et ne fonctionne que sur Firefox pour le moment, voir ici
Matthias

6

Chrome Devtools vous permet d'y parvenir avec Blackboxing . Vous pouvez créer un wrapper console.log qui peut avoir des effets secondaires, appeler d'autres fonctions, etc., tout en conservant le numéro de ligne qui a appelé la fonction wrapper.

Mettez simplement un petit wrapper console.log dans un fichier séparé, par exemple

(function() {
    var consolelog = console.log
    console.log = function() {
        // you may do something with side effects here.
        // log to a remote server, whatever you want. here
        // for example we append the log message to the DOM
        var p = document.createElement('p')
        var args = Array.prototype.slice.apply(arguments)
        p.innerText = JSON.stringify(args)
        document.body.appendChild(p)

        // call the original console.log function
        consolelog.apply(console,arguments)
    }
})()

Nommez-le quelque chose comme log-blackbox.js

Ensuite, allez dans les paramètres de Chrome Devtools et trouvez la section "Blackboxing", ajoutez un modèle pour le nom de fichier que vous voulez blackbox, dans ce cas log-blackbox.js


Remarque: assurez-vous que vous n'avez pas de code que vous voudriez afficher dans la trace de pile dans le même fichier, car il sera également supprimé de la trace.
jamesthollowell

6

J'ai trouvé une solution simple pour combiner la réponse acceptée (liaison à console.log / error / etc) avec une logique extérieure pour filtrer ce qui est réellement enregistré.

// or window.log = {...}
var log = {
  ASSERT: 1, ERROR: 2, WARN: 3, INFO: 4, DEBUG: 5, VERBOSE: 6,
  set level(level) {
    if (level >= this.ASSERT) this.a = console.assert.bind(window.console);
    else this.a = function() {};
    if (level >= this.ERROR) this.e = console.error.bind(window.console);
    else this.e = function() {};
    if (level >= this.WARN) this.w = console.warn.bind(window.console);
    else this.w = function() {};
    if (level >= this.INFO) this.i = console.info.bind(window.console);
    else this.i = function() {};
    if (level >= this.DEBUG) this.d = console.debug.bind(window.console);
    else this.d = function() {};
    if (level >= this.VERBOSE) this.v = console.log.bind(window.console);
    else this.v = function() {};
    this.loggingLevel = level;
  },
  get level() { return this.loggingLevel; }
};
log.level = log.DEBUG;

Usage:

log.e('Error doing the thing!', e); // console.error
log.w('Bonus feature failed to load.'); // console.warn
log.i('Signed in.'); // console.info
log.d('Is this working as expected?'); // console.debug
log.v('Old debug messages, output dominating messages'); // console.log; ignored because `log.level` is set to `DEBUG`
log.a(someVar == 2) // console.assert
  • Notez que console.assertutilise la journalisation conditionnelle.
  • Assurez-vous que les outils de développement de votre navigateur affichent tous les niveaux de message!

Parce qu'il ne donne aucun numéro de ligne ni d'exemples fonctionnels montrant le niveau de journalisation.
not2qubit

Le numéro de ligne sera le même que si vous utilisez directement la console. J'ai mis à jour la réponse avec des exemples d'utilisation. Il n'y a pas beaucoup de votes car j'y ai répondu deux ans plus tard :)
Jacob Phillips

4

Si vous souhaitez simplement contrôler si le débogage est utilisé et avoir le numéro de ligne correct, vous pouvez le faire à la place:

if(isDebug && window.console && console.log && console.warn && console.error){
    window.debug = {
        'log': window.console.log,
        'warn': window.console.warn,
        'error': window.console.error
    };
}else{
    window.debug = {
        'log': function(){},
        'warn': function(){},
        'error': function(){}
    };
}

Lorsque vous avez besoin d'accéder au débogage, vous pouvez le faire:

debug.log("log");
debug.warn("warn");
debug.error("error");

Si isDebug == true, Les numéros de ligne et les noms de fichiers affichés dans la console seront corrects, car debug.logetc est en fait un alias de console.logetc.

Si isDebug == falseaucun message de débogage n'est affiché, car debug.logetc ne fait simplement rien (une fonction vide).

Comme vous le savez déjà, une fonction wrapper gâchera les numéros de ligne et les noms de fichiers, c'est donc une bonne idée d'éviter d'utiliser les fonctions wrapper.


Super, je dois faire attention à l'ordre de isDebug = trueet debug.js, mais cette réponse fonctionne!
Rufus

3
window.debug = window.consoleserait un peu plus propre.
fredrik

@fredrik alors je devrai "implémenter" toutes les fonctions membres si isDebug == false. : {
Alvin Wong

@AlvinWong Je viens de menat pour si isDebug===true. Ou événement à ceci: jsfiddle.net/fredrik/x6Jw5
fredrik

4

Les solutions de trace de pile affichent le numéro de ligne mais ne permettent pas de cliquer pour aller à la source, ce qui est un problème majeur. La seule solution pour conserver ce comportement est de se lier à la fonction d'origine.

La liaison empêche d'inclure une logique intermédiaire, car cette logique perturberait les numéros de ligne. Cependant, en redéfinissant les fonctions liées et en jouant avec la substitution de chaînes de console , un comportement supplémentaire est toujours possible.

Cet essentiel montre un cadre de journalisation minimaliste qui offre des modules, des niveaux de journalisation, un formatage et des numéros de ligne cliquables appropriés en 34 lignes. Utilisez-le comme une base ou une inspiration pour vos propres besoins.

var log = Logger.get("module").level(Logger.WARN);
log.error("An error has occured", errorObject);
log("Always show this.");

EDIT: l'essentiel inclus ci-dessous

/*
 * Copyright 2016, Matthieu Dumas
 * This work is licensed under the Creative Commons Attribution 4.0 International License.
 * To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/
 */

/* Usage : 
 * var log = Logger.get("myModule") // .level(Logger.ALL) implicit
 * log.info("always a string as first argument", then, other, stuff)
 * log.level(Logger.WARN) // or ALL, DEBUG, INFO, WARN, ERROR, OFF
 * log.debug("does not show")
 * log("but this does because direct call on logger is not filtered by level")
 */
var Logger = (function() {
    var levels = {
        ALL:100,
        DEBUG:100,
        INFO:200,
        WARN:300,
        ERROR:400,
        OFF:500
    };
    var loggerCache = {};
    var cons = window.console;
    var noop = function() {};
    var level = function(level) {
        this.error = level<=levels.ERROR ? cons.error.bind(cons, "["+this.id+"] - ERROR - %s") : noop;
        this.warn = level<=levels.WARN ? cons.warn.bind(cons, "["+this.id+"] - WARN - %s") : noop;
        this.info = level<=levels.INFO ? cons.info.bind(cons, "["+this.id+"] - INFO - %s") : noop;
        this.debug = level<=levels.DEBUG ? cons.log.bind(cons, "["+this.id+"] - DEBUG - %s") : noop;
        this.log = cons.log.bind(cons, "["+this.id+"] %s");
        return this;
    };
    levels.get = function(id) {
        var res = loggerCache[id];
        if (!res) {
            var ctx = {id:id,level:level}; // create a context
            ctx.level(Logger.ALL); // apply level
            res = ctx.log; // extract the log function, copy context to it and returns it
            for (var prop in ctx)
                res[prop] = ctx[prop];
            loggerCache[id] = res;
        }
        return res;
    };
    return levels; // return levels augmented with "get"
})();


Cette réponse n'a que 3 votes positifs, mais elle est incroyablement plus riche et propre que toute autre dans la page
Tom

cependant, il semble que toutes les parties utiles soient sur une base externe.
Ryan The Leach

3

L'idée avec bind Function.prototype.bindest géniale. Vous pouvez également utiliser l' enregistreur de lignes de la bibliothèque npm . Il montre les fichiers source d'origine:

Créez un enregistreur n'importe qui une fois dans votre projet:

var LoggerFactory = require('lines-logger').LoggerFactory;
var loggerFactory = new LoggerFactory();
var logger = loggerFactory.getLoggerColor('global', '#753e01');

Imprimer les journaux:

logger.log('Hello world!')();

entrez la description de l'image ici


2

Voici un moyen de conserver vos consoleinstructions de journalisation existantes tout en ajoutant un nom de fichier et un numéro de ligne ou d'autres informations de trace de pile sur la sortie:

(function () {
  'use strict';
  var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
  var isChrome = !!window.chrome && !!window.chrome.webstore;
  var isIE = /*@cc_on!@*/false || !!document.documentMode;
  var isEdge = !isIE && !!window.StyleMedia;
  var isPhantom = (/PhantomJS/).test(navigator.userAgent);
  Object.defineProperties(console, ['log', 'info', 'warn', 'error'].reduce(function (props, method) {
    var _consoleMethod = console[method].bind(console);
    props[method] = {
      value: function MyError () {
        var stackPos = isOpera || isChrome ? 2 : 1;
        var err = new Error();
        if (isIE || isEdge || isPhantom) { // Untested in Edge
          try { // Stack not yet defined until thrown per https://docs.microsoft.com/en-us/scripting/javascript/reference/stack-property-error-javascript
            throw err;
          } catch (e) {
            err = e;
          }
          stackPos = isPhantom ? 1 : 2;
        }

        var a = arguments;
        if (err.stack) {
          var st = err.stack.split('\n')[stackPos]; // We could utilize the whole stack after the 0th index
          var argEnd = a.length - 1;
          [].slice.call(a).reverse().some(function(arg, i) {
            var pos = argEnd - i;
            if (typeof a[pos] !== 'string') {
              return false;
            }
            if (typeof a[0] === 'string' && a[0].indexOf('%') > -1) { pos = 0 } // If formatting
            a[pos] += ' \u00a0 (' + st.slice(0, st.lastIndexOf(':')) // Strip out character count
              .slice(st.lastIndexOf('/') + 1) + ')'; // Leave only path and line (which also avoids ":" changing Safari console formatting)
            return true;
          });
        }
        return _consoleMethod.apply(null, a);
      }
    };
    return props;
  }, {}));
}());

Ensuite, utilisez-le comme ceci:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <script src="console-log.js"></script>
</head>
<body>
  <script>
  function a () {
    console.log('xyz'); // xyz   (console-log.html:10)
  }
  console.info('abc'); // abc   (console-log.html:12)
  console.log('%cdef', "color:red;"); // (IN RED:) // def   (console-log.html:13)
  a();
  console.warn('uuu'); // uuu   (console-log.html:15)
  console.error('yyy'); // yyy   (console-log.html:16)
  </script>
</body>
</html>

Cela fonctionne dans Firefox, Opera, Safari, Chrome et IE 10 (pas encore testé sur IE11 ou Edge).


Beau travail, mais toujours pas à 100% de ce dont j'ai besoin. Je voudrais avoir les informations de nom de fichier et de numéro de ligne sur le côté droit de la vue de la console, où il peut être cliqué pour ouvrir la source. Cette solution affiche les informations dans le cadre du message (comme ceci:) my test log message (myscript.js:42) VM167 mypage.html:15, qui n'est pas aussi bon à lire et n'est pas lié. Encore du bon travail donc un vote positif.
Frederic Leitenberger

Ouais, alors que ce serait idéal, il n'y a aucun moyen, AFAIK, d'usurper le lien de nom de fichier qui apparaît dans la console ...
Brett Zamir

@BrettZamir a posté une question sur ce code ici: stackoverflow.com/questions/52618368/…
Mahks

1
//isDebug controls the entire site.
var isDebug = true;

//debug.js
function debug(msg, level){
    var Global = this;
    if(!(Global.isDebug && Global.console && Global.console.log)){
        return;
    }
    level = level||'info';
    return 'console.log(\'' + level + ': '+ JSON.stringify(msg) + '\')';
}

//main.js
eval(debug('Here is a msg.'));

Cela me donnera info: "Here is a msg." main.js(line:2).

Mais le plus evalest nécessaire, dommage.


2
eval est mal! Donc, chaque mal.
fredrik

1

Code de http://www.briangrinstead.com/blog/console-log-helper-function :

// Full version of `log` that:
//  * Prevents errors on console methods when no console present.
//  * Exposes a global 'log' function that preserves line numbering and formatting.
(function () {
  var method;
  var noop = function () { };
  var methods = [
      'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
      'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
      'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
      'timeStamp', 'trace', 'warn'
  ];
  var length = methods.length;
  var console = (window.console = window.console || {});

  while (length--) {
    method = methods[length];

    // Only stub undefined methods.
    if (!console[method]) {
        console[method] = noop;
    }
  }


  if (Function.prototype.bind) {
    window.log = Function.prototype.bind.call(console.log, console);
  }
  else {
    window.log = function() { 
      Function.prototype.apply.call(console.log, console, arguments);
    };
  }
})();

var a = {b:1};
var d = "test";
log(a, d);

Cela ne semble pas montrer le numéro de ligne d'origine d'où logest appelé
ragamufin

Je suis presque sûr que cela a fonctionné lorsque j'ai testé, mais j'ai remplacé le code par la version "complète" de la même page. A travaillé au moins dans Chrome 45.
Timo Kähkönen

Compris. Avec les changements que vous avez maintenant, c'est essentiellement la même chose que quelques-unes des autres réponses et fonctionne. J'étais juste curieux de connaître votre code précédent parce que vous aviez une application à la fin qui a soulevé des possibilités intéressantes pour moi de l'utiliser pour plus, mais comme il n'affichait pas le numéro de ligne, j'étais de retour à la case départ. Merci quand même!
ragamufin

1

J'ai moi-même étudié cette question ces derniers temps. Besoin de quelque chose de très simple pour contrôler la journalisation, mais aussi pour conserver les numéros de ligne. Ma solution n'a pas l'air aussi élégante dans le code, mais fournit ce dont j'ai besoin. Si l'on est assez prudent avec les fermetures et les retenues.

J'ai ajouté un petit wrapper au début de l'application:

window.log = {
    log_level: 5,
    d: function (level, cb) {
        if (level < this.log_level) {
            cb();
        }
    }
};

Pour que plus tard, je puisse simplement faire:

log.d(3, function(){console.log("file loaded: utils.js");});

Je l'ai testé avec Firefox et Crome, et les deux navigateurs semblent afficher le journal de la console comme prévu. Si vous remplissez comme ça, vous pouvez toujours étendre la méthode 'd' et lui passer d'autres paramètres, afin qu'elle puisse effectuer une journalisation supplémentaire.

Je n'ai encore trouvé aucun inconvénient sérieux pour mon approche, à l'exception de la ligne laide dans le code pour la journalisation.


1

window.line = function () {
    var error = new Error(''),
        brower = {
            ie: !-[1,], // !!window.ActiveXObject || "ActiveXObject" in window
            opera: ~window.navigator.userAgent.indexOf("Opera"),
            firefox: ~window.navigator.userAgent.indexOf("Firefox"),
            chrome: ~window.navigator.userAgent.indexOf("Chrome"),
            safari: ~window.navigator.userAgent.indexOf("Safari"), // /^((?!chrome).)*safari/i.test(navigator.userAgent)?
        },
        todo = function () {
            // TODO: 
            console.error('a new island was found, please told the line()\'s author(roastwind)');        
        },
        line = (function(error, origin){
            // line, column, sourceURL
            if(error.stack){
                var line,
                    baseStr = '',
                    stacks = error.stack.split('\n');
                    stackLength = stacks.length,
                    isSupport = false;
                // mac版本chrome(55.0.2883.95 (64-bit))
                if(stackLength == 11 || brower.chrome){
                    line = stacks[3];
                    isSupport = true;
                // mac版本safari(10.0.1 (12602.2.14.0.7))
                }else if(brower.safari){
                    line = stacks[2];
                    isSupport = true;
                }else{
                    todo();
                }
                if(isSupport){
                    line = ~line.indexOf(origin) ? line.replace(origin, '') : line;
                    line = ~line.indexOf('/') ? line.substring(line.indexOf('/')+1, line.lastIndexOf(':')) : line;
                }
                return line;
            }else{
                todo();
            }
            return '😭';
        })(error, window.location.origin);
    return line;
}
window.log = function () {
    var _line = window.line.apply(arguments.callee.caller),
        args = Array.prototype.slice.call(arguments, 0).concat(['\t\t\t@'+_line]);
    window.console.log.apply(window.console, args);
}
log('hello');

voici ma solution à cette question. lorsque vous appelez la méthode: log, il imprimera le numéro de ligne où vous imprimez votre journal


1

Une petite variante est que debug () renvoie une fonction, qui est ensuite exécutée là où vous en avez besoin - debug (message) (); et affiche ainsi correctement le numéro de ligne et le script d'appel corrects dans la fenêtre de la console, tout en permettant des variations comme la redirection en tant qu'alerte ou l'enregistrement dans un fichier.

var debugmode='console';
var debugloglevel=3;

function debug(msg, type, level) {

  if(level && level>=debugloglevel) {
    return(function() {});
  }

  switch(debugmode) {
    case 'alert':
      return(alert.bind(window, type+": "+msg));
    break;
    case 'console':
      return(console.log.bind(window.console, type+": "+msg));
    break;
    default:
      return (function() {});
  }

}

Puisqu'elle renvoie une fonction, cette fonction doit être exécutée à la ligne de débogage avec () ;. Deuxièmement, le message est envoyé à la fonction de débogage, plutôt que dans la fonction retournée, permettant le prétraitement ou la vérification dont vous pourriez avoir besoin, comme la vérification de l'état au niveau du journal, rendant le message plus lisible, sautant différents types ou rapportant uniquement des éléments répondre aux critères de niveau de journalisation;

debug(message, "serious", 1)();
debug(message, "minor", 4)();

1

Vous pouvez simplifier la logique ici. Cela suppose que votre indicateur de débogage global n'est PAS dynamique et défini lors du chargement de l'application ou transmis en tant que configuration. Ceci est destiné à être utilisé pour le marquage de l'environnement (par exemple, imprimer uniquement en mode développement et non en production)

Vanille JS:

(function(window){ 
  var Logger = {},
      noop = function(){};

  ['log', 'debug', 'info', 'warn', 'error'].forEach(function(level){
    Logger[level] = window.isDebug ? window.console[level] : noop;
  });

  window.Logger = Logger;
})(this);

ES6:

((window) => {
  const Logger = {};
  const noop = function(){};

  ['log', 'debug', 'info', 'warn', 'error'].forEach((level) => {
    Logger[level] = window.isDebug ? window.console[level] : noop;
  });

  window.Logger = Logger;
})(this);

Module:

const Logger = {};
const noop = function(){};

['log', 'debug', 'info', 'warn', 'error'].forEach((level) => {
  Logger[level] = window.isDebug ? window.console[level] : noop;
});

export default Logger;

Angulaire 1.x:

angular
  .module('logger', [])
  .factory('Logger', ['$window',
    function Logger($window) {
      const noop = function(){};
      const logger = {};

      ['log', 'debug', 'info', 'warn', 'error'].forEach((level) => {
        logger[level] = $window.isDebug ? $window.console[level] : noop;
      });

      return logger;
    }
  ]);

Tout ce que vous aurez à faire maintenant est de remplacer toutes les références de console par Logger


1

Cette implémentation est basée sur la réponse sélectionnée et permet de réduire la quantité de bruit dans la console d'erreur: https://stackoverflow.com/a/32928812/516126

var Logging = Logging || {};

const LOG_LEVEL_ERROR = 0,
    LOG_LEVEL_WARNING = 1,
    LOG_LEVEL_INFO = 2,
    LOG_LEVEL_DEBUG = 3;

Logging.setLogLevel = function (level) {
    const NOOP = function () { }
    Logging.logLevel = level;
    Logging.debug = (Logging.logLevel >= LOG_LEVEL_DEBUG) ? console.log.bind(window.console) : NOOP;
    Logging.info = (Logging.logLevel >= LOG_LEVEL_INFO) ? console.log.bind(window.console) : NOOP;
    Logging.warning = (Logging.logLevel >= LOG_LEVEL_WARNING) ? console.log.bind(window.console) : NOOP;
    Logging.error = (Logging.logLevel >= LOG_LEVEL_ERROR) ? console.log.bind(window.console) : NOOP;

}

Logging.setLogLevel(LOG_LEVEL_INFO);

0

J'ai trouvé certaines des réponses à ce problème un peu trop complexes pour mes besoins. Voici une solution simple, rendue dans Coffeescript. It'a adapté de la version de Brian Grinstead ici

Il suppose l'objet de la console globale.

# exposes a global 'log' function that preserves line numbering and formatting.
(() ->
    methods = [
      'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
      'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
      'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
      'timeStamp', 'trace', 'warn']
    noop = () ->
    # stub undefined methods.
    for m in methods  when  !console[m]
        console[m] = noop

    if Function.prototype.bind?
        window.log = Function.prototype.bind.call(console.log, console);
    else
        window.log = () ->
            Function.prototype.apply.call(console.log, console, arguments)
)()

0

La façon dont je l'ai résolu était de créer un objet, puis de créer une nouvelle propriété sur l'objet en utilisant Object.defineProperty () et de renvoyer la propriété console, qui était ensuite utilisée comme fonction normale, mais maintenant avec la capacité étendue.

var c = {};
var debugMode = true;

var createConsoleFunction = function(property) {
    Object.defineProperty(c, property, {
        get: function() {
            if(debugMode)
                return console[property];
            else
                return function() {};
        }
    });
};

Ensuite, pour définir une propriété il vous suffit de faire ...

createConsoleFunction("warn");
createConsoleFunction("log");
createConsoleFunction("trace");
createConsoleFunction("clear");
createConsoleFunction("error");
createConsoleFunction("info");

Et maintenant, vous pouvez utiliser votre fonction comme

c.error("Error!");

0

Sur la base d'autres réponses (principalement @arctelix one), j'ai créé ceci pour Node ES6, mais un test rapide a également montré de bons résultats dans le navigateur. Je passe simplement l'autre fonction comme référence.

let debug = () => {};
if (process.argv.includes('-v')) {
    debug = console.log;
    // debug = console; // For full object access
}

0

Voici ma fonction d'enregistrement (basée sur certaines des réponses). J'espère que quelqu'un pourra en profiter:

const DEBUG = true;

let log = function ( lvl, msg, fun ) {};

if ( DEBUG === true ) {
    log = function ( lvl, msg, fun ) {
        const d = new Date();
        const timestamp = '[' + d.getHours() + ':' + d.getMinutes() + ':' +
            d.getSeconds() + '.' + d.getMilliseconds() + ']';
        let stackEntry = new Error().stack.split( '\n' )[2];
        if ( stackEntry === 'undefined' || stackEntry === null ) {
            stackEntry = new Error().stack.split( '\n' )[1];
        }
        if ( typeof fun === 'undefined' || fun === null ) {
            fun = stackEntry.substring( stackEntry.indexOf( 'at' ) + 3,
                stackEntry.lastIndexOf( ' ' ) );
            if ( fun === 'undefined' || fun === null || fun.length <= 1 ) {
                fun = 'anonymous';
            }
        }
        const idx = stackEntry.lastIndexOf( '/' );
        let file;
        if ( idx !== -1 ) {
            file = stackEntry.substring( idx + 1, stackEntry.length - 1 );
        } else {
            file = stackEntry.substring( stackEntry.lastIndexOf( '\\' ) + 1,
                stackEntry.length - 1 );
        }
        if ( file === 'undefined' || file === null ) {
            file = '<>';
        }

        const m = timestamp + ' ' + file + '::' + fun + '(): ' + msg;

        switch ( lvl ) {
        case 'log': console.log( m ); break;
        case 'debug': console.log( m ); break;
        case 'info': console.info( m ); break;
        case 'warn': console.warn( m ); break;
        case 'err': console.error( m ); break;
        default: console.log( m ); break;
        }
    };
}

Exemples:

log( 'warn', 'log message', 'my_function' );
log( 'info', 'log message' );
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.