是否有多传输记录器在向控制台报告时保留原始文件中的调用位置?

时间:2015-04-26 14:10:11

标签: javascript logging

序言

已知库Winston与许多其他用于多传输日志记录的不同库具有相同的问题。当其中一个传输是console时,调试器控制台(浏览器或Node.js的任何环境)中报告的消息错过了非常强大的信息:启动初始调用的位置(开发人员的文件),而不是显示库内的呼叫位置。在这种情况下,来自不同文件/地点的多个调用都会被报告,就像从同一个地方记录一样。

尝试了解决方案

我研究了两种方法。一个是浏览器/节点上的技巧,当他们推断出console.log的呼叫位置时。我发现它的唯一方法是通过source maps。这是一种技术,允许将缩小的js源映射到原始源并在查看完整源时进行调试。但是,这假设从实际(缩小)源到原始的一个过渡。如果在潜在库console.log中替换mylogger的来源,则应该是动态的,并反映调用mylogger.log的多个位置。由于浏览器只加载一次地图文件,我还没有找到一种动态执行此操作的方法。

另一个是替换console.log的调用,并在自定义函数内调用所有其他传输(这可以是相同的Winston)。但是,如果我们进行如下的简单替换

var originalLog = console.log;
console.__proto__.log = function(message){
    message = [new Date().toISOString(), message].join(' ');
    originalLog.call(console, message);
//here send via other transports
    body.innerHTML = body.innerHTML + message + '<br/>';
};

originalLog的呼叫位置始终相同,并在控制台输出中相应地报告。所以我想到拦截对console.log的调用,但保留了原始的原生函数。但是我没有得到呼叫的参数。

function interceptGettingLog(){
    var originalLog = console.log;
    Object.defineProperties(console.__proto__, {
        log: {
            get: function(){
//arguments is always empty here, which is not a big surprise
                originalLog.call(console, 'log accessed ' + JSON.stringify(arguments));
                return originalLog;
            }
        }
    });
}

简短的问题

在调用console.log时,是否有人知道不同的日志记录方法或浏览器/ Node.js上的欺骗方法?我们的目标是拥有一个多级多传输记录器,它可以在配置中切换冗长和传输(对于开发和生产而言会有所不同),具有console.log的全部功能,同时还具有整洁的语法,即在开发人员需要记录某些内容的地方进行单个函数调用。感谢您阅读:)

2 个答案:

答案 0 :(得分:1)

到目前为止,这是我可以弥补的最佳解决方案。我假设它不是 clean ,因为它强制调用行上的特定语法。 但它确实有效。

function logInfo(){
//do multitransport multilevel logging on your decision
// for example, Winston
    var args = Array.prototype.slice.call(arguments);
    winston.log.apply(winston, args);
    if(levels.contains('console')){
//return a console.log function to call it in the 'right' place
        return console.log.bind.apply(console.log, [console].concat(args));
    }else{
//return a no-operation function to skip output to console
         return function nop(){};
    }
}

用法

...
logInfo('My message:', {foo:true, count: 100})();
...

诀窍是返回console.log与传递给主日志记录函数的参数绑定,并在调用主日志记录函数的同一位置调用它。这样我们就可以避免重复代码:只记录指定一次的参数。主日志记录功能后的括号()表示是否会输出到控制台。如果配置指示不输出到控制台,我们返回一个空函数。

<强> PS 我会考虑 clean 替换console.log的那个。因此,您无需修改​​即可应用补丁 现有代码console.log次调用。但是如果不重载()就不可能实现这一点,这在ES5中是不可行的。

使用参数数组调用的bind的信用转到@FelixKling https://stackoverflow.com/a/21507470/4573999

答案 1 :(得分:1)

在Chrome开发工具中,您可以“封装”包装器脚本,chrome会报告调用黑盒子脚本中的函数的位置。

右键单击开发工具源中的源脚本,然后选择“Blackbox脚本”。

Chrome dev tools notes on blackboxing

Paul Irish wrote a gist about it