Un wrapper appropriato per console.log con il numero di riga corretto?


132

Ora sto sviluppando un'applicazione e inserisco uno isDebugswitch globale . Vorrei avvolgere console.logper un uso più conveniente.

//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.');

Quindi ottengo questo risultato nella console di Firefox.

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

Cosa succede se desidero accedere con il numero di riga dove debug()viene chiamato, come info: Here is a msg. main.js (line 2)?


È possibile utilizzare console.logper informazioni, console.warnavvisi e console.errorerrori, invece di aggiungere qualcosa console.logtramite una funzione wrapper.
Alvin Wong,

2
@AlvinWong Sì, lo so, ma il problema è che ho bisogno di un interruttore di debug globale, che controlla se consoledeve essere utilizzato. Per raggiungere tale obiettivo, un wrapper sembra essere l'unico modo?
Rufus,

Per Google Chrome vedi stackoverflow.com/a/25729203/1429301 Nel tuo caso il modello sarebbe debug.js
Frison Alexander

Risposte:


117

Questa è una vecchia domanda e tutte le risposte fornite sono eccessivamente complicate, hanno MAJOR problemi tra browser diversi e non forniscono nulla di super utile. Questa soluzione funziona in ogni browser e riporta tutti i dati della console esattamente come dovrebbe. Non sono necessari hack e una riga di codice Scopri il codice .

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

Crea lo switch in questo modo:

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

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

Quindi chiama semplicemente come segue:

debug('This is happening.')

Puoi persino assumere console.log con un interruttore come questo:

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

Se vuoi fare qualcosa di utile con quello .. Puoi aggiungere tutti i metodi della console e racchiuderlo in una funzione riutilizzabile che offre non solo un controllo globale, ma anche a livello di 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!')

Ora puoi aggiungerlo alle tue lezioni:

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

16
Correggimi se sbaglio, ma questo non ti consente di aggiungere alcuna funzionalità aggiuntiva, giusto? In sostanza stai solo alias l'oggetto console? Un esempio approssimativo: non c'è modo di console.log () l'evento due volte per ogni debug.log ()?
AB Carroll

3
@ABCarroll Potresti legare console.logdue volte una log()funzione personalizzata contenente due chiamate console.log, tuttavia i numeri di linea rispecchierebbero la linea su cui console.logrisiede effettivamente, non dove debug.logviene chiamata. Tuttavia, potresti fare cose come aggiungere prefissi / suffissi dinamici ecc. Ci sono anche modi per compensare il problema del numero di riga, ma penso che sia un'altra domanda.
Dai un'occhiata a

2
Questo metodo non funziona in Firefox dalla versione 47 alla 49 inclusa. Ed è stato risolto solo nella versione 50.0a2. Bene, l'FF50 uscirà tra 2 settimane, ma passo diverse ore a capire perché non funziona. Quindi penso che queste informazioni possano essere utili per qualcuno. link
Vladimir Liubimov,

Credo che @ABCarroll significhi che tutto ciò che è all'interno dell'istanza non può essere utilizzato in runtime. per un'altra istanza, lo stato globale può essere definito solo in un'istanza, quindi se in seguito si this.isDebugpassa a false, non importa. Semplicemente non so se c'è un modo per aggirare questo, forse è di progettazione. In questo senso, isDebugè piuttosto fuorviante vare dovrebbe essere constinvece un .
Cregox,

2
Questo non risponde alla domanda "Cosa succede se voglio accedere con il numero di riga in cui viene chiamato debug ()?"
technomage

24

Mi è piaciuta la risposta di @frrikrik , quindi l'ho arrotolata con un'altra risposta che divide il webkit stacktrace e l'ho unito al wrapper console.log sicuro di @ PaulIrish . "Standardizza" filename:lineun "oggetto speciale" in modo che risalti e abbia lo stesso aspetto in FF e Chrome.

Test in violino: 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

Questo funziona anche nel nodo e puoi provarlo con:

// 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 ---');

una risposta leggermente più avanzato per tener conto degli ulteriori consolemetodi come warn, error, ecc - stackoverflow.com/a/14842659/1037948
drzaus

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

@sigod - probabilmente dipende dal browser o che l'ho scritto 2 anni fa e il browser è cambiato. qual è il tuo scenario?
drzaus,

