Пользовательская функция журнала консоли, оболочка 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!')

8 ответов

Решение

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

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

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

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) 

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

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

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

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

Я использую это в 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");

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

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

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

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

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

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

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

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

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

Попробуй это

      window.log = (() => {
  if (dev_mode) {
    return console.log;
  } else return () => {};
})();

Кажется, вы слишком много боретесь. У меня есть простое однострочное решение:-

       //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`)

Другие вопросы по тегам