console.log的正确包装器,具有正确的行号?

Ruf*_*fus 119 javascript

我现在正在开发一个应用程序,并放置一个全局isDebug开关.我想换行console.log以方便使用.

//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.');
Run Code Online (Sandbox Code Playgroud)

然后我在Firefox控制台中得到了这个结果.

info: Here is a msg.                       debug.js (line 8)
Run Code Online (Sandbox Code Playgroud)

如果我想用debug()被调用的行号记录,info: Here is a msg. main.js (line 2)怎么办?

arc*_*lix 109

这是一个老问题,提供的所有答案都过于hackey,有主要的跨浏览器问题,并且没有提供任何超级有用的东西.此解决方案适用于每个浏览器,并准确报告所有控制台数据.不需要黑客和一行代码检查代码.

var debug = console.log.bind(window.console)
Run Code Online (Sandbox Code Playgroud)

像这样创建开关:

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

if (isDebug) var debug = console.log.bind(window.console)
else var debug = function(){}
Run Code Online (Sandbox Code Playgroud)

然后简单地调用如下:

debug('This is happening.')
Run Code Online (Sandbox Code Playgroud)

您甚至可以使用如下开关接管console.log:

if (!isDebug) console.log = function(){}
Run Code Online (Sandbox Code Playgroud)

如果你想做一些有用的东西..你可以添加所有控制台方法并将其包装在一个可重用的函数中,该函数不仅提供全局控制,还提供类级别:

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!')
Run Code Online (Sandbox Code Playgroud)

现在您可以将它添加到您的类:

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

  • 如果我错了,请纠正我,但这不允许你添加任何其他功能,但是,对吗?你基本上只是控制台对象的别名?一个粗略的例子 - 对于每个debug.log(),没有办法将console.log()事件两次? (12认同)
  • 这并没有回答“如果我想使用调用 debug() 的行号进行日志记录怎么办?” (7认同)
  • @ABCarroll你可以通过绑定一个包含两个调用`console.log`的自定义`log()`函数来两次`console.log`,但是行号会反映`console.log`实际驻留的行,而不是`debug.log`被调用.但是,您可以执行添加动态前缀/后缀等操作.还有一些方法可以补偿行号问题,但这是我认为的另一个问题.请查看此项目以获取示例:https://github.com/arctelix/iDebugConsole/blob/master/README.md (3认同)
  • 此方法在Firefox 47到49(包括47和49)中不起作用.并且仅在版本50.0a2中修复.好的FF50将在2周内发布,但我花了几个小时才意识到它为什么不起作用.所以我认为这些信息可能对某人有所帮助.[链接](https://bugzilla.mozilla.org/show_bug.cgi?id=1280818) (2认同)
  • https://totallynoob.com/javascript-prefix-console-log-without-affecting-the-line-number/ 此解决方案允许在自定义控制台日志中附加文本作为前缀 (2认同)

drz*_*aus 23

我喜欢@fredrik的答案,所以我将另一个答案拆分为Webkit 堆栈跟踪,并将其与@PaulIrish的安全console.log包装器合并."标准化" filename:line为"特殊对象",因此它在FF和Chrome中看起来大致相同.

小提琴测试: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
Run Code Online (Sandbox Code Playgroud)

这也适用于节点,您可以使用以下方法对其进行测试:

// 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 ---');
Run Code Online (Sandbox Code Playgroud)


nam*_*uol 15

您可以通过以下方式巧妙地使用以下内容来维护行号输出日志级别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)
Run Code Online (Sandbox Code Playgroud)

