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

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

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

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

log('some very important message!')
4

7 回答 7

5

是的,但它非常 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?")

产生:

What light through yonder window breaks? (<anonymous>:2:42) 
于 2013-12-11T16:45:23.520 回答
4

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

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

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) 

您可以使用以下方法提取函数名称:

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

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

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

于 2013-12-11T16:54:30.907 回答
1

所以,这就是我最终所追求的(其中喊是一个只在开发模式下运行的定制功能):

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() 在应用程序的其余部分之前声明时可以从应用程序内的任何位置调用,并为开发人员提供所需的所有信息,并且不会退出开发模式。

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

于 2013-12-14T21:05:08.473 回答
0

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

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

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

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

于 2013-12-11T16:44:54.103 回答
0

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

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

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

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

使用(任何地方)作为:

this.log("foo");

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

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

但是请确保您的范围被命名......迫使您从这个出发:

Module.method = function(){}

对此:

Module.method = function method(){}

至于行号,调用 (new Error()) 将使您能够访问调用它的行号 - 甚至在所有浏览器上都没有。

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

尽管我不愿承认,但暗示正则表达式而不是尝试结果的另一个答案似乎是解决您问题的更快方法。

于 2013-12-11T17:03:13.670 回答
0

我在 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");
于 2019-11-18T15:55:11.043 回答
-1

看来你们都太挣扎了。我有一个简单的单线解决方案:-

//Just do this, that I have done below: HAVE FUN

var log=console.log;

log(`So this way is known as Aniket's way.`);
log(`Don't be too serious this is just the fun way of doing same thing`);

log(`Thank You`)

于 2020-10-27T08:43:35.830 回答