1
uno dei miei colleghi ha incollato il tuo codice nel nostro progetto. Ha rotto il sito in IE11 e Safari 5. Non sono sicuro di altre versioni di questo browser. Forse aggiungerai un segno di spunta per i futuri copiatrici?
sigod,

1
@sigod che ne dici adesso? aggiunto if(!stack) return '?'al metodo che fallisce, piuttosto che dove viene chiamato (quindi se qualcuno usa il metodo stesso sono anche "protetti")
drzaus,

18

È possibile mantenere i numeri di riga e generare il livello di registro con un uso intelligente di 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)

Facendo un ulteriore passo in avanti, potresti sfruttare le consoledistinzioni di errore / avvertenza / informazioni e avere comunque livelli personalizzati. Provalo!

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
Sto provando da un po 'di tempo a prefissare automaticamente l'output di console.debug(...)con function namee arguments- qualche idea su come farlo?
Daniel Sokolowski,

3
Ho osservato la moltitudine di wrapper / shim / ecc. Per console. e questo è il primo che ho incontrato che combina la conservazione dei numeri di riga con la personalizzazione dell'output. È un uso intelligente del fatto che .bind fa anche un po 'di curry per te, puoi associare uno o più argomenti oltre al contesto . Potresti fare un ulteriore passo avanti e passargli una funzione noop con un metodo .toString che potrebbe eseguire il codice quando viene chiamato il metodo log! Vedi questo jsfiddle
Sam Hasler

2
Forse non in tutti i browser (non l'ho esaminato), ma sostituendo il %scon %oin Chrome stamperà i parametri come ti aspetteresti (gli oggetti sono espandibili, i numeri e le stringhe sono colorati, ecc.).
Anson,

amo questa soluzione. Ho apportato alcune modifiche che funzionano meglio per la mia applicazione, ma la maggior parte è ancora intatta e funziona alla perfezione. Grazie
Ward,

9

Da: Come ottenere il numero di riga della funzione del chiamante JavaScript? Come ottenere l'URL di origine del chiamante JavaScript? l' Erroroggetto ha una proprietà del numero di riga (in FF). Quindi qualcosa del genere dovrebbe funzionare:

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

Nel browser Webkit err.stackè presente una stringa che rappresenta lo stack di chiamate corrente. Verrà visualizzato il numero di riga corrente e ulteriori informazioni.

AGGIORNARE

Per ottenere il numero di biancheria corretto è necessario richiamare l'errore su quella riga. Qualcosa di simile a:

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();mi dà il contesto in cui viene eseguito, se lo inserisco debug.js, allora otterrò info: Here is a msg. file: http://localhost/js/debug.js line:7.
Rufus,

1
Che senso ha Log = Error? Stai ancora modificando la classe Error, giusto?
drzaus,

In combinazione con la tua risposta un paio di altri - vedi sotto stackoverflow.com/a/14841411/1037948
drzaus

8

Un modo per mantenere il numero di riga è qui: https://gist.github.com/bgrins/5108712 . Si riduce più o meno a questo:

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

Potresti avvolgerlo isDebuge impostarlowindow.log su function() { }se non si esegue il debug.


7

Puoi passare il numero di riga al tuo metodo di debug, in questo modo:

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

Qui, (new Error).lineNumberti darebbe il numero di riga corrente nel tuo javascriptcodice.


2
Un po 'prolisso, vero?
Rufus,

2
Penso che sia abbastanza per rispondere alla tua domanda. :)
Subodh,

1
la proprietà lineNumber non è standard e funziona solo su Firefox in questo momento, vedi qui
Matthias

6

Chrome Devtools ti consente di raggiungere questo obiettivo con Blackboxing . È possibile creare un wrapper console.log che può avere effetti collaterali, chiamare altre funzioni, ecc. E conservare comunque il numero di riga che ha chiamato la funzione wrapper.

Basta inserire un piccolo wrapper console.log in un file separato, ad es

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

Assegnalo a qualcosa come log-blackbox.js

Quindi vai alle impostazioni di Chrome Devtools e trova la sezione "Blackboxing", aggiungi uno schema per il nome del file che desideri inserire nella blackbox, in questo caso log-blackbox.js


