Существует ли многотранспортный регистратор, который сохраняет место вызова в исходном файле при отправке отчетов на консоль?

Преамбула

Известная библиотека Winston имеет ту же проблему, что и многие другие библиотеки, которые служат для ведения многотранспортного журнала. Когда один из транспортов console сообщенное сообщение в консоли отладчика (браузер или любая среда для Node.js) пропускает очень мощную информацию: место, где начался начальный вызов (файл разработчика), а вместо этого место вызова внутри библиотеки. В этом случае все сообщения из разных файлов/мест сообщаются, как если бы они регистрировались из одного места.

Решения пробовали

У меня есть два подхода. Один из них был трюк в браузере / Node, когда они вызывают место вызова console.log. Единственный способ, которым я нашел, это сделать через исходные карты. Это технология, которая позволяет отображать мини-источники 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;
            }
        }
    });
}

Вопрос короче

Кто-нибудь знает другой подход к протоколированию или способ обмана в браузере / Node.js при вызове console.log? Цель состоит в том, чтобы иметь многоуровневый многотранспортный логгер, который позволит переключать многословие и транспорты в конфигурации (которые будут отличаться для разработки и производства), имеют полную мощность console.log и в то же время опрятный синтаксис, т.е. один вызов функции в месте, где разработчику нужно что-то записывать. Спасибо за чтение:)

Ответ 1

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

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 Я считаю, что чист тот, который заменяет console.log. Таким образом, вы можете применять патч без изменения существующий код с вызовами console.log. Но достичь этого невозможно, не перегружая (), что не возможно в ES5.

Кредит для bind, вызываемый с массивом аргументов, относится к @FelixKling fooobar.com/questions/130672/...

Ответ 2

В инструментах Chrome dev вы можете "черным ящиком" обертки script, а хром сообщит о точке, в которой вызывается функция в черном ящике script.

Вы прямо щелкните источник script в источниках инструментов dev и выберите "Blackbox script".

Заметки разработчика Chrome для черновика

Пол Ирланд написал об этом