Расширение console.log без влияния на строку журнала
Я хотел бы расширить функцию "console.log", чтобы добавить дополнительную информацию к ее выводу, но я не хочу влиять на информацию о имени/номере номера script, сгенерированную браузером в окне консоли. Посмотрите, как я создаю свою собственную реализацию, я получаю бесполезную информацию о трассировке, должен ли я найти эту область кода... (все они ссылаются на реализацию журнала, а не на фактический script, который вызвал сообщение журнала)
![enter image description here]()
В принципе, мое приложение представляет собой очень подключаемую инфраструктуру, и любой выход журнала может возникать в любом количестве кадров.
Поэтому я хочу, чтобы каждое сообщение журнала включало специальный уникальный идентификатор в начале сообщения журнала.
Я попытался заменить метод console.log своим, но хром жалуется на
Uncaught TypeError: Illegal invocation
вот как я его переопределяю
var orig = console.log;
console.log = function( message )
{
orig( (window == top ? '[root]' : '[' + window.name + ']') + ': ' + message );
}
Любые идеи?
[EDIT]
Примечание. После исправления проблемы "незаконного вызова" кажется, что имя файла /linenumber все еще "загрязнено" переопределением...
[EDIT]
Похоже, что общий ответ - НЕТ - несмотря на некоторые запутанные гонимые погони, желаемая функциональность НЕ достижима в текущих версиях браузеров.
Ответы
Ответ 1
Да, можно добавить информацию, не испортив номера исходной строки вызова журнала. Некоторые из других ответов здесь приблизились, но трюк заключается в том, чтобы ваш пользовательский метод ведения журнала возвращал модифицированный регистратор. Ниже приведен простой пример, который был только умеренно проверен, который использует контекстный вариант.
log = function() {
var context = "My Descriptive Logger Prefix:";
return Function.prototype.bind.call(console.log, console, context);
}();
Это можно использовать с:
log("A log message...");
Вот jsfiddle: http://jsfiddle.net/qprro98v/
Можно легко получить креатив и передать переменную контекста, а также удалить автоматически исполняемые параметры из определения функции. то есть log ( "DEBUG:" ) ( "Отладочное сообщение" ), журнал ( "INFO:" ) ( "Вот некоторая информация" ) и т.д.
Единственная действительно импортирующая часть функции (в отношении номеров строк) заключается в том, что она возвращает регистратор.
Ответ 2
Если ваш случай использования может иметь дело с несколькими ограничениями, есть способ, которым это можно заставить работать. Ограничения:
-
Дополнительный лог-контент должен быть рассчитан во время привязки; он не может быть чувствительным к времени или в зависимости от сообщения входящего журнала.
-
Дополнительный контент журнала может быть размещен только в начале сообщения журнала.
С этими ограничениями для вас может работать следующее:
var context = "ALIASED LOG:"
var logalias;
if (console.log.bind === 'undefined') { // IE < 10
logalias = Function.prototype.bind.call(console.log, console, context);
}
else {
logalias = console.log.bind(console, context);
}
logalias('Hello, world!');
http://jsfiddle.net/Wk2mf/
Ответ 3
На самом деле это возможно в хроме. Вот самое актуальное. Это может варьироваться в зависимости от настройки, и как я получил расщепления, нужно просто зарегистрировать весь стек и найти нужную мне информацию.
var stack = new Error().stack;
var file = stack.split("\n")[2].split("/")[4].split("?")[0]
var line = stack.split("\n")[2].split(":")[5];
Вот и все, сохраняя ведение журнала собственных объектов.
var orig = console.log
console.log = function(input) {
var isChrome = navigator.userAgent.indexOf("Chrome") !== -1;
if(isChrome){
var stack = new Error().stack;
var file = stack.split("\n")[2].split("/")[4].split("?")[0]
var line = stack.split("\n")[2].split(":")[5];
var append = file + ":" + line;
}
orig.apply(console, [input, append])
}
Ответ 4
Допустимым решением может быть создание собственной функции регистрации, которая возвращает функцию console.log
, связанную с аргументами журнала.
log = function() {
// Put your extension code here
var args = Array.prototype.slice.call(arguments);
args.unshift(console);
return Function.prototype.bind.apply(console.log, args);
}
// Note the extra () to call the original console.log
log("Foo", {bar: 1})();
Ответ 5
Вам нужно вызвать console.log
с правильным контекстом (console
):
orig.call(console, message);
Чтобы выполнить свою функцию, разрешив несколько аргументов:
var orig = console.log;
console.log = function() {
var msgs = [],
prefix = (window== top ? '[root]' : '[' + window.name + ']');
while(arguments.length) {
msgs.push(prefix + ': ' + [].shift.call(arguments));
}
orig.apply(console, msgs);
};
Демо: http://jsfiddle.net/je2wR/
Помните, что вы теряете встроенный браузер объектов/массивов в консоли при объединении объектов со строками с помощью знака +.
Ответ 6
Я только что ответил на это сообщение, которое помогло мне ответить на исходный вопрос "alias":
(http://stackoverflow.com/a/12942764/401735)
my_log_alias = console.log.bind(console)
По-видимому, была создана возможность сделать это. Протестировано. Работает.
после этого my_log_alias совпадает с console.log и может быть вызван таким же образом; Вызов этого изнутри функции будет сообщать номер строки для этого вызова функции, включая строку внутри псевдонима или функции совета, где это применимо.
В частности, номер строки, которую предоставляет Chrome, укажет вам файл, в котором находится строка, поэтому то, что вы делаете, может быть ненужным; Подумайте о том, как сообщить об этом в качестве запроса об ошибке/функции в chrome, чтобы он предоставил эту информацию в console.log.
Ответ 7
Кристофер Керри обеспечил отличное решение. Я немного расширил его для своих нужд. Здесь модуль AMD:
define([], function () {
var enableDebug = true;
var separator = ">";
function bind(f, thisArg, ctx) {
if (f.bind !== 'undefined') { // IE < 10
return Function.prototype.bind.call(f, thisArg, ctx);
}
else {
return f.bind(thisArg, ctx);
}
}
function newConsole(context, parentConsole) {
var log;
var debug;
var warn;
var error;
if (!parentConsole) {
parentConsole = console;
}
context = context + separator;
if (enableDebug) {
debug = bind(console.log, console, context + "DEBUG" + separator);
} else {
debug = function () {
// suppress all debug messages
};
}
log = bind(console.log, console, context);
warn = bind(console.warn, console, context);
error = bind(console.error, console, context);
return {
debug: debug,
info: log,
log: log,
warn: warn,
error: error,
/* access console context information */
context: context,
/* create a new console with nested context */
nest: function (subContext) {
return newConsole(context + subContext, this);
},
parent: parentConsole
};
}
return newConsole("");
});
По умолчанию это выведет > {message}
. Вы также можете добавить вложенные контексты для ведения журнала, например. console.nest("my").log("test")
выводит >my> test
.
Я также добавил функцию debug
, которая будет отступать сообщениями с >DEBUG>
Надеюсь, что кто-нибудь найдет это полезным.
Ответ 8
Я просмотрел это несколько раз и всегда считал, что это невозможно.
Мое обходное решение, если вам интересно, - назначить консоль другой переменной, а затем обернуть все мои сообщения журнала в функцию, которая позволяет мне изменять/стиль/что угодно в сообщении.
Он отлично выглядит с CoffeeScript, не уверен, что он практичен с простым JS.
Я просто привык к префиксу всего x
.
logger.debug x 'Foo'
log x 'Bar'
log x('FooBar %o'), obj
Ответ 9
В настоящее время это невозможно, в будущем мы можем сделать это с помощью объекта Proxy в ECMAScript 6.
Мой вариант использования состоял в том, чтобы автоматически префиксировать консольные сообщения с полезной информацией, такой как переданные аргументы и метод выполнения. в настоящий момент наиболее близким является использование Function.prototype.apply
.
Простой подход состоит в том, чтобы просто написать ваши отладочные операторы как таковые:
console.info('=== LazyLoad.css(', arguments, '): css files are skipped, gives us a clean slate to style within theme\ CSS.');
Сложный подход заключается в использовании вспомогательной функции, как описано ниже, я лично сейчас предпочитаю простой подход.
![Extending 'console.debug' function approach]()
/* Debug prefixing function
* ===========================
*
* A helper used to provide useful prefixing information
* when calling 'console.log', 'console.debug', 'console.error'.
* But the catch is that to utilize one must leverage the
* '.apply' function as shown in the below examples.
*
* '''
* console.debug.apply(console, _fDebugPrefix(arguments)
* .concat('your message'));
*
* // or if you need to pass non strings
* console.debug.apply(console, _fDebugPrefix(arguments)
* .concat('json response was:', oJson));
*
*
* // if you need to use strict mode ("use strict") one can't
* // extract the function name but following approach works very
* // well; updating the name is just a matter of search and replace
* var aDebugPrefix = ['fYourFunctionName('
* ,Array.prototype.slice.call(arguments, 0),
* ,')'];
* console.debug.apply(console,
* aDebugPrefix.concat(['json response was:', oJson]));
* '''
*/
function _fDebugPrefix(oArguments) {
try {
return [oArguments.callee.name + '('
,Array.prototype.slice.call(oArguments, 0)
, ')'];
}
catch(err) { // are we in "use strict" mode ?
return ['<callee.name unsupported in "use strict">('
,Array.prototype.slice.call(oArguments, 0)
, ')'];
}
}
Ответ 10
Я столкнулся с этой проблемой также о расширении console.log(), чтобы приложение могло расширять, управлять и делать причудливые вещи вместе с тем, чтобы записывать материал на консоль. Однако потеря информации о номере линии была равносильна отказу. После борьбы с этим вопросом я придумал длинный способ обхода, но, по крайней мере, он все еще использует "1-лайнер".
Сначала определите глобальный класс для использования или добавления некоторых методов в ваш основной существующий класс "app":
/**
* Log message to our in-app and possibly on-screen console, return args.
* @param {!string} aMsgLevel - one of "log", "debug", "info", "warn", or "error"
* @param {any} aArgs - the arguments to log (not used directly, just documentation helper)
* @returns args so it can be nested within a console.log.apply(console,app.log()) statement.
*/
MyGlobalClassWithLogMethods.prototype.debugLog = function(aMsgLevel, aArgs) {
var s = '';
var args = [];
for (var i=1; i<arguments.length; i++) {
args.push(arguments[i]);
if (arguments[i])
s += arguments[i].toString()+' ';
}
if (typeof this.mLog === 'undefined')
this.mLog = [];
this.mLog.push({level: aMsgLevel, msg: s});
return args;
};
MyGlobalClassWithLogMethods.prototype.log = function() {
var args = ['log'].concat(Array.prototype.slice.call(arguments));
return this.debugLog.apply(this,args);
};
MyGlobalClassWithLogMethods.prototype.debug = function() {
var args = ['debug'].concat(Array.prototype.slice.call(arguments));
return this.debugLog.apply(this,args);
};
MyGlobalClassWithLogMethods.prototype.info = function() {
var args = ['info'].concat(Array.prototype.slice.call(arguments));
return this.debugLog.apply(this,args);
};
MyGlobalClassWithLogMethods.prototype.warn = function() {
var args = ['warn'].concat(Array.prototype.slice.call(arguments));
return this.debugLog.apply(this,args);
};
MyGlobalClassWithLogMethods.prototype.error = function() {
var args = ['error'].concat(Array.prototype.slice.call(arguments));
return this.debugLog.apply(this,args);
};
//not necessary, but it is used in my example code, so defining it
MyGlobalClassWithLogMethods.prototype.toString = function() {
return "app: " + JSON.stringify(this);
};
Затем мы применяем эти методы так:
//JS line done as early as possible so rest of app can use logging mechanism
window.app = new MyGlobalClassWithLogMethods();
//only way to get "line info" reliably as well as log the msg for actual page display;
// ugly, but works. Any number of params accepted, and any kind of var will get
// converted to str using .toString() method.
console.log.apply(console,app.log('the log msg'));
console.debug.apply(console,app.debug('the log msg','(debug)', app));
console.info.apply(console,app.info('the log msg','(info)'));
console.warn.apply(console,app.warn('the log msg','(warn)'));
console.error.apply(console,app.error('the log msg','(error)'));
Теперь консоль получает сообщения журнала с соответствующей информацией о строке, а также наше приложение содержит массив сообщений журнала, которые можно использовать. Например, чтобы отобразить ваш журнал в приложении с помощью HTML, JQuery и некоторых CSS, можно использовать следующий упрощенный пример.
Во-первых, HTML:
<div id="debug_area">
<h4 class="text-center">Debug Log</h4>
<ul id="log_list">
<!-- console log/debug/info/warn/error ('msg') lines will go here -->
</ul>
</div>
некоторый CSS:
.log_level_log {
color: black;
background-color: white;
font-size: x-small;
}
.log_level_debug {
color: #060;
background-color: #80FF80;
font-size: x-small;
}
.log_level_info {
color: #00F;
background-color: #BEF;
font-size: x-small;
}
.log_level_warn {
color: #E65C00;
background-color: #FB8;
font-size: x-small;
}
.log_level_error {
color: #F00;
background-color: #FBB;
font-size: x-small;
}
и некоторые JQuery:
var theLog = app.mLog || [];
if (theLog.length>0) {
var theLogList = $('#log_list');
theLogList.empty();
for (var i=0; i<theLog.length; i++) {
theLogList.prepend($('<li class="log_level_'+theLog[i].level+'"></li>').text(theLog[i].msg));
}
}
Это упрощенное использование, но как только у вас есть механизм на месте, вы можете делать все, что может придумать ваше воображение, в том числе оставить строки журнала в коде, но установить порог, чтобы пройти только предупреждения и ошибки, Надеюсь, это поможет другим своим проектам.
Ответ 11
Попробуйте setTimeout(console.log.bind(console,'foo'));
Ответ 12
Недавно Chrome представила функцию, которая может решить вашу проблему без взлома кода. Он называется "черный ящик", который в основном позволяет отмечать файлы, которые следует игнорировать с помощью своих инструментов.
https://gist.github.com/paulirish/c307a5a585ddbcc17242
Да, это решение специфично для браузера, но если вы используете Chrome, вам нужно это решение.
Решения с огромным взломом при опрокидывании ошибки для каждого журнала могут отображать правильную строку, но это не будет кликабельная ссылка в вашей консоли.
Решения, основанные на привязке/сглаживании, позволяют изменять печатный текст. Вы не сможете переслать аргументы третьей функции для дальнейшей обработки.