Pembungkus yang tepat untuk console.log dengan nomor baris yang benar?

132

Saya sekarang sedang mengembangkan aplikasi, dan melakukan isDebugperalihan global . Saya ingin membungkus console.loguntuk penggunaan yang lebih nyaman.

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

Lalu saya mendapatkan hasil ini di konsol Firefox.

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

Bagaimana jika saya ingin login dengan nomor baris di mana debug()dipanggil, seperti info: Here is a msg. main.js (line 2)?

Rufus
sumber
Anda dapat menggunakan console.loginfo, console.warnuntuk peringatan dan console.errorkesalahan, alih-alih menambahkan sesuatu console.logmelalui fungsi wrapper.
Alvin Wong
2
@ AlvinWong Ya saya tahu itu, tapi masalahnya adalah saya perlu saklar debug global, yang mengontrol apakah consoleperlu digunakan. Untuk mencapai tujuan tersebut, pembungkus sepertinya menjadi satu-satunya cara?
Rufus
Untuk Google Chrome, lihat stackoverflow.com/a/25729203/1429301 Dalam kasus Anda polanya adalah debug.js
Frison Alexander

Jawaban:

117

Ini adalah pertanyaan lama dan Semua jawaban yang diberikan terlalu hackey, memiliki masalah lintas browser UTAMA, dan tidak memberikan sesuatu yang super berguna. Solusi ini berfungsi di setiap browser dan melaporkan semua data konsol persis seperti yang seharusnya. Tidak diperlukan peretasan dan satu baris kode. Lihat codepen .

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

Buat sakelar seperti ini:

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

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

Maka cukup hubungi sebagai berikut:

debug('This is happening.')

Anda bahkan dapat mengambil alih console.log dengan sakelar seperti ini:

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

Jika Anda ingin melakukan sesuatu yang bermanfaat dengan itu .. Anda dapat menambahkan semua metode konsol dan membungkusnya dalam fungsi yang dapat digunakan kembali yang tidak hanya memberikan kontrol global, tetapi juga tingkat kelas:

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

Sekarang Anda dapat menambahkannya ke kelas Anda:

var MyClass = function() {
  this.isDebug = true //local state
  this.debug = Debugger(isDebug, this)
  this.debug.warn('It works in classses')
}
arctelix
sumber
16
Perbaiki saya jika saya salah, tetapi ini tidak memungkinkan Anda untuk menambahkan fungsionalitas tambahan, benarkan? Anda pada dasarnya hanya aliasing objek konsol? Contoh kasar - tidak ada cara untuk console.log () acara dua kali untuk setiap debug.log ()?
AB Carroll
3
@ABCarroll Anda dapat console.logdua kali dengan mengikat log()fungsi kustom yang berisi dua panggilan console.log, namun nomor baris akan mencerminkan baris yang console.logsebenarnya berada, bukan tempat debug.logdipanggil. Namun, Anda dapat melakukan hal-hal seperti menambahkan awalan dinamis / sufiks dll. Ada juga cara untuk mengkompensasi masalah nomor baris, tapi itu pertanyaan lain yang saya pikir. Lihat proyek ini sebagai contoh: github.com/arctelix/iDebugConsole/blob/master/README.md
arctelix
2
Metode ini tidak berfungsi di Firefox dari versi 47 hingga 49 inklusif. Dan diperbaiki hanya dalam versi 50.0a2. Yah FF50 akan dirilis dalam 2 minggu, tapi saya menghabiskan beberapa jam untuk menyadari mengapa itu tidak berhasil. Jadi saya pikir informasi ini mungkin bermanfaat bagi seseorang. tautan
Vladimir Liubimov
Saya percaya apa yang dimaksud dengan @ABCarroll adalah semua yang ada di dalam instance tidak dapat digunakan dalam runtime. misalnya lain, negara global hanya dapat didefinisikan dalam Instansiasi, jadi jika Anda kemudian mengubah this.isDebugke false, tidak akan peduli. Saya hanya tidak tahu apakah ada jalan keluarnya, mungkin karena desain. Dalam hal itu, itu isDebugadalah hal yang cukup menyesatkan vardan harus menjadi constsebaliknya.
cregox
2
Ini tidak menjawab pertanyaan "Bagaimana jika saya ingin login dengan nomor baris di mana debug () dipanggil?"
technomage
24

Saya menyukai jawaban @ fredrik , jadi saya menggulungnya dengan jawaban lain yang membagi stacktrace Webkit , dan menggabungkannya dengan pembungkus aman console.log @ PaulIrish . "Membakukan" filename:lineke "objek khusus" sehingga menonjol dan sebagian besar terlihat sama di FF dan Chrome.

Pengujian di biola: 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

Ini juga berfungsi dalam simpul, dan Anda bisa mengujinya dengan:

// 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 ---');
drzaus
sumber
jawaban yang sedikit lebih maju ke akun untuk tambahan consolemetode seperti warn, error, dll - stackoverflow.com/a/14842659/1037948
drzaus
1
var line = stack.split('\n')[2];-'undefined' is not an object
sigod
@sigod - mungkin tergantung pada browser, atau yang saya tulis ini 2 tahun yang lalu dan browser telah berubah. apa skenario kamu?
drzaus
1
salah satu rekan saya menyalin-tempel kode Anda ke proyek kami. Itu merusak situs di IE11 dan Safari 5. Tidak yakin tentang versi lain dari browser ini. Mungkin Anda akan menambahkan cek untuk copy paste yang akan datang?
sigod
1
@ astaga, bagaimana dengan sekarang? ditambahkan if(!stack) return '?'ke metode yang gagal, bukan dari tempat namanya (jadi jika ada yang menggunakan metode itu sendiri mereka juga "dilindungi")
drzaus
18

Anda dapat mempertahankan nomor baris dan mengeluarkan tingkat log dengan beberapa penggunaan cerdas 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)

Mengambil langkah lebih jauh, Anda dapat memanfaatkan perbedaan consoleerror / peringatan / info dan masih memiliki tingkat kustom. Cobalah!

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)
namuol
sumber
1
Aku sudah berusaha untuk sementara waktu sekarang untuk secara otomatis awalan output dari console.debug(...)dengan function namedan arguments- pemikiran tentang bagaimana melakukan hal itu?
Daniel Sokolowski
3
Saya telah melihat banyak pembungkus konsol / shims / dll. dan ini adalah yang pertama saya temui yang menggabungkan mempertahankan nomor baris dengan menyesuaikan output. Ini adalah penggunaan pintar dari fakta bahwa .bind juga melakukan beberapa currying untuk Anda, Anda dapat mengikat satu atau lebih argumen di samping konteksnya . Anda dapat mengambilnya selangkah lebih maju dan meneruskannya fungsi noop dengan metode .toString yang dapat menjalankan kode ketika metode log dipanggil! Lihat jsfiddle ini
Sam Hasler
2
Mungkin tidak di semua peramban (belum memeriksanya), tetapi mengganti %sdengan %odi Chrome akan mencetak parameter seperti yang Anda harapkan (objek dapat diperbesar, angka dan string diwarnai, dll).
anson
suka solusi ini. Saya membuat beberapa perubahan yang berfungsi lebih baik untuk aplikasi saya, tetapi sebagian besar masih utuh dan berjalan dengan indah. Terima kasih
Ward
9

Dari: Bagaimana cara mendapatkan nomor saluran fungsi pemanggil JavaScript? Bagaimana cara mendapatkan URL sumber pemanggil JavaScript? yang Errorobjek memiliki properti nomor baris (di FF). Jadi sesuatu seperti ini seharusnya bekerja:

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

Di browser Webkit Anda memiliki err.stackstring yang mewakili tumpukan panggilan saat ini. Ini akan menampilkan nomor baris saat ini dan informasi lainnya.

MEMPERBARUI

Untuk mendapatkan linenumber yang benar, Anda harus mengaktifkan kesalahan pada baris itu. Sesuatu seperti:

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);
fredrik
sumber
1
new Error();memberi saya konteks di mana dieksekusi, jika saya memasukkannya debug.js, maka saya akan mendapatkannya info: Here is a msg. file: http://localhost/js/debug.js line:7.
Rufus
1
Apa gunanya Log = Error? Anda masih memodifikasi kelas Kesalahan, bukan?
drzaus
Kombinasikan jawaban Anda dengan pasangan lain - lihat di bawah stackoverflow.com/a/14841411/1037948
drzaus
8

Cara untuk menyimpan nomor saluran ada di sini: https://gist.github.com/bgrins/5108712 . Ini kurang lebih bermuara pada ini:

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

Anda dapat membungkus ini dengan isDebugdan mengatur window.logke function() { }jika Anda tidak men-debug.

Brian Grinstead
sumber
7

Anda dapat meneruskan nomor baris ke metode debug Anda, seperti ini:

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

Di sini, (new Error).lineNumberakan memberi Anda nomor baris saat ini dalam javascriptkode Anda .

Subodh
sumber
2
Sedikit bertele-tele, bukan?
Rufus
2
Saya pikir sudah cukup untuk menjawab pertanyaan Anda. :)
Subodh
1
properti lineNumber adalah non-standar, dan hanya berfungsi pada firefox sekarang, lihat di sini
Matthias
6

Chrome Devtools memungkinkan Anda mencapai ini dengan Blackboxing . Anda dapat membuat pembungkus konsol.log yang dapat memiliki efek samping, memanggil fungsi lain, dll, dan masih mempertahankan nomor baris yang disebut fungsi pembungkus.

Cukup masukkan pembungkus console.log kecil ke dalam file terpisah, mis

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

Beri nama itu seperti log-blackbox.js

Lalu pergi ke pengaturan Chrome Devtools dan temukan bagian "Blackboxing", tambahkan pola untuk nama file yang ingin Anda blackbox, dalam hal ini log-blackbox.js

kzahel
sumber
Catatan: Pastikan Anda tidak memiliki kode apapun Anda akan ingin muncul dalam jejak stack dalam file yang sama, karena juga akan dihapus dari jejak.
jamesthollowell
6

Saya menemukan solusi sederhana untuk menggabungkan jawaban yang diterima (mengikat ke console.log / error / etc) dengan beberapa logika luar untuk menyaring apa yang sebenarnya dicatat.

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

Pemakaian:

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
  • Catatan yang console.assertmenggunakan logging bersyarat.
  • Pastikan alat dev browser Anda menunjukkan semua level pesan!
Jacob Phillips
sumber
Karena tidak memberikan nomor baris atau contoh kerja yang menunjukkan level log.
not2qubit
Nomor baris akan sama dengan jika menggunakan konsol secara langsung. Saya memperbarui jawabannya dengan contoh penggunaan. Itu tidak memiliki banyak suara karena saya menjawabnya dua tahun kemudian :)
Jacob Phillips
4

Jika Anda hanya ingin mengontrol apakah debug digunakan dan memiliki nomor baris yang benar, Anda dapat melakukan ini sebagai gantinya:

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

Ketika Anda membutuhkan akses untuk debug, Anda dapat melakukan ini:

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

Jika isDebug == true, Nomor baris dan nama file yang ditampilkan di konsol akan benar, karena debug.logdll sebenarnya adalah alias dari console.logdll.

Jika isDebug == false, tidak ada pesan debug yang ditampilkan, karena debug.logdll tidak melakukan apa-apa (fungsi kosong).

Seperti yang sudah Anda ketahui, fungsi wrapper akan mengacaukan nomor baris dan nama file, jadi sebaiknya Anda tidak menggunakan fungsi wrapper.

Alvin Wong
sumber
Hebat, saya perlu berhati-hati tentang urutan isDebug = truedan debug.js, tetapi jawaban ini berhasil!
Rufus
3
window.debug = window.consoleakan sedikit lebih bersih.
fredrik
@Fredrik maka saya harus "menerapkan" semua fungsi anggota jika isDebug == false. : {
Alvin Wong
@ AlvinWong saya hanya menat untuk if isDebug===true. Atau acara untuk ini: jsfiddle.net/fredrik/x6Jw5
fredrik
4

Solusi penelusuran tumpukan menampilkan nomor baris tetapi tidak mengizinkan klik untuk pergi ke sumber, yang merupakan masalah besar. Satu-satunya solusi untuk menjaga perilaku ini adalah dengan mengikat ke fungsi aslinya.

Binding mencegah untuk memasukkan logika perantara, karena logika ini akan mengacaukan dengan nomor baris. Namun, dengan mendefinisikan kembali fungsi terikat dan bermain dengan substitusi string konsol , beberapa perilaku tambahan masih dimungkinkan.

Intisari ini menunjukkan kerangka kerja logging minimalis yang menawarkan modul, level log, pemformatan, dan nomor baris yang dapat diklik dalam 34 baris. Gunakan itu sebagai dasar atau inspirasi untuk kebutuhan Anda sendiri.

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

EDIT: intinya termasuk di bawah ini

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

solendil
sumber
Jawaban ini hanya memiliki 3 upvotes tetapi sangat lebih kaya dan bersih daripada yang lain di halaman
Tom
Namun, sepertinya semua bagian yang berguna ada di inti eksternal.
Ryan The Leach
3

Ide dengan bind Function.prototype.bindsangat brilian. Anda juga dapat menggunakan npm library -logger . Ini menunjukkan file sumber asal:

Buat siapa saja yang pernah logger di proyek Anda:

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

Mencetak log:

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

masukkan deskripsi gambar di sini

deathangel908
sumber
2

Berikut adalah cara untuk menjaga consolepernyataan logging yang ada saat menambahkan nama file dan nomor baris atau info jejak tumpukan lainnya ke 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;
  }, {}));
}());

Kemudian gunakan seperti ini:

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

Ini berfungsi di Firefox, Opera, Safari, Chrome, dan IE 10 (belum diuji pada IE11 atau Edge).

Brett Zamir
sumber
Kerja bagus, tapi masih belum 100% yang saya butuhkan. Saya ingin memiliki informasi nama file dan nomor baris di sisi kanan tampilan konsol, di mana dapat diklik untuk membuka sumber. Solusi ini menunjukkan informasi sebagai bagian dari pesan (seperti ini my test log message (myscript.js:42) VM167 mypage.html:15:), yang tidak terlalu baik untuk dibaca dan tidak ditautkan. Pekerjaan yang masih bagus jadi sebuah upvote.
Frederic Leitenberger
Ya, sementara itu akan ideal, tidak ada cara, AFAIK, untuk menipu tautan nama file yang muncul di konsol ...
Brett Zamir
@ BrettZamir memposting pertanyaan tentang kode ini di sini: 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.'));

Ini akan memberiku info: "Here is a msg." main.js(line:2).

Tapi ekstra evaldibutuhkan, sayang.

Rufus
sumber
2
eval is Evil! Jadi setiap kejahatan.
fredrik
1

Kode dari 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);
Timo Kähkönen
sumber
Tampaknya ini tidak menunjukkan nomor baris asli tempat logdipanggil dari
ragamufin
Saya hampir yakin bahwa itu berhasil ketika saya menguji, tetapi saya mengganti kode dengan versi "penuh" dari halaman yang sama. Paling tidak bekerja di Chrome 45.
Timo Kähkönen
Dimengerti Dengan perubahan yang Anda miliki sekarang pada dasarnya sama dengan beberapa jawaban dan pekerjaan lainnya. Saya hanya ingin tahu tentang kode Anda sebelumnya karena Anda memiliki aplikasi pada akhirnya yang meningkatkan kemungkinan menarik bagi saya untuk menggunakan ini lebih banyak tetapi karena tidak menunjukkan nomor baris saya kembali ke titik awal. Terimakasih Meskipun!
ragamufin
1

Saya telah melihat masalah ini sendiri belakangan ini. Membutuhkan sesuatu yang sangat lurus ke depan untuk mengendalikan penebangan, tetapi juga untuk mempertahankan nomor baris. Solusi saya tidak terlihat elegan dalam kode, tetapi memberikan apa yang dibutuhkan untuk saya. Jika seseorang cukup hati-hati dengan penutupan dan penahan.

Saya telah menambahkan pembungkus kecil ke awal aplikasi:

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

Sehingga nanti saya bisa langsung melakukan:

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

Saya sudah mengujinya dari firefox dan crome, dan kedua browser tampaknya menunjukkan log konsol sebagaimana dimaksud. Jika Anda mengisi seperti itu, Anda selalu dapat memperluas metode 'd' dan meneruskan parameter lain ke dalamnya, sehingga dapat melakukan beberapa logging tambahan.

Belum menemukan kelemahan serius untuk pendekatan saya, kecuali baris kode yang jelek untuk logging.

Vladimir M
sumber
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');

inilah solusi saya tentang pertanyaan ini. ketika Anda memanggil metode: log, itu akan mencetak nomor baris tempat Anda mencetak log Anda

Feng Li
sumber
1

Variasi kecil adalah memiliki debug () mengembalikan fungsi, yang kemudian dieksekusi di mana Anda membutuhkannya - debug (pesan) (); dan dengan demikian menunjukkan nomor baris yang benar dan skrip panggilan di jendela konsol, sambil memungkinkan variasi seperti mengarahkan ulang sebagai peringatan, atau menyimpan ke 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() {});
  }

}

Karena mengembalikan fungsi, fungsi itu perlu dijalankan pada baris debug dengan () ;. Kedua, pesan dikirim ke fungsi debug, alih-alih ke fungsi yang dikembalikan memungkinkan pra-pemrosesan atau pengecekan yang mungkin Anda butuhkan, seperti memeriksa status tingkat log, membuat pesan lebih mudah dibaca, melompati berbagai jenis, atau hanya melaporkan item memenuhi kriteria tingkat log;

debug(message, "serious", 1)();
debug(message, "minor", 4)();
Saul Dobney
sumber
1

Anda dapat menyederhanakan logika di sini. Ini mengasumsikan bendera debug global Anda TIDAK dinamis dan ditetapkan pada muat aplikasi atau diteruskan karena beberapa konfigurasi. Ini dimaksudkan untuk digunakan untuk penandaan lingkungan (mis. Hanya mencetak ketika dalam mode dev dan bukan produksi)

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

Modul:

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 sudut:

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

Yang perlu Anda lakukan sekarang adalah mengganti semua referensi konsol dengan Logger

disfungsi
sumber
1

Implementasi ini didasarkan pada jawaban yang dipilih dan membantu mengurangi jumlah kebisingan di konsol kesalahan: 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);
Brian
sumber
0

Saya menemukan beberapa jawaban untuk masalah ini agak terlalu rumit untuk kebutuhan saya. Ini adalah solusi sederhana, disajikan dalam Coffeescript. Ini diadaptasi dari versi Brian Grinstead di sini

Ini mengasumsikan objek konsol global.

# 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)
)()
sandover
sumber
0

Cara saya menyelesaikannya adalah dengan membuat objek, kemudian membuat properti baru pada objek menggunakan Object.defineProperty () dan mengembalikan properti konsol, yang kemudian digunakan sebagai fungsi normal, tetapi sekarang dengan kemampuan yang diperluas.

var c = {};
var debugMode = true;

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

Kemudian, untuk mendefinisikan properti yang baru saja Anda lakukan ...

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

Dan sekarang Anda dapat menggunakan fungsi Anda seperti

c.error("Error!");
Abel Rodríguez
sumber
0

Berdasarkan jawaban lain (terutama @arctelix satu) saya membuat ini untuk Node ES6, tetapi tes cepat menunjukkan hasil yang baik di browser juga. Saya hanya melewati fungsi lain sebagai referensi.

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

Inilah fungsi logger saya (berdasarkan beberapa jawaban). Semoga seseorang dapat memanfaatkannya:

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

Contoh:

log( 'warn', 'log message', 'my_function' );
log( 'info', 'log message' );
merusak
sumber