172 votes

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

Je suis en train de développer une application, et je place une commande globale isDebug un interrupteur. Je voudrais envelopper console.log pour 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.');

J'obtiens alors ce résultat dans la console de Firefox.

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

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

131voto

arctelix Points 2686

Il s'agit d'une vieille question et toutes les réponses fournies sont trop bricolées, ont des problèmes MAJEURS de croisement de navigateurs et ne fournissent rien de super utile. Cette solution fonctionne dans tous les navigateurs et rapporte toutes les données de la console exactement comme il se doit. Aucun piratage nécessaire et une seule 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(){}

Il suffit ensuite d'appeler comme suit :

debug('This is happening.')

Vous pouvez même prendre le contrôle de la console.log avec un interrupteur 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 l'emballer dans une fonction réutilisable qui donne non seulement un contrôle global, mais aussi 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')
}

27voto

drzaus Points 3344

J'ai aimé Réponse de @fredrik alors je l'ai enroulé avec une autre réponse qui divise le stacktrace de Webkit et l'a fusionné avec Le wrapper console.log sûr de @PaulIrish . "Normalise" le filename:line à un "objet spécial" pour qu'il se démarque et qu'il soit pratiquement identique dans FF et Chrome.

Test dans le 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/
        /// * https://stackoverflow.com/questions/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 ---');

23voto

namuol Points 4345

Vous pouvez gérer les numéros de ligne y d'afficher le niveau du journal avec une utilisation astucieuse de la fonction 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)

En allant un peu plus loin, vous pourriez utiliser l'option console La distinction entre les erreurs, les avertissements et les informations de l'UE permet de conserver des niveaux personnalisés. Essayez-le !

function setDebug(isDebug) {
  if (isDebug) {
    window.debug = {
      log: window.console.log.bind(window.console, 'log: %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.'); // -> log: 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)

11voto

angabriel Points 1363

Ecoute McFly, c'est la seule chose qui a marché pour moi :

let debug = true;
Object.defineProperty(this, "log", {get: function () {
  return debug ? console.log.bind(window.console, '['+Date.now()+']', '[DEBUG]') 
               : function(){};}
});

// usage:
log('Back to the future');
// outputs:
[1624398754679] [DEBUG] Back to the future

L'intérêt est d'éviter un autre appel de fonction comme log('xyz')() ou pour créer un objet wrapper ou même une classe. Il est également sûr ES5.

Si vous ne voulez pas de préfixe, il suffit de supprimer le paramètre.

mise à jour inclut l'horodatage actuel en préfixe de chaque sortie de journal.

10voto

Jacob Phillips Points 3074

J'ai trouvé une solution simple pour combiner la réponse acceptée (liaison à console.log/error/etc) avec une logique externe pour filtrer ce qui est effectivement 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;

Utilisation :

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.assert utilise la journalisation conditionnelle.
  • Assurez-vous que les outils de développement de votre navigateur affichent tous les niveaux de message !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X