javascript 自定义控制台日志功能,console.log 包装器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20524700/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 18:42:03  来源:igfitidea点击:

Custom console log function, a console.log wrapper

javascriptdebug-backtrace

提问by John

function log( msgOrObj ){
    if(dev_mode){
        console.log({
            'message': msgOrObj,
            'caller': arguments.callee.caller.toString()
        });
    }
}

So, I have attempted to write a simple custom console log function (as above). However I am struggling to find which file and line the caller came from. The most I can see is the function that called it.

因此,我尝试编写一个简单的自定义控制台日志功能(如上)。但是我很难找到调用者来自哪个文件和行。我能看到的最多的是调用它的函数。

Has anyone done anything similar? Or is this even possible?

有没有人做过类似的事情?或者这甚至可能吗?

example used in somescript.js from line 70:

来自第 70 行的 somescript.js 中使用的示例:

log('some very important message!')

采纳答案by John

So, this is what I went for in the end (where shout is a bespoke function only running in dev mode):

所以,这就是我最终想要的(其中shout 是一个仅在开发模式下运行的定制功能):

function log( msgOrObj ){
    if(dev_mode){
        if( typeof(window.console) != 'undefined' ){
            try {  invalidfunctionthrowanerrorplease(); }
            catch(err) {  var logStack = err.stack;  }
            var fullTrace = logStack.split('\n');
            for( var i = 0 ; i < fullTrace.length ; ++i ){
                fullTrace[i] = fullTrace[i].replace(/\s+/g, ' ');
            }
            var caller = fullTrace[1],
                callerParts = caller.split('@'),
                line = '';

            //CHROME & SAFARI
            if( callerParts.length == 1 ){
                callerParts = fullTrace[2].split('('), caller = false;
                //we have an object caller
                if( callerParts.length > 1 ){
                    caller = callerParts[0].replace('at Object.','');
                    line = callerParts[1].split(':');
                    line = line[2];
                }
                //called from outside of an object
                else {
                    callerParts[0] = callerParts[0].replace('at ','');
                    callerParts = callerParts[0].split(':');
                    caller = callerParts[0]+callerParts[1];
                    line = callerParts[2];
                }
            }
            //FIREFOX
            else {
                var callerParts2 = callerParts[1].split(':');
                line = callerParts2.pop();
                callerParts[1] = callerParts2.join(':');
                caller = (callerParts[0] == '') ? callerParts[1] : callerParts[0];
            }
            console.log( ' ' );
            console.warn( 'Console log: '+ caller + ' ( line '+ line +' )' );
            console.log( msgOrObj );
            console.log({'Full trace:': fullTrace });
            console.log( ' ' );
        } else {
            shout('This browser does not support console.log!')
        }
    }
}

log() when declared before the rest of the application can be called anywhere from within the app and give the developer all the information required plus will not run out of dev mode.

log() 在应用程序的其余部分之前声明时可以从应用程序内的任何地方调用,并为开发人员提供所需的所有信息,并且不会用完开发模式。

(http://webconfiguration.blogspot.co.uk/2013/12/javascript-console-log-wrapper-with.html)

http://webconfiguration.blogspot.co.uk/2013/12/javascript-console-log-wrapper-with.html

回答by Joe

Yes but it's very hacky and not cross browser-safe. You can use this as a starting point. It borrows from this answer.

是的,但它非常hacky 并且不跨浏览器安全。您可以以此为起点。它借鉴了这个答案

window.trace = function stackTrace() {
    var err = new Error();
    return err.stack;
}

window.my_log = function (x) {
    var line = trace();
    var lines = line.split("\n");
    console.log(x + " " + lines[2].substring(lines[2].indexOf("("), lines[2].lastIndexOf(")") + 1))
}


window.my_log("What light through yonder window breaks?")

Produces:

产生:

What light through yonder window breaks? (<anonymous>:2:42) 

回答by milks

The only way I've seen to reliably extract this kind of info is to throw an error and then extract the caller info from the stack trace, something along the lines of:

我见过的可靠提取此类信息的唯一方法是抛出错误,然后从堆栈跟踪中提取调用者信息,大致如下:

function log( msgOrObj ){
    if(dev_mode){

        try {
            in_val_id(); // force an error by calling an non-existent method
        catch(err) {
            // some regex/string manipulation here to extract function name
            // line num, etc. from err.stack
            var caller = ...
            var lineNo = ...
        }

        console.log({
            'message': msgOrObj,
            'caller': caller,
            'lineNo': lineNo
        });
    }
}

The stack in Chrome is in this form:

Chrome 中的堆栈是这种形式:

ReferenceError: in_val_id is not defined
at log (<anonymous>:4:13)
at <anonymous>:2:14
at <anonymous>:2:28
at Object.InjectedScript._evaluateOn (<anonymous>:581:39)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:540:52)
at Object.InjectedScript.evaluate (<anonymous>:459:21) 

you can extract the function name with:

您可以使用以下命令提取函数名称:

caller = err.stack.split('\n')[3].split('at ')[1].split(' (')[0];

using a regex here might be more performant. You'll probably need different approaches to extract this info with different browsers.

在这里使用正则表达式可能会更高效。您可能需要不同的方法来使用不同的浏览器提取此信息。

A word of warning though; throwing and handling errors is expensive so outputting a lot of log messages in this way is likely to impact on general performance, though this may be acceptable if it is specifically for a debug mode

警告的话;抛出和处理错误的成本很高,因此以这种方式输出大量日志消息可能会影响总体性能,但如果专门用于调试模式,这可能是可以接受的

回答by Andrew S

I use this in Node and its particularly effective. Console.log is just a function it can be reassigned as well as stored for safe keeping and returned back after we are done. I've no reason to believe this would not work in a browser too.

我在 Node 中使用它,它特别有效。Console.log 只是一个函数,它可以重新分配,也可以存储以安全保存并在我们完成后返回。我没有理由相信这在浏览器中也不起作用。

//Store console.log function in an object so
//we can still use it.
theConsole = {};
theConsole.log = console.log;

//This function is called when console.log occurs
//arguments[0] is what would normally be printed.
console.log = function(){
    theConsole.log(">" + arguments[0]);
}

//Call our console.log wrapper
console.log("Testing testing 123");
console.log("Check one two");

//Put back the way it was
console.log = theConsole.log;
console.log("Now normal");

回答by NodeNodeNode

There are a couple options to quickly go about this.

有几个选项可以快速解决这个问题。

1 - Use console.error Not very convenient, actual errors will go unnoticed and seeing a lot of red in your console output may have a negative impact on your morale. In short - don't use, unless it's for a very small script or some test

1 - 使用 console.error 不是很方便,实际的错误不会被注意到,在控制台输出中看到很多红色可能会对你的士气产生负面影响。简而言之 - 不要使用,除非它是一个非常小的脚本或一些测试

2 - Add your log method to the prototype of Object to get the current scope/ module name/ etc. Much more flexible and elegant.

2 - 将您的日志方法添加到 Object 的原型中以获取当前范围/模块名称/等。更加灵活和优雅。

Object.prototype.log = function(message){
    console.log({
        'message': message,
        'caller': this, 
        'stack':arguments.callee.caller.toString()
    });
};

Use (anywhere) as:

使用(任何地方)作为:

this.log("foo");

You could add the techniques from thisthread to get exact function name inside your object, as so:

您可以添加线程中的技术 以获取对象内的确切函数名称,如下所示:

    var callerFunc = arguments.callee.caller.toString();
    callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 9, callerFunc.indexOf("(")) || "anoynmous");

Yet make sure your scope is named... forcing you to go from this:

但是请确保您的范围已命名...迫使您从这里开始:

Module.method = function(){}

To this:

对此:

Module.method = function method(){}

As for line numbers, calling (new Error()) will give you access to the line number where it was called - and not even on all browsers.

至于行号,调用 (new Error()) 会让你访问调用它的行号——甚至不是在所有浏览器上。

Creating an elegant debugging function is a piece of work

创建一个优雅的调试功能是一项工作

As much as I hate to admit it, the other answer implying reg-exps over a try result seems to be the faster cure for your problem.

尽管我不愿承认,但暗示 reg-exps 超过尝试结果的另一个答案似乎是解决您问题的更快方法。

回答by Tsanyo Tsanev

Instead of using arguments you can do

而不是使用参数,你可以做

function log( msg ) {
    if (dev_mode) {
        var e = new Error(msg);
        console.log(e.stack);
    }
}

This will show you the order in which all the functions were called (including line numbers and files). You can just ignore the first 2 lines of the stack (one will contain the error message and one will contain the log function since you are creating the error object within the function).

这将显示调用所有函数的顺序(包括行号和文件)。您可以忽略堆栈的前两行(一行将包含错误消息,另一行包含日志函数,因为您是在函数内创建错误对象)。

If you want a more robust logging - use A proper wrapper for console.log with correct line number?as @DoXicK suggested

如果您想要更强大的日志记录 - 使用正确的行号为 console.log使用适当的包装器?正如@DoXicK 建议的那样