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

时间:2012-12-11 07:36:56

标签: 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.');

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

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

如果我想要调用debug()被调用的行号,如info: Here is a msg. main.js (line 2)

,该怎么办?

26 个答案:

答案 0 :(得分:103)

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

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

像这样创建开关:

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

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

然后简单地调用如下:

debug('This is happening.')

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

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

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

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

现在您可以将它添加到您的课程中:

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

答案 1 :(得分:23)

我喜欢@fredrik's answer,因此我使用another answer which splits the Webkit stacktrace汇总了它,并将其与@PaulIrish's safe console.log wrapper合并。将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

这也可以在节点中使用,您可以使用以下方法进行测试:

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

答案 2 :(得分:13)

您可以通过巧妙地使用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)

更进一步,您可以使用console的错误/警告/信息区别,并且仍然具有自定义级别。 Try it!

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)

答案 3 :(得分:9)

来自:How to get JavaScript caller function line number? How to get JavaScript caller source URL? Error对象具有行号属性(在FF中)。所以这样的事情应该有效:

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

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

<强>更新

要获得正确的亚麻布,您需要在该行上调用错误。类似的东西:

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

答案 4 :(得分: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);
    };
}

如果您没有调试,可以使用isDebug将其打包并将window.log设置为function() { }

答案 5 :(得分:7)

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

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

在此处,(new Error).lineNumber会在javascript代码中为您提供当前行号。

答案 6 :(得分: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)
    }
})()

将其命名为log-blackbox.js

然后转到Chrome Devtools设置,找到&#34; Blackboxing&#34;部分,添加您想要黑名单的文件名模式,在本例中为log-blackbox.js

答案 7 :(得分:5)

我找到了一个简单的解决方案,将接受的答案(绑定到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;

用法:

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

答案 8 :(得分:4)

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

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

当您需要访问调试时,可以执行以下操作:

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

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

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

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

答案 9 :(得分:3)

堆栈跟踪解决方案显示行号,但不允许单击转到源,这是一个主要问题。保持此行为的唯一解决方案是bind到原始函数。

Binding阻止包含中间逻辑,因为这个逻辑会弄乱行号。但是,通过重新定义绑定函数并使用控制台string substitution,还可以执行一些其他行为。

This gist显示了一个简约的日志记录框架,它提供34行中的模块,日志级别,格式和正确的可点击行号。将其作为满足您自身需求的基础或灵感。

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

答案 10 :(得分:2)

2021

听着 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

美妙之处在于避免了另一个像 log('xyz')() 这样的函数调用 或者创建一个包装对象甚至类。它也是 ES5 安全的。

如果不需要前缀,直接删除参数即可。

update 包含当前时间戳以作为每个日志输出的前缀。

答案 11 :(得分:2)

使用bind Function.prototype.bind的想法很棒。您也可以使用npm库lines-logger。它显示原始源文件:

在您的项目中一次创建记录器的任何人:

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

打印日志:

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

enter image description here

答案 12 :(得分:2)

这是一种在输出中添加文件名和行号或其他堆栈跟踪信息时保留现有console日志记录语句的方法:

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

然后像这样使用它:

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

适用于Firefox,Opera,Safari,Chrome和IE 10(尚未在IE11或Edge上测试过)。

答案 13 :(得分:1)

&#13;
&#13;
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');
&#13;
&#13;
&#13;

这是我对这个问题的解决方案。当您调用方法:log时,它将打印您打印日志的行号

答案 14 :(得分:1)

我最近一直在看这个问题。需要非常直接的东西来控制日志记录,还要保留行号。我的解决方案在代码中看起来并不优雅,但提供了我需要的东西。如果一个人足够小心,有封闭和保留。

我在应用程序的开头添加了一个小包装器:

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

以后我可以简单地做:

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

我已经对firefox和crome进行了测试,两个浏览器似乎都按预期显示了控制台日志。如果你这样填写,你可以随时扩展&#39; d&#39;方法并将其他参数传递给它,以便它可以进行一些额外的记录。

Haven没有发现我的方法有任何严重的缺点,除了记录代码中的丑陋行。

答案 15 :(得分:1)

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

答案 16 :(得分:1)

稍微变化就是让debug()返回一个函数,然后在需要的地方执行它 - debug(message)();并在控制台窗口中正确显示正确的行号和调用脚本,同时允许重定向为警报或保存到文件等变体。

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

}

由于它返回一个函数,该函数需要在调试行中用();执行。其次,将消息发送到调试函数,而不是发送到返回的函数,允许预处理或检查您可能需要的函数,例如检查日志级别状态,使消息更具可读性,跳过不同类型或仅报告项目符合日志级别标准;

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

答案 17 :(得分:1)

此实现基于所选答案,有助于减少错误控制台中的杂音: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);

答案 18 :(得分: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.'));

这会给我info: "Here is a msg." main.js(line:2)

但需要额外的eval,可惜。

答案 19 :(得分:0)

我解决它的方法是创建一个对象,然后使用 Object.defineProperty()在对象上创建一个新属性,并返回console属性,然后将其用作普通函数,但现在已经延长了空缺。

var c = {};
var debugMode = true;

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

然后,要定义一个属性,你就是......

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

现在您可以像

一样使用您的功能
c.error("Error!");

答案 20 :(得分:0)

我发现这个问题的一些答案对我的需求来说有点过于复杂。这是一个简单的解决方案,在Coffeescript中呈现。它改编自Brian Grinstead的版本here

它假设全局控制台对象。

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

答案 21 :(得分:0)

您可以在这里简化逻辑。这假设您的全局调试标志不是动态的,并且在应用程序加载时设置或作为某些配置传入。这旨在用于环境标记(例如,仅在处于开发人员模式时才打印,而不在生产环境中打印)

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

模块:

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:

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

您现在要做的就是用Logger替换所有控制台引用

答案 22 :(得分:0)

基于其他答案(主要是@arctelix一个),我为Node ES6创建了这个答案,但是快速测试也显示了在浏览器中的良好结果。我只是通过其他函数作为参考。

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

答案 23 :(得分:0)

这是我的记录器功能(基于某些答案)。希望有人可以利用它:

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

示例:

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

答案 24 :(得分:0)

我知道有一个老问题,但是一段时间以来我一直在为自己的解决方案进行研究。回来看看是否有新信息。既然看起来好像没有人靠近,我想我应该把解决方案扔进绞拧器中(因为这似乎仍然是问题上最活跃的线索):

https://github.com/fatlard1993/log

在开始了解代理之前,我最初在这里对其他一些答案使用了类似的方法。这给了我一个主意,并激发了将其变为现在的想法。

答案 25 :(得分:0)

这里的所有解决方案都围绕着真正的问题展开-调试器应该能够忽略堆栈的一部分以给出有意义的行。 VSCode的js调试器现在可以执行此操作。。在进行此编辑时,该功能可通过夜间构建的js-debug扩展程序使用。请参阅以下段落中的链接。

proposed a feature for VSCode's debugger here忽略启动配置的任何skipFiles文件路径中的堆栈顶部。该属性位于您的vscode工作空间的launch.json配置中。因此,您可以创建一个负责包装console.log的文件/模块,将其添加到skipFiles中,调试器将显示被调用的行而不是console.log本身。

它在js-debug扩展的每晚构建中。看起来可能在Visual Studio代码的下一个次要版本中。我已经验证它可以使用每晚构建。是的,不再有骇人的解决方法了!