Пользовательская консольная функция журнала, оболочка console.log

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

Итак, я попытался написать простую пользовательскую функцию консольного журнала (как указано выше). Однако я изо всех сил пытаюсь найти файл и строку, из которой пришел вызывающий. Самое большее, что я вижу, это функция, которая его называла.

Кто-нибудь сделал что-нибудь подобное? Или это возможно?

пример, используемый в somescript.js из строки 70:

log('some very important message!')

Ответ 1

Итак, это то, что я пошел в конце (где крик - это функция на заказ, работающая только в режиме dev):

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(), когда объявлено до того, как остальная часть приложения может быть вызвана в любом месте приложения и предоставить разработчику всю необходимую информацию плюс не будет работать из режима dev.

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

Ответ 2

Да, но он очень взломан и не перекрещивается с браузером. Вы можете использовать это как отправную точку. Он заимствует из этого ответа.

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) 

Ответ 3

Единственный способ, с помощью которого я мог надежно извлечь такую ​​информацию, - это выбросить ошибку, а затем извлечь информацию о вызывающем абоненте из трассировки стека, что-то вроде строк:

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

использование регулярного выражения здесь может быть более эффективным. Вероятно, вам понадобятся разные подходы к извлечению этой информации с помощью разных браузеров.

Слово предупреждения, хотя; метаданные и ошибки обработки являются дорогостоящими, поэтому вывод большого количества сообщений журнала таким образом может повлиять на общую производительность, хотя это может быть приемлемым, если оно специально для режима отладки

Ответ 4

Вместо использования аргументов вы можете сделать

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

Это покажет вам порядок, в котором были вызваны все функции (включая номера строк и файлы). Вы можете просто игнорировать первые 2 строки стека (один будет содержать сообщение об ошибке, а один будет содержать функцию журнала, поскольку вы создаете объект ошибки внутри функции).

Если вы хотите более надежную регистрацию - используйте Собственную оболочку для console.log с правильным номером строки?, поскольку @DoXicK предложил

Ответ 5

Есть несколько вариантов, чтобы быстро обойти это.

1 - используйте console.error Не очень удобные, фактические ошибки останутся незамеченными и видя, что много красного на вашем выходе в консоль может негативно повлиять на ваш моральный дух. Короче говоря - не используйте, если только он для очень маленького script или некоторого теста

2 - Добавьте свой метод журнала к прототипу объекта для получения текущего объема/имени модуля/и т.д. Гораздо более гибким и элегантным.

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()) даст вам доступ к номеру строки, где он был вызван, и даже не во всех браузерах.

Создание элегантной функции отладки - это часть работы

Насколько я ненавижу это признавать, другой ответ, подразумевающий рег-exps по результату попытки, кажется, является более быстрым решением для вашей проблемы.