Nota: assicurarsi di non avere alcun codice che si desidera visualizzare nella traccia dello stack nello stesso file, poiché verrà rimosso anche dalla traccia.
Jamesthollowell,

6

Ho trovato una soluzione semplice per combinare la risposta accettata (associazione a console.log / error / etc) con una logica esterna per filtrare ciò che è effettivamente registrato.

// 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;

Uso:

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
  • Si noti che console.assertutilizza la registrazione condizionale.
  • Assicurati che gli strumenti di sviluppo del tuo browser mostrino tutti i livelli dei messaggi!

Perché non fornisce alcun numero di riga né esempi funzionanti che mostrano il livello di registro.
not2qubit

Il numero di riga sarà lo stesso che se si utilizza direttamente la console. Ho aggiornato la risposta con esempi di utilizzo. Non ha molti voti perché gli ho risposto due anni dopo :)
Jacob Phillips,

4

Se vuoi semplicemente controllare se viene utilizzato il debug e avere il numero di riga corretto, puoi invece farlo:

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

Quando è necessario l'accesso al debug, è possibile effettuare ciò:

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

Se isDebug == true, I numeri di riga e i nomi dei file visualizzati nella console saranno corretti, poiché debug.logetc è in realtà un alias diconsole.log ecc.

Se isDebug == falsenon viene mostrato alcun messaggio di debug, perché debug.logetc semplicemente non fa nulla (una funzione vuota).

Come già sapete, una funzione wrapper confonderà i numeri di riga e i nomi dei file, quindi è una buona idea impedire l'uso delle funzioni wrapper.


Fantastico, devo stare attento all'ordine di isDebug = truee debug.js, ma questa risposta funziona!
Rufus,

3
window.debug = window.consolesarebbe un po 'più pulito.
Fredrik,

@fredrik allora dovrò "implementare" tutte le funzioni membro se isDebug == false. : {
Alvin Wong l'

@AlvinWong I menat for if isDebug===true. O evento a questo: jsfiddle.net/fredrik/x6Jw5
fredrik l'

4

Le soluzioni di analisi dello stack visualizzano il numero di riga ma non consentono di fare clic per passare all'origine, il che rappresenta un grave problema. L'unica soluzione per mantenere questo comportamento è legarsi alla funzione originale.

Il binding impedisce di includere la logica intermedia, poiché questa logica interferirebbe con i numeri di riga. Tuttavia, ridefinendo le funzioni associate e giocando con la sostituzione delle stringhe della console , è ancora possibile un comportamento aggiuntivo.

Questa sintesi mostra un framework di registrazione minimalista che offre moduli, livelli di registro, formattazione e numeri di riga selezionabili corretti in 34 righe. Usalo come base o ispirazione per le tue esigenze.

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

EDIT: gist incluso di seguito

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


Questa risposta ha solo 3 voti, ma è incredibilmente più ricca e pulita di qualsiasi altra nella pagina
Tom,

tuttavia, sembra che tutte le parti utili siano su un contenuto esterno.
Ryan The Leach,

3

L'idea con bind Function.prototype.bindè geniale. È inoltre possibile utilizzare il logger di righe della libreria npm . Mostra i file di origine:

Crea logger chiunque una volta nel tuo progetto:

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

Stampa registri:

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

inserisci qui la descrizione dell'immagine


2

Ecco un modo per conservare le consoledichiarazioni di registrazione esistenti durante l'aggiunta di un nome file e numero di riga o altre informazioni di traccia stack sull'output:

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

Quindi usalo in questo modo:

<!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>

Funziona con Firefox, Opera, Safari, Chrome e IE 10 (non ancora testato su IE11 o Edge).


Bel lavoro, ma non è ancora al 100% quello di cui ho bisogno. Vorrei avere le informazioni sul nome file e sul numero di riga sul lato destro della vista console, dove è possibile fare clic per aprire l'origine. Questa soluzione mostra le informazioni come parte del messaggio (come questo:) my test log message (myscript.js:42) VM167 mypage.html:15, che non è buono da leggere e non è collegato. Ancora un buon lavoro quindi un voto positivo.
Frederic Leitenberger,

Sì, mentre sarebbe l'ideale, non c'è modo, AFAIK, di falsificare il collegamento al nome file che appare nella console ...
Brett Zamir,

@BrettZamir postato una domanda su questo codice qui: 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.'));

Questo mi darà info: "Here is a msg." main.js(line:2).

Ma evalè necessario un extra , peccato.


2
eval è il male! Quindi ogni male.
Fredrik,

1

Codice da 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);

Questo non sembra mostrare il numero della linea originale da cui logviene chiamato
ragamufin

Sono quasi sicuro che abbia funzionato durante il test, ma ho sostituito il codice con la versione "completa" della stessa pagina. Ha funzionato almeno in Chrome 45.
Timo Kähkönen,

Inteso. Con le modifiche che hai ora è essenzialmente lo stesso di alcune delle altre risposte e funziona. Ero solo curioso del tuo codice precedente perché alla fine avevi un'applicazione che mi ha permesso di usarlo per più, ma dal momento che non mostrava il numero di riga ero tornato al punto di partenza. Grazie comunque!
Ragamufin,

1

Ho esaminato questo problema da solo ultimamente. Necessario qualcosa di molto semplice per controllare la registrazione, ma anche per conservare i numeri di riga. La mia soluzione non sembra elegante nel codice, ma fornisce ciò che è necessario per me. Se uno è abbastanza attento con chiusure e ritenzione.

Ho aggiunto un piccolo wrapper all'inizio dell'applicazione:

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

In modo che in seguito posso semplicemente fare:

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

L'ho testato su Firefox e Chrome, ed entrambi i browser sembrano mostrare il registro della console come previsto. Se riempi in questo modo, puoi sempre estendere il metodo 'd' e passargli altri parametri, in modo che possa fare qualche registrazione extra.

Non ho ancora riscontrato seri inconvenienti per il mio approccio, tranne la brutta riga nel codice per la registrazione.


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

ecco la mia soluzione su questa domanda. quando si chiama il metodo: log, verrà stampato il numero di riga in cui si stampa il registro


1

Una piccola variazione è quella di avere debug () restituire una funzione, che viene quindi eseguita dove serve - debug (message) (); e quindi mostra correttamente il numero di riga corretto e lo script chiamante nella finestra della console, consentendo variazioni come il reindirizzamento come avviso o il salvataggio su file.

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

}

Poiché restituisce una funzione, tale funzione deve essere eseguita sulla riga di debug con () ;. In secondo luogo, il messaggio viene inviato alla funzione di debug, piuttosto che alla funzione restituita, consentendo la pre-elaborazione o il controllo di cui potresti aver bisogno, ad esempio il controllo dello stato a livello di registro, rendendo il messaggio più leggibile, saltando tipi diversi o riportando solo elementi soddisfare i criteri a livello di registro;

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

1

Puoi semplificare la logica qui. Ciò presuppone che il tuo flag di debug globale NON sia dinamico e impostato sul caricamento dell'app o passato come una configurazione. Questo è destinato all'uso per la segnalazione ambientale (ad es. Stampa solo in modalità sviluppo e non produzione)

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

Modulo:

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

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

export default Logger;

1.x angolare:

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

Ora devi solo sostituire tutti i riferimenti della console con Logger


1

Questa implementazione si basa sulla risposta selezionata e aiuta a ridurre la quantità di rumore nella console degli errori: 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

Ho trovato alcune delle risposte a questo problema un po 'troppo complesse per le mie esigenze. Ecco una soluzione semplice, resa in Coffeescript. Si è adattato dalla versione di Brian Grinstead qui

Presuppone l'oggetto 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

Il modo in cui l'ho risolto è stato quello di creare un oggetto, quindi creare una nuova proprietà sull'oggetto usando Object.defineProperty () e restituire la proprietà console, che è stata quindi utilizzata come funzione normale, ma ora con la capacità estesa.

var c = {};
var debugMode = true;

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

Quindi, per definire una proprietà devi solo ...

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

E ora puoi usare la tua funzione proprio come

c.error("Error!");

0

Sulla base di altre risposte (principalmente @arctelix one) ho creato questo per Node ES6, ma un test rapido ha mostrato buoni risultati anche nel browser. Sto solo passando l'altra funzione come riferimento.

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

0

Ecco la mia funzione di logger (basata su alcune delle risposte). Spero che qualcuno possa farne uso:

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

Esempi:

log( 'warn', 'log message', 'my_function' );
log( 'info', 'log message' );
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.