Разработчикам удобно пользоваться консолью для отладки, но ещё удобнее, если будет оболочка, в которой учтены особенности реализации консоли в различных браузерах, поэтому тема обёрток для консоли устойчиво существует.
Рассмотрим ранее опубликованные решения, затем сделаем обзор методов консоли с помощью перевода недавней статьи Axel Rauschmayer-а, разработчика и консультанта с более чем 15-летним стажем, затем я опубликую некоторые свои решения, которые оказались удачными в процессе эволюции и отладки на ряде проектов.
Обёртки консоли на Хабре, обзоры и документация
⚫ "Используем console «на полную»" — показывает способы отличной обработки объектов, учёт особенностей различных браузеров в реализации.
Делаем консоль чуточку удобнее — Подменяет исходный объект, что решает некоторые баги. Отлично исправляет деградацию некоторых браузеров по полноте поддержки методов. Остаётся разве что длинность написания нативных методов, что есть плюс в плане неизучения новых названий, но требует набора оригинальных слов. Может быть решено ускорителями набора типа emmet в IDE.
⚫ simple wrapper for console.log — 2010 (англ.).
⚫ Console.Log: Say Goodbye to JavaScript Alerts for Debugging! (IE), 2011 (англ.)
00
⚫ "Firebug* console API" — эта статья в чём-то полнее последующего перевода. Обе они дадут взаимно дополняющую информацию. (Воспользуемся переводом, чтобы самостоятельно не тестировать вручную, повторяя проделанную автором работу.)
⚫ Перевод обзора из блога Axel Rauschmayer
Итоговая таблица с сортировкой методов по алфавиту.
В большинстве браузеров существует глобальный объект console с методами для логирования и отладки. Он — не часть языка, но стал фактическим стандартом, появившись вначале в отладчике Firebug. Так как основная цель для него — отладка, он часто используется при разработке и редко — в работающем коде.
Как стандартизирована консоль в различных браузерах?
Firebug первым начал продвигать API консоли и его вики-документацию, успешнее других приближаясь к стандартизации. Кроме того, Brian Kardell и Paul Irish работают над спецификацией API, что в перспективе должно дать лучшую согласованность поведения браузеров. ДО сих пор их правила довольно различны, поэтому данная статья даст общее краткое описание. Дополнительную информацию вы получите в документации к различным платформам.
Chrome: developers.google.com/chrome-developer-tools/docs/console-api/
Firebug: getfirebug.com/wiki/index.php/Console_API
Firefox: developer.mozilla.org/en-US/docs/Web/API/console
IExplorer: msdn.microsoft.com/en-us/library/ie/hh772183.aspx
Node.js: nodejs.org/api/stdio.html
Safari: Safari Developer Guide
Баг в IE9: объект console существует, если хотя бы раз было открыто окно средств разработчика (Developer Tools? F12). Иначе — происходит ошибка ReferenceError. Как вариант обхода бага, нужно проверять наличие объекта и ставить заглушку в случае отсутствия.
Методы для простого логирования
⚫ console.clear() — очистить консоль;
⚫ console.debug(object1, object2?, ...) — то же, что console.log() (вопросики означают необязательность аргумента);
⚫ console.error(object1, object2?, ...) — логирование параметров под значком ошибки (без остановки кода) и, возможно, добавляется трассировка стека вызовов и ссылка на код.
⚫ console.exception(errorObject, object1?, ...]) [только в Firebug] — объекты с интерактивным стеком трассировки;
⚫ console.info(object1?, object2?, ...) — логирование в консоль; в браузерах может помечаться значком и, возможно, имеет трассировку стека или ссылку; поддерживаются шаблоны printf, как в console.log.
⚫ console.log(object1?, object2?, ...) — логирование в консоль. Если первый аргумент — строка в формате директив printf, она форматирует значения остальных аргументов. Пример (Node.js REPL):
> console.log('%s', { foo: 'bar' })
[object Object]
> console.log('%j', { foo: 'bar' })
{"foo":"bar"}
Единственная надёжная кроссплатформенная директива форматирования — это '%s'. Node.js поддерживает '%j' для JSON-данных. Браузеры могут поддерживать другие директивы интерактивных действий для консоли (подробнее здесь (рус.)).
⚫ console.trace() — показ интерактивного стека вызовов функций в браузерах (стек вызовов, приведший к выполнению кода в данной точке, аналогично тому, что видим в сообщениях об ошибках);
⚫ console.warn(object1?, object2?, ...) — логирование под значком предупреждения; может содержать трассировку стека или ссылку. Поддерживаются шаблоны printf, как в console.log.
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
---|---|---|---|---|---|---|
clear() | ✓ | ✓ | -⊝- | ✓ | -⊝- | ✓ |
debug() | ✓ | ✓ | ✓ | ✓ | -⊝- | ✓ |
error() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
exception() | -⊝- | ✓ | -⊝- | -⊝- | -⊝- | -⊝- |
info() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
log() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
trace() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
warn() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Методы для проверок и подсчёта
⚫ console.assert(expr, obj?) — если первый аргумент ложен, то выводит объект в консоль и выбрасывает исключение; если true — ничего не делает;
⚫ console.count(label?) — подсчитывает, сколько раз встретилась функция с этой меткой.
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
---|---|---|---|---|---|---|
assert() | ✓ | ✓ | -⊝- | ✓ | ✓ | ✓ |
count() | ✓ | ✓ | -⊝- | ✓ | -⊝- | ✓ |
Методы для логов с форматированием
⚫ console.dir(object) — выводит представление объекта в консоли. Может быть интерактивно — разворачиваться, просматриваться в других вкладках инструмента (в Node.js — без интерактивности).
⚫ console.dirxml(object) — выводит XML-дерево элемента HTML или XML.
⚫ console.group(object1?, object2?, ...) — начинает вывод сворачиваемого объекта в консоли, содержащего группы указанных и будущих значений в каждой новой строке. Блок объявляется завершённым командой console.groupEnd() и изначально развёрнут для просмотра, но может сворачиваться-разворачиваться вручную (мышью).
⚫ console.groupCollapsed(object1?, object2?, ...) — работает аналогично console.group(), но блок изначально свёрнут.
⚫ console.groupEnd() — закрывает группу, которая была начата console.group() или console.groupCollapsed().
⚫ console.table(data, columns?) — выводит массив как таблицу, по одному элементу на строку. Дополнительный аргумент указывает, какие свойства массива отображаются в колонках. Если пропущен — отображаются все свойства. Несуществующие свойства отображаются в колонках как неопределённые.
var persons = [
{ firstName: 'Jane', lastName: 'Bond' },
{ firstName: 'Lars', lastName: 'Croft', age: 72 }
];
// Эквивалентные записи:
console.table(persons);
console.table(persons, ['firstName', 'lastName', 'age']);
Будем видеть в консоли:
(index) | firstName | lastName | age |
---|---|---|---|
0 | «Jane» | «Bond» | undefined |
1 | «Lars» | «Croft» | 72 |
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
---|---|---|---|---|---|---|
dir() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
dirxml() | ✓ | ✓ | -⊝- | ✓ | -⊝- | ✓ |
group() | ✓ | ✓ | ✓ | ✓ | -⊝- | ✓ |
groupCollapsed() | ✓ | ✓ | ✓ | ✓ | -⊝- | ✓ |
groupEnd() | ✓ | ✓ | ✓ | ✓ | -⊝- | ✓ |
table() | ✓ | ✓ | -⊝- | -⊝- | -⊝- | -⊝- |
Профилирование и тайминги
⚫ console.markTimeline(label) — [Safari-only] то же, что timeStamp().
⚫ console.profile(title?) — включение профилирования. Необязательный аргумент используется для комментирования в отчёте.
⚫ console.profileEnd() — останавливает профилирование и выводит отчёт.
⚫ console.time(label) — запускает таймер с указанной меткой (названием, идентификатором).
⚫ console.timeEnd(label) — останавливает таймер с меткой и показывает насчитанное время.
⚫ console.timeStamp(label?) — выводит промежуточные отсчёты времени для таймера с указанной меткой.
Chrome | Firebug | Firefox | IE | Node.js | Safari | |
---|---|---|---|---|---|---|
markTimeline() | -⊝- | -⊝- | -⊝- | -⊝- | -⊝- | ✓ |
profile() | ✓ | ✓ | (devtools) | ✓ | -⊝- | ✓ |
profileEnd() | ✓ | ✓ | (devtools) | ✓ | -⊝- | ✓ |
time() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
timeEnd() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
timeStamp() | ✓ | ✓ | -⊝- | -⊝- | -⊝- | -⊝- |
"(devtools)" означает, что метод будет работать в случае, если открыта панель инструментов разработчика.
Благодарности:
В подготовке этого обзора участвовали два человека: Matthias Reuter (@ gweax) и Philipp Kyeck (@ pkyeck).
--Автор: Axel Rauschmayer. (Конец перевода.)
Итоговая таблица с сортировкой по алфавиту. (Ссылки помогут увидеть подробности и прочитать о поддержке Оперой в дополнение к этой статье. В последнюю колонку добавлены краткие замечания об Опере оттуда.)
Chrome | Firebug | Firefox | IE | Node.js | Safari | Opera | |
---|---|---|---|---|---|---|---|
assert() | ✓ | ✓ | -⊝- | ✓ | ✓ | ✓ | ± |
clear() | ✓ | ✓ | -⊝- | ✓ | -⊝- | ✓ | ✓ |
count() | ✓ | ✓ | -⊝- | ✓ | -⊝- | ✓ | ± |
debug() | ✓ | ✓ | ✓ | ✓ | -⊝- | ✓ | ± |
dir() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
dirxml() | ✓ | ✓ | -⊝- | ✓ | -⊝- | ✓ | ± |
error() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ± |
exception() | -⊝- | ✓ | -⊝- | -⊝- | -⊝- | -⊝- | ± |
group() | ✓ | ✓ | ✓ | ✓ | -⊝- | ✓ | ✓ |
groupCollapsed() | ✓ | ✓ | ✓ | ✓ | -⊝- | ✓ | ✓ |
groupEnd() | ✓ | ✓ | ✓ | ✓ | -⊝- | ✓ | ✓ |
info() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
log() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ± |
markTimeline() | -⊝- | -⊝- | -⊝- | -⊝- | -⊝- | ✓ | -⊝- |
profile() | ✓ | ✓ | (devtools) | ✓ | -⊝- | ✓ | -⊝- |
profileEnd() | ✓ | ✓ | (devtools) | ✓ | -⊝- | ✓ | -⊝- |
table() | ✓ | ✓ | -⊝- | -⊝- | -⊝- | -⊝- | -⊝- |
time() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ± |
timeEnd() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ± |
timeStamp() | ✓ | ✓ | -⊝- | -⊝- | -⊝- | -⊝- | -⊝- |
trace() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ± |
warn() | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
Спасибо автору блога за свежие сведения и таблицы, относящиеся к методам консоли. Зарядившись попкорном, продолжим разговор. Имеем все методы, чтобы пользоваться, но чаще всего не нужно всех. Достаточно иногда одного, но универсального console.log. Есть ниши задач, где нужны скромные, но кроссбраузерные возможности.
Несколько сниппетов (вставок кода с функциями), для различных применений
Всё, что выше — это красиво, годится как справочник, довольно полно и хорошо. Но нужны решения, а не теория — ведь для каждой мелкой задачи понадобятся похожие решения.
Опыт показывает, что совсем не нужно иметь исчерпывающую поддержку всех функций — чаще всего достаточно одной или нескольких, и больше интересны сервисные функции: отключить консоль полностью одной переменной или выражением (когда код выложен на продакшн), выводить только ошибки по переменной или готовить ошибки для отсылки в техподдержку проекта, иметь управляемый вывод сообщений в виде нескольких вариантов.
Сложные и некроссбраузерные функции скорее не нужны, чем нужны: красивый вывод таблиц, не позволяющий отлаживаться в IE или Safari, будет скорее мешать, заставит возвращаться к уровню настроек консоли в неподходящие моменты.
Поэтому, исходя из опыта, примеры будут максимально простые, но работающие и без лишнего кода. Если части кода не понадобится, проще выбрать для проекта или страницы менее сложный пример.
Вначале надо проделать собственные измышления о том, что нам надо иметь. Нелюбители читать чьи-то измышления могут на этом оставить статью. На основании них будут построены примеры.
1. Дизайн кода функций.
Поговорим и выберем дизайн кода. Это — не дизайн страницы, это — то, как код будет смотреться в текстовом редакторе.
Для отладки имеем 2 стандартных способа и, соответственно, дизайна — функции типа alert/confirm/prompt и методы объекта console. Замещать стандартные имена функций и методов — всё же, не всегда хорошо. Эа исключением случаев, когда надо предотвратить ошибки реализаций, как в IE. Для своей отладки, на мой взгляд, целесообразнее выбрать другое имя для функций или их группы. Например, я экспериментировал с применением слова «Alert», с большой буквы, но и оно показалось длинным после нескольких проектов, и я перешёл на «wcl()» — символическое сокращение от «window.console.log». если вам не понравился выбор, подставьте в примеры свой вариант.
Из «wcl()» логично и понятно следуют остальные сокращения — «wci» — window.console.info; wcw — window.console.warn; wce — window.console.error. Такие слова редко встречаются в именах перемеенных, достаточно короткие и нормально отыскиваются взглядом или поиском по проекту. Для таймингов добавим wct(), а для сброса консоли — wcc().
Эти функции предлагается класть сразу в глобальный объект. Это не будет засорять пространство глобального объекта, потому что на продакшене их можно при желании выкусить из кодов проекта. А применение экономит не менее 2 символов или больше, чем если бы они были в объекте (типа C.log, C.err,...).
На этом дизайн не закончен — достаточно удобным оказался ещё такой финт, чтобы приписать их в методы объекта String.
String.prototype.wcl = wcl;
Не спешите поднимать негодующие руки — это не нарушение чистых принципов, потому что работать это будет, опять же, на этапе отладки, разработки. На чистом проекте их тоже можно из кода выкусить. А помогает способ тем, что отладочные сообщения легко искать через Ctrl-F.
'Ajax_request'.wcl(data); //даёт вывод 'Ajax_request' Object{...данные...}
//Равносильно
wcl('Ajax_request', data);
Найти в коде этот фрагмент — по строке "Ajax_request'" (с апострофом в конце). В начале строки мы вольны поставить свои дополнительные символы для лучшего выделения сообщения в логе, например"==".
Дизайн вывода: лог не всегда доступен в браузерах. Это верно не только для IE с его знаменитым багом, но и для браузеров на телевизорах — в Smart TV — технологиях и в ТВ-приставках кабельного телевидения используются браузеры, не имеющие консольного вывода и не собирающиеся его иметь. Приходится использовать удалённый отладчик или вывод в блок на экране. Идеально, если будет переменная, которая позволит показать или создать блок, и переводящая весь лог на экран. Не помешает он и для IE, избавив нас от отслеживания ошибок отсутствия объекта.
Наконец, если надо быстро очистить продакшн от логов, в оболочке надо иметь выражение, запрещающее вывод логов. Например, выводить, если домен — localhost и не иначе. Тогда не требуется удалять их из кода парсингом проекта, хотя выключенная отладка будет немного нагружать JS и увеличивать код.
Подведём итоги кодового дизайна (он сформировался не сейчас на этих рассуждениях, а года за 2 практики; рассуждения — способ объяснить причины происхождения и получаемые удобства).
1) используем имена для логов: wcw, wci, wcl, wce, wcc, wct;
2) прочие возможности использовать не будем — не доросли до использования, но доросли до понимания, что простое лучше, чем сложное;
3) все функции могут работать как методы объекта String для удобства написания в коде: 'строка'.wcl();
4) могут отключаться одним выражением;
5) может выводить логи в другое представление — див на экране или удалённая консоль;
6) интересна возможность динамического переключения потоков для распределения информации.
2. Сниппеты
2.1. Простое логирование без IE
var noConsole =0, win = window
,wcl = function(a){ a = a!==undefined ? a :''; //консоль как метод строки или функция, с отключением по noConsole ==1
if(win.console && !noConsole)
win.console.log.apply(console, this instanceof String
? ["'=="+ this +"'"].concat([].slice.call(arguments))
: arguments);
};
String.prototype.wcl = wcl;
Здесь есть пара элементов простой уличной магии: первая строка функции позволяет не указывать аргументов и не иметь ошибок для выражений вида 'место_трассировки_116'.wcl(). А выражение [].slice.call(arguments) позволяет приобрести коллекции аргументов сввойство массива, чтобы они без ошибок могли участвовать в операции concat(). (Об этом нередко спрашивают на собеседованиях: каким способом вы превращаете коллекцию в массив?)
Если решили вообще отказаться от свойства объекта, получается совсем коротко (тут вопрос — в дизайне кода, устроит ли нас написание только в формате wcl(...)):
var noConsole =0, win = window
,wcl = function(){ //консоль как метод строки или функция, с отключением по noConsole ==1
if(win.console && !noConsole)
win.console.log(arguments);
};
Не проверяем отсутствие аргументов, поскольку просто «wcl();» без аргументов использовать не будем. Будет работать и в IE, если открыто окно инструментов разработчика.
2.2. Простое логирование с IE
Непонимание браузером IE того, что console.log — это функция, приводит к ещё одному витку магии (и, в общем, немного замедляет работу во всех бр-рах, поэтому лучше использовать, если действительно нужен IE).
var noConsole =0, win = window
,wcl = function(a){ a = a!==undefined ? a :''; //консоль как метод строки или функция, с откл. по noConsole ==1, +IE
if(win.console && !noConsole)
Function.prototype.apply.call(console.log, console, this instanceof String
? ["'=="+ this +"'"].concat([].slice.call(arguments))
: arguments);
};
String.prototype.wcl = wcl;
2.3. Четыре уровня сообщений в логах
Если хотим немного раскрасить вывод, чтобы на цвет различать важность и характер сообщений своего проекта, воспользуемся копипейстом используем написанный в 2.1 код для работы 4 похожих и всеми поддерживаемых функций — log, warn, info, error. Поскольку копипейст в коде — не лучший, хотя и простой метод, скопируем следующий сниппет, где копипейст уже преобразован в цикл, и добавлена интересная возможность — указать уровень сообщений, которые будут выводиться в лог. Уровни:
0: warn, (warning)
1: info,
2: log,
3: error.
Некоторая переменная logLevel будет указывать, ниже какого уровня сообщения не выводить.
(function(w, logLevel, wcA){ var lvl =0
,$x = function(el, h){if(h) for(var i in h) el[i] = h[i]; return el};
for(var i in wcA) //консоль[i] как метод строки или функция
w[i] = (function(lvl, wcAI, i){
return function(a){ a = a!==undefined|| arguments.length ? a :'';
if(w.console && logLevel <= lvl)
Function.prototype.apply.call(w.console[i], w.console, this instanceof String
//w.console[i].apply(console, this instanceof String //--for without IE
? [wcAI + this +"'"].concat([].slice.call(arguments))
: arguments);
else
w.console[i] = function(){};
} })(lvl++, wcA[i], {wcw:'warn', wci:'info', wcl:'log', wce:'error'}[i]);
w.wcc = w.console.clear;
$x(String.prototype, {wcw: w.wcw, wci: w.wci, wcl: w.wcl, wce: w.wce, wcc: w.wcc });
})(window, /*logLevel*/ 0, {wcw:"'-w-", wci:'--', wcl:"'==", wce:"'=E="});
2.4. Четыре уровня сообщений в логах или в блоке на экране
На случай невозможности пользоваться консолью код придётся расширить практически вдвое, чтобы формирвать вывод логов в видимый блок на экране. Как дополнительную функцию, добавляется возможность перезапускать логгер в любом месте программы, меняя как подробность логирования выбором logLevel, так и вывод на экран или в консоль. Отключается логирование установкой logLevel = 4 при перезапуске.
(Чтобы это запустилось в IE, нужны вспомогательные определения: )
if(!Array.indexOf) //old browser support
Array.prototype.indexOf = function(obj){
for(var i =0, iL = this.length; i < iL; i++)
if(this[i] == obj)
return i;
return -1;
};
if(!document.getElementsByClassName)
document.getElementsByClassName = function(className){
if(!className) return [];
var e = document.getElementsByTagName('*')
,list = [];
for(var i =0, iL = e.length; i < iL; i++){
var clss = e[i].className.split(' ');
if(clss.indexOf(className) >-1)
list.push(e[i]);
}
return list;
};
$e() — это способ генерации блоков:
var $e = function(g){//g={el,cl,ht,cs,at,on,apT}
if(!g.el && g.el !==undefined && g.el !='') return g.el;
g.el = g.el ||'DIV';
var o = g.el = typeof g.el =='string'? document.createElement(g.el) : g.el;
if(o){
if(g.cl)
o.className = g.cl;
if(g.cs){
if(!IE) $x(o.style, g.cs);
else{
var s ='';
for(i in g.cs)
s += toCsKey(i) +':'+ g.cs[i] +';';
o.style.cssText = s;
}}
if(g.ht || g.at){
var at = g.at ||{}; if(g.ht) at.innerHTML = g.ht;}
if(at)
for(var i in at){
if(i=='innerHTML') o[i] = at[i];
else o.setAttribute(i, at[i]);}
g.apT && g.apT.appendChild(o); //ставится по ориентации, если новый
return o;
}
var logOnScreen =1
,logLevel =0 //0..4
,consoleOrig
,loadLogger = function(onScreen, logLevel){ logLevel = logLevel !==undefined ? logLevel : 3;
var w = window, wcA ={wcw:"'-w-", wci:'--', wcl:"'==", wce:"'=E="}
,cons = w.document.getElementsByClassName('console')[0];
if(onScreen){ //вывод сообщений консоли в блок на экране
if(!cons)
cons = $e({cl:'console',cs:{position:'fixed',width:'600px',minHeight:'150px',maxHeight:'800px',overflow:'auto',overflowX:'hidden',overflowY:'auto',top:'-2px',left:'300px',zIndex:99999,fontSize:'13px',fontFamily:'Arial',backgroundColor:'#a5c6ee',opacity:0.65, filter:'progid:DXImageTransform.Microsoft.Alpha(opacity=65)'}, apT: w.document.body });
cons && (cons.style.display ='block');
var consA = {warn:'w', info:'i', log:'', error:'E'};
if(!w.console) w.console ={};
consoleOrig = w.console;
w.console ={};
lvl =0;
for(var i in consA){
w.console[i] = (function(lvl, consAI, conCA){return function(aa){
if(cons && logLevel <= lvl){
cons.innerHTML +=['<i class=cons'+ conCA +'>'+ (this instanceof String ?"'=="+ this +"'": consAI) +'</i>'].concat([].slice.call(arguments))
.join('<i class=consDelim>/ </i>') +'<br>';
cons.scrollTop = Math.max(0, cons.scrollHeight);
}
} })(lvl++, consA[i], i.charAt(0).toUpperCase() + i.substr(1) );
}
w.console.clear = function(a){if(cons) cons.innerHTML ='';}
}else
cons && (cons.style.display ='none');
lvl =0;
for(var i in wcA) //консоль[i] как метод строки или функция
w[i] = (function(lvl, wcAI, i){
return function(a){ a = a!==undefined|| arguments.length ? a :'';
if(w.console && logLevel <= lvl)
Function.prototype.apply.call(w.console[i], w.console, this instanceof String
//w.console[i].apply(console, this instanceof String //--for without IE
? [wcAI + this +"'"].concat([].slice.call(arguments))
: arguments);
else
w.console[i] = function(){};
} })(lvl++, wcA[i], {wcw:'warn', wci:'info', wcl:'log', wce:'error'}[i]);
w.wcc = w.console.clear;
$x(String.prototype, {wcw: w.wcw, wci: w.wci, wcl: w.wcl, wce: w.wce, wcc: w.wcc });
};
Запускается этот логгер после загрузки DOM, потому что может использоваться див для вывода логов.
if(window.addEventListener)
this.addEventListener('DOMContentLoaded',tst,!1);
else
this.attachEvent('onload',tst);
var tst = function(){
loadLogger(logOnScreen, logLevel);
wcl('tst1');
wcl();
'tst2'.wcl();
'tst3'.wcl({t: 23, o:{s: true}});
'tst-wcw'.wcw(120)
'tst-wci'.wci(121)
'tst-wcl'.wcl(122)
'tst-wce'.wce(123)
};
Если высота текста превысит максимальную высоту блока, будет действовать подкрутка скролла строкой «cons.scrollTop = Math.max(0, cons.scrollHeight);».
3. Дизайн таймингов
Есть основания не придерживаться формата логов группы «time*», потому что в исходном формате они малоинформативны. Используется только один аргумент, а строка вывода содержит только сосчитанное время. Чтобы строка не пустовала, лучше заполнить её одним из форматов логов, например, wci(), поставив в него посчитанный интервал и другие значения из остальных аргументов. Правда, для этого надо продублировать механизм подсчёта, сделав заодно его и для IE. Это же даст возможность выводить значения в див.
Сделаем для начала проще — пусть таймеры работают только для консоли. Но у нас есть избыточная форма: контекстный метод и обычная функция. Пусть 'x'.wct() будет стартом таймера, а wct('x') — его окончанием. Если же аргументов больше двух — выводится 2 строки: обычный лог, а затем тайминг.
В этой системе нет места timeStamp(), хотя можно было бы придумать для них функцию wcts(), тоже с любым количеством аргументов. Но лучше придерживаться минимализма.
var logOnScreen =0
,logLevel =1 //0..4
,logTime =1
,consoleOrig
,loadLogger = function(onScreen, logLevel){ logLevel = logLevel !==undefined ? logLevel : 3;
var w = window, wcA ={wcw:"'-w-", wci:'--', wcl:"'==", wce:"'=E="}
,cons = w.document.getElementsByClassName('console')[0];
if(onScreen){ //вывод сообщений консоли в блок на экране
if(!cons)
cons = $e({cl:'console',cs:{position:'fixed',width:'600px',minHeight:'150px',maxHeight:'800px',overflow:'auto',overflowX:'hidden',overflowY:'auto',top:'-2px',left:'300px',zIndex:99999,fontSize:'13px',fontFamily:'Arial',backgroundColor:'#a5c6ee',opacity:0.65, filter:'progid:DXImageTransform.Microsoft.Alpha(opacity=65)'}, apT: w.document.body });
cons && (cons.style.display ='block');
var consA = {warn:'w', info:'i', log:'', error:'E'};
if(!w.console) w.console ={};
consoleOrig = w.console;
w.console ={};
lvl =0;
for(var i in consA){
w.console[i] = (function(lvl, consAI, conCA){return function(aa){
if(cons && logLevel <= lvl){
cons.innerHTML +=['<i class=cons'+ conCA +'>'+ (this instanceof String ?"'=="+ this +"'": consAI) +'</i>'].concat([].slice.call(arguments))
.join('<i class=consDelim>/ </i>') +'<br>';
cons.scrollTop = Math.max(0, cons.scrollHeight);
}
} })(lvl++, consA[i], i.charAt(0).toUpperCase() + i.substr(1) );
}
w.console.clear = function(){if(cons) cons.innerHTML ='';};
}else
cons && (cons.style.display ='none');
lvl =0;
for(var i in wcA) //консоль[i] как метод строки или функция
w[i] = (function(lvl, wcAI, i){
return function(a){ a = a!==undefined|| arguments.length ? a :'';
if(w.console && logLevel <= lvl)
Function.prototype.apply.call(w.console[i], w.console, this instanceof String
//w.console[i].apply(console, this instanceof String //--for without IE
? [wcAI + this +"'"].concat([].slice.call(arguments))
: arguments);
else
w.console[i] = function(){};
} })(lvl++, wcA[i], {wcw:'warn', wci:'info', wcl:'log', wce:'error'}[i]);
w.wcc = w.console.clear;
w.wct = !document.all && logTime ? (function(lvl, wcAI, i){
return function(a){
arguments.length ? (arguments.length !=1 || this != w ? this.wcl.apply(this,arguments) :0
,console.timeEnd.call(console, this != w ? this : a) ): console.time.call(console,this);
} })() : function(){};
$x(String.prototype, {wcw: w.wcw, wci: w.wci, wcl: w.wcl, wce: w.wce, wcc: w.wcc, wct: w.wct });
};
Проверить его можно так:
var tst = function(){
loadLogger(logOnScreen, logLevel);
'x'.wct()
wcl('tst1');
wcl();
'tst2'.wcl();
'y'.wct()
'tst3'.wcl({t: 23, o:{s: true}});
wct('x')
wct('y','другие данные')
};
Выглядит:
Автор: spmbt