Пользовательская консольная функция журнала, оболочка 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 по результату попытки, кажется, является более быстрым решением для вашей проблемы.