更进一步,你可以利用console错误/警告/信息区别,仍然有自定义级别.试试吧!

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)
Run Code Online (Sandbox Code Playgroud)

  • 我一直在寻找众多的控制台包装/垫片等.这是我遇到的第一个结合保留行号和自定义输出的行.这是一个聪明的用法[.bind也为你做了一些讨论,你可以绑定一个或多个参数除了上下文](https://leanpub.com/javascript-allonge/read#leanpub-auto-结合的方法).您可以更进一步,并使用.toString方法传递一个noop函数,该方法可以在调用log方法时运行代码!**参见[this jsfiddle](http://jsfiddle.net/SamHasler/esesdrge /) (3认同)
  • 我已经尝试了一段时间自动在“console.debug(...)”的输出前面添加“函数名称”和“参数”前缀 - 关于如何做到这一点有什么想法吗? (2认同)
  • 可能不是在所有浏览器中(没有查看过),但在Chrome中用'%o`替换'%s`将以您期望的方式打印参数(对象是可扩展的,数字和字符串是彩色的,等等). (2认同)

ang*_*iel 12

听着 McFly,这是唯一对我有用的东西:

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
Run Code Online (Sandbox Code Playgroud)

这样做的好处是避免另一个函数调用,例如log('xyz')() 创建包装对象甚至类。ES5 也是安全的。

如果您不需要前缀,只需删除该参数即可。

更新包括当前时间戳作为每个日志输出的前缀。

  • 我花了一段时间才明白为什么你将defineProperty与“get”一起使用,以便日期始终更新,而不是静态的...... (3认同)
  • @SL5net:好的我明白你的意思了。由于这不是问题的一部分,并且已经有答案(如您发布的答案),我想保持这个答案的重点。 (2认同)

fre*_*rik 9

来自:如何获取JavaScript来电者功能行号?如何获取JavaScript调用者源URL?Error对象具有行号属性(在FF中).所以像这样的东西应该工作:

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

在Webkit浏览器中,您有err.stack一个表示当前调用堆栈的字符串.它将显示当前行号和更多信息.

UPDATE

要获得正确的亚麻布,您需要在该行上调用错误.就像是:

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);
Run Code Online (Sandbox Code Playgroud)


Sub*_*odh 8

您可以将行号传递给调试方法,如下所示:

//main.js
debug('Here is a msg.', (new Error).lineNumber);
Run Code Online (Sandbox Code Playgroud)

在这里,(new Error).lineNumber将为您提供javascript代码中的当前行号.

  • 有点啰嗦,不是吗? (2认同)
  • 我认为这足以回答您的问题.:) (2认同)
  • lineNumber 属性是非标准的,目前仅适用于 Firefox,请参阅[此处](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/lineNumber) (2认同)

Bri*_*ead 8

保持行号的方法如下:https://gist.github.com/bgrins/5108712.它或多或少归结为:

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);
    };
}
Run Code Online (Sandbox Code Playgroud)

如果你没有调试,你可以用它包装isDebug并设置window.logfunction() { }.


Jac*_*ips 6

我找到了一个简单的解决方案,将接受的答案(绑定到console.log/error/etc)与一些外部逻辑相结合,以过滤实际记录的内容.

// 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;
Run Code Online (Sandbox Code Playgroud)

用法:

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
Run Code Online (Sandbox Code Playgroud)
  • 请注意,console.assert使用条件记录.
  • 确保浏览器的开发工具显示所有消息级别!


Alv*_*ong 5

如果您只是想控制是否使用调试并具有正确的行号,您可以这样做:

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(){}
    };
}
Run Code Online (Sandbox Code Playgroud)

当您需要访问调试时,可以这样做:

debug.log("log");
debug.warn("warn");
debug.error("error");
Run Code Online (Sandbox Code Playgroud)

如果isDebug == true,控制台中显示的行号和文件名将是正确的,因为etc 实际上是etcdebug.log的别名。console.log

如果isDebug == false,则不会显示任何调试消息,因为debug.logetc 根本不执行任何操作(空函数)。

如您所知,包装函数会弄乱行号和文件名,因此最好防止使用包装函数。

  • `window.debug = window.console` 会更干净一些。 (3认同)

kza*_*hel 5

Chrome Devtools可让您通过Blackboxing实现这一目标.您可以创建可能有副作用的console.log包装器,调用其他函数等,并仍保留调用包装函数的行号.

只需将一个小的console.log包装器放入一个单独的文件中,例如

(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)
    }
})()
Run Code Online (Sandbox Code Playgroud)

将其命名为log-blackbox.js

然后转到Chrome Devtools设置并找到"Blackboxing"部分,为要黑盒子的文件名添加一个模式,在本例中为log-blackbox.js


sol*_*dil 5

Stack trace 解决方案显示行号但不允许单击转到源,这是一个主要问题。保持这种行为的唯一解决方案是绑定到原始函数。

绑定会阻止包含中间逻辑,因为此逻辑会与行号混淆。然而,通过重新定义绑定函数和使用控制台字符串替换,一些额外的行为仍然是可能的。

这个要点显示了一个简约的日志框架,它提供了模块、日志级别、格式和 34 行的正确可点击行号。将其用作满足您自己需求的基础或灵感。

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

编辑:下面包含的要点

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