Правильная обертка для console.log с правильным номером строки?
Я сейчас разрабатываю приложение и размещаю глобальный isDebug
переключатель. Я хотел бы завернуть console.log
для более удобного использования.
//isDebug controls the entire site.
var isDebug = true;
//debug.js
function debug(msg, level){
var Global = this;
if(!(Global.isDebug && Global.console && Global.console.log)){
return;
}
level = level||'info';
Global.console.log(level + ': '+ msg);
}
//main.js
debug('Here is a msg.');
Затем я получаю этот результат в консоли Firefox.
info: Here is a msg. debug.js (line 8)
Что делать, если я хочу войти с номером строки, где debug()
вызывается, как info: Here is a msg. main.js (line 2)
?
32 ответа
Это старый вопрос, и все предоставленные ответы являются чрезмерно хакерскими, имеют ОСНОВНЫЕ кросс-браузерные проблемы и не предоставляют ничего сверх полезного. Это решение работает в любом браузере и сообщает все данные консоли точно так, как должно. Никаких взломов не требуется, и одна строка кода Проверьте код ручки.
var debug = console.log.bind(window.console)
Создайте переключатель следующим образом:
isDebug = true // toggle this to turn on / off for global controll
if (isDebug) var debug = console.log.bind(window.console)
else var debug = function(){}
Затем просто позвоните следующим образом:
debug('This is happening.')
Вы можете даже взять на себя файл console.log с помощью такого переключателя:
if (!isDebug) console.log = function(){}
Если вы хотите сделать что-то полезное с этим.. Вы можете добавить все консольные методы и обернуть это в многократно используемую функцию, которая дает не только глобальный контроль, но и уровень класса:
var Debugger = function(gState, klass) {
this.debug = {}
if (gState && klass.isDebug) {
for (var m in console)
if (typeof console[m] == 'function')
this.debug[m] = console[m].bind(window.console, klass.toString()+": ")
}else{
for (var m in console)
if (typeof console[m] == 'function')
this.debug[m] = function(){}
}
return this.debug
}
isDebug = true //global debug state
debug = Debugger(isDebug, this)
debug.log('Hello log!')
debug.trace('Hello trace!')
Теперь вы можете добавить его к своим классам:
var MyClass = function() {
this.isDebug = true //local state
this.debug = Debugger(isDebug, this)
this.debug.warn('It works in classses')
}
Вы можете поддерживать номера строк и выводить уровень журнала с некоторым умным использованием Function.prototype.bind
:
function setDebug(isDebug) {
if (window.isDebug) {
window.debug = window.console.log.bind(window.console, '%s: %s');
} else {
window.debug = function() {};
}
}
setDebug(true);
// ...
debug('level', 'This is my message.'); // --> level: This is my message. (line X)
Сделав еще один шаг вперед, вы можете использовать console
есть ошибки / предупреждения / информация о различиях и все еще имеют пользовательские уровни. Попытайся!
function setDebug(isDebug) {
if (isDebug) {
window.debug = {
log: window.console.log.bind(window.console, '%s: %s'),
error: window.console.error.bind(window.console, 'error: %s'),
info: window.console.info.bind(window.console, 'info: %s'),
warn: window.console.warn.bind(window.console, 'warn: %s')
};
} else {
var __no_op = function() {};
window.debug = {
log: __no_op,
error: __no_op,
warn: __no_op,
info: __no_op
}
}
}
setDebug(true);
// ...
debug.log('wat', 'Yay custom levels.'); // -> wat: Yay custom levels. (line X)
debug.info('This is info.'); // -> info: This is info. (line Y)
debug.error('Bad stuff happened.'); // -> error: Bad stuff happened. (line Z)
Мне понравился ответ @fredrik, поэтому я свел его с другим ответом, который разделяет трассировку стека Webkit, и объединил его с безопасной оболочкой @PaulIrish console.log. "Стандартизирует" filename:line
для "специального объекта", поэтому он выделяется и выглядит в основном одинаково в FF и Chrome.
Тестирование в скрипке: http://jsfiddle.net/drzaus/pWe6W/
_log = (function (undefined) {
var Log = Error; // does this do anything? proper inheritance...?
Log.prototype.write = function (args) {
/// <summary>
/// Paulirish-like console.log wrapper. Includes stack trace via @fredrik SO suggestion (see remarks for sources).
/// </summary>
/// <param name="args" type="Array">list of details to log, as provided by `arguments`</param>
/// <remarks>Includes line numbers by calling Error object -- see
/// * http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
/// * https://stackru.com/questions/13815640/a-proper-wrapper-for-console-log-with-correct-line-number
/// * https://stackru.com/a/3806596/1037948
/// </remarks>
// via @fredrik SO trace suggestion; wrapping in special construct so it stands out
var suffix = {
"@": (this.lineNumber
? this.fileName + ':' + this.lineNumber + ":1" // add arbitrary column value for chrome linking
: extractLineNumberFromStack(this.stack)
)
};
args = args.concat([suffix]);
// via @paulirish console wrapper
if (console && console.log) {
if (console.log.apply) { console.log.apply(console, args); } else { console.log(args); } // nicer display in some browsers
}
};
var extractLineNumberFromStack = function (stack) {
/// <summary>
/// Get the line/filename detail from a Webkit stack trace. See https://stackru.com/a/3806596/1037948
/// </summary>
/// <param name="stack" type="String">the stack string</param>
if(!stack) return '?'; // fix undefined issue reported by @sigod
// correct line number according to how Log().write implemented
var line = stack.split('\n')[2];
// fix for various display text
line = (line.indexOf(' (') >= 0
? line.split(' (')[1].substring(0, line.length - 1)
: line.split('at ')[1]
);
return line;
};
return function (params) {
/// <summary>
/// Paulirish-like console.log wrapper
/// </summary>
/// <param name="params" type="[...]">list your logging parameters</param>
// only if explicitly true somewhere
if (typeof DEBUGMODE === typeof undefined || !DEBUGMODE) return;
// call handler extension which provides stack trace
Log().write(Array.prototype.slice.call(arguments, 0)); // turn into proper array
};//-- fn returned
})();//--- _log
Это также работает в узле, и вы можете проверить это с:
// no debug mode
_log('this should not appear');
// turn it on
DEBUGMODE = true;
_log('you should', 'see this', {a:1, b:2, c:3});
console.log('--- regular log ---');
_log('you should', 'also see this', {a:4, b:8, c:16});
// turn it off
DEBUGMODE = false;
_log('disabled, should not appear');
console.log('--- regular log2 ---');
Я нашел простое решение, чтобы объединить принятый ответ (привязка к console.log/error/etc) с некоторой внешней логикой, чтобы отфильтровать то, что фактически зарегистрировано.
// or window.log = {...}
var log = {
ASSERT: 1, ERROR: 2, WARN: 3, INFO: 4, DEBUG: 5, VERBOSE: 6,
set level(level) {
if (level >= this.ASSERT) this.a = console.assert.bind(window.console);
else this.a = function() {};
if (level >= this.ERROR) this.e = console.error.bind(window.console);
else this.e = function() {};
if (level >= this.WARN) this.w = console.warn.bind(window.console);
else this.w = function() {};
if (level >= this.INFO) this.i = console.info.bind(window.console);
else this.i = function() {};
if (level >= this.DEBUG) this.d = console.debug.bind(window.console);
else this.d = function() {};
if (level >= this.VERBOSE) this.v = console.log.bind(window.console);
else this.v = function() {};
this.loggingLevel = level;
},
get level() { return this.loggingLevel; }
};
log.level = log.DEBUG;
Использование:
log.e('Error doing the thing!', e); // console.error
log.w('Bonus feature failed to load.'); // console.warn
log.i('Signed in.'); // console.info
log.d('Is this working as expected?'); // console.debug
log.v('Old debug messages, output dominating messages'); // console.log; ignored because `log.level` is set to `DEBUG`
log.a(someVar == 2) // console.assert
- Обратите внимание, что
console.assert
использует условное ведение журнала. - Убедитесь, что инструменты разработчика вашего браузера показывают все уровни сообщений!
Год 2021
Послушай, Макфлай, это единственное, что у меня сработало:
let debug = true;
Object.defineProperty(this, "log", {get: function () {
return debug ? console.log.bind(window.console, '['+Date.now()+']', '[DEBUG]')
: function(){};}
});
// usage:
log('Back to the future');
// outputs:
[1624398754679] [DEBUG] Back to the future
Красота заключается в том, чтобы избежать вызова другой функции, например
log('xyz')()
или создать объект-оболочку или даже класс. Это также безопасно для ES5.
Если вам не нужен префикс, просто удалите параметр.
update включал текущую метку времени для префикса каждого вывода журнала.
Chrome Devtools позволяет вам достичь этого с помощью Blackboxing. Вы можете создать оболочку console.log, которая может иметь побочные эффекты, вызывать другие функции и т. Д., И при этом сохранить номер строки, вызвавшей функцию оболочки.
Просто поместите небольшую оболочку console.log в отдельный файл, например
(function() {
var consolelog = console.log
console.log = function() {
// you may do something with side effects here.
// log to a remote server, whatever you want. here
// for example we append the log message to the DOM
var p = document.createElement('p')
var args = Array.prototype.slice.apply(arguments)
p.innerText = JSON.stringify(args)
document.body.appendChild(p)
// call the original console.log function
consolelog.apply(console,arguments)
}
})()
Назовите это что-то вроде log-blackbox.js
Затем перейдите в настройки Chrome Devtools и найдите раздел "Blackboxing", добавьте шаблон для имени файла, который вы хотите добавить в черный ящик, в данном случае log-blackbox.js
От: Как получить номер строки функции вызывающего JavaScript? Как получить исходный URL звонящего из JavaScript? Error
Объект имеет свойство номера строки (в FF). Так что-то вроде этого должно работать:
var err = new Error();
Global.console.log(level + ': '+ msg + 'file: ' + err.fileName + ' line:' + err.lineNumber);
В браузере Webkit у вас есть err.stack
это строка, представляющая текущий стек вызовов. Он будет отображать текущий номер строки и дополнительную информацию.
ОБНОВИТЬ
Чтобы получить правильный номер белья, вам нужно вызвать ошибку в этой строке. Что-то вроде:
var Log = Error;
Log.prototype.write = function () {
var args = Array.prototype.slice.call(arguments, 0),
suffix = this.lineNumber ? 'line: ' + this.lineNumber : 'stack: ' + this.stack;
console.log.apply(console, args.concat([suffix]));
};
var a = Log().write('monkey' + 1, 'test: ' + 2);
var b = Log().write('hello' + 3, 'test: ' + 4);
Способ сохранить номер строки здесь: https://gist.github.com/bgrins/5108712. Это более или менее сводится к этому:
if (Function.prototype.bind) {
window.log = Function.prototype.bind.call(console.log, console);
}
else {
window.log = function() {
Function.prototype.apply.call(console.log, console, arguments);
};
}
Вы могли бы обернуть это с isDebug
и установить window.log
в function() { }
если вы не отлаживаете.
Вы можете передать номер строки в ваш метод отладки, например так:
//main.js
debug('Here is a msg.', (new Error).lineNumber);
Вот, (new Error).lineNumber
даст вам текущий номер строки в вашем javascript
код.
Решения трассировки стека отображают номер строки, но не позволяют щелкнуть, чтобы перейти к источнику, что является серьезной проблемой. Единственное решение для сохранения этого поведения - это привязка к исходной функции.
Привязка препятствует включению промежуточной логики, потому что эта логика будет портить номера строк. Однако, переопределяя связанные функции и играя с подстановкой консольной строки, некоторое дополнительное поведение все еще возможно.
В этом гистограмме показана минималистичная структура ведения журнала, которая предлагает модули, уровни ведения журнала, форматирование и правильные номера строк, которые можно активировать нажатием, в 34 строках. Используйте это как основу или вдохновение для своих собственных нужд.
var log = Logger.get("module").level(Logger.WARN);
log.error("An error has occured", errorObject);
log("Always show this.");
Если вы просто хотите контролировать, используется ли отладка, и правильно ли указан номер строки, вы можете сделать это вместо этого:
if(isDebug && window.console && console.log && console.warn && console.error){
window.debug = {
'log': window.console.log,
'warn': window.console.warn,
'error': window.console.error
};
}else{
window.debug = {
'log': function(){},
'warn': function(){},
'error': function(){}
};
}
Когда вам нужен доступ к отладке, вы можете сделать это:
debug.log("log");
debug.warn("warn");
debug.error("error");
Если isDebug == true
, Номера строк и имена файлов, показанные в консоли, будут правильными, потому что debug.log
и т.д. на самом деле псевдоним console.log
и т.п.
Если isDebug == false
Отладочные сообщения не отображаются, потому что debug.log
и т.д. просто ничего не делает (пустая функция).
Как вы уже знаете, функция-обертка будет портить номера строк и имена файлов, поэтому рекомендуется не использовать функции-обертки.
Вот способ сохранить ваши существующие console
регистрация операторов при добавлении имени файла и номера строки или другой информации трассировки стека на вывод:
(function () {
'use strict';
var isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
var isChrome = !!window.chrome && !!window.chrome.webstore;
var isIE = /*@cc_on!@*/false || !!document.documentMode;
var isEdge = !isIE && !!window.StyleMedia;
var isPhantom = (/PhantomJS/).test(navigator.userAgent);
Object.defineProperties(console, ['log', 'info', 'warn', 'error'].reduce(function (props, method) {
var _consoleMethod = console[method].bind(console);
props[method] = {
value: function MyError () {
var stackPos = isOpera || isChrome ? 2 : 1;
var err = new Error();
if (isIE || isEdge || isPhantom) { // Untested in Edge
try { // Stack not yet defined until thrown per https://docs.microsoft.com/en-us/scripting/javascript/reference/stack-property-error-javascript
throw err;
} catch (e) {
err = e;
}
stackPos = isPhantom ? 1 : 2;
}
var a = arguments;
if (err.stack) {
var st = err.stack.split('\n')[stackPos]; // We could utilize the whole stack after the 0th index
var argEnd = a.length - 1;
[].slice.call(a).reverse().some(function(arg, i) {
var pos = argEnd - i;
if (typeof a[pos] !== 'string') {
return false;
}
if (typeof a[0] === 'string' && a[0].indexOf('%') > -1) { pos = 0 } // If formatting
a[pos] += ' \u00a0 (' + st.slice(0, st.lastIndexOf(':')) // Strip out character count
.slice(st.lastIndexOf('/') + 1) + ')'; // Leave only path and line (which also avoids ":" changing Safari console formatting)
return true;
});
}
return _consoleMethod.apply(null, a);
}
};
return props;
}, {}));
}());
Тогда используйте это так:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="console-log.js"></script>
</head>
<body>
<script>
function a () {
console.log('xyz'); // xyz (console-log.html:10)
}
console.info('abc'); // abc (console-log.html:12)
console.log('%cdef', "color:red;"); // (IN RED:) // def (console-log.html:13)
a();
console.warn('uuu'); // uuu (console-log.html:15)
console.error('yyy'); // yyy (console-log.html:16)
</script>
</body>
</html>
Это работает в Firefox, Opera, Safari, Chrome и IE 10 (еще не протестировано на IE11 или Edge).
Идея с привязкой Function.prototype.bind
блестящий Вы также можете использовать библиотеку строк-журнала npm. Он показывает исходные файлы:
Создайте регистратор кто-нибудь один раз в вашем проекте:
var LoggerFactory = require('lines-logger').LoggerFactory;
var loggerFactory = new LoggerFactory();
var logger = loggerFactory.getLoggerColor('global', '#753e01');
Печать журналов:
logger.log('Hello world!')();
С современным javascript и использованием геттеров вы можете написать что-то вроде этого:
window.Logger = {
debugMode: true,
get info() {
if ( window.Logger.debugMode ) {
return window.console.info.bind( window.console );
} else {
return () => {};
}
}
}
Приятная часть этого заключается в том, что вы можете распечатать как статические, так и вычисленные значения вместе с правильными номерами строк. Вы даже можете определить несколько регистраторов с разными настройками:
class LoggerClz {
name = null;
debugMode = true;
constructor( name ) { this.name = name; }
get info() {
if ( this.debugMode ) {
return window.console.info.bind( window.console, 'INFO', new Date().getTime(), this.name );
} else {
return () => {};
}
}
}
const Logger1 = new LoggerClz( 'foo' );
const Logger2 = new LoggerClz( 'bar' );
function test() {
Logger1.info( '123' ); // INFO 1644750929128 foo 123 [script.js:18]
Logger2.info( '456' ); // INFO 1644750929128 bar 456 [script.js:19]
}
test();
Вы можете использовать дополнительную цепочку , чтобы действительно упростить это. Вы получаете полный доступ к объекту консоли без хаков и лаконичного синтаксиса.
Небольшое изменение состоит в том, чтобы debug() возвращал функцию, которая затем выполняется там, где вам это нужно - debug(message)(); и поэтому правильно показывает правильный номер строки и вызывающий скрипт в окне консоли, допуская такие варианты, как перенаправление в виде предупреждения или сохранение в файл.
var debugmode='console';
var debugloglevel=3;
function debug(msg, type, level) {
if(level && level>=debugloglevel) {
return(function() {});
}
switch(debugmode) {
case 'alert':
return(alert.bind(window, type+": "+msg));
break;
case 'console':
return(console.log.bind(window.console, type+": "+msg));
break;
default:
return (function() {});
}
}
Поскольку он возвращает функцию, эту функцию необходимо выполнить в строке отладки с помощью ();. Во-вторых, сообщение отправляется в функцию отладки, а не в возвращаемую функцию, позволяющую выполнить предварительную обработку или проверку, которая может вам понадобиться, например, проверить состояние уровня журнала, сделать сообщение более читабельным, пропустить различные типы или только элементы отчетов. соответствие критериям уровня журнала;
debug(message, "serious", 1)();
debug(message, "minor", 4)();
Я сам в последнее время смотрю на эту проблему. Нужно было что-то очень прямое для управления регистрацией, но также для сохранения номеров строк. Мое решение не выглядит элегантно в коде, но предоставляет то, что мне нужно. Если вы достаточно осторожны с замыканиями и удержанием.
Я добавил небольшую оболочку в начало приложения:
window.log = {
log_level: 5,
d: function (level, cb) {
if (level < this.log_level) {
cb();
}
}
};
Так что позже я могу просто сделать:
log.d(3, function(){console.log("file loaded: utils.js");});
Я протестировал Firefox и Crome, и оба браузера, похоже, отображают консольный журнал, как и предполагалось. Если вы заполняете таким образом, вы всегда можете расширить метод 'd' и передать ему другие параметры, чтобы он мог выполнять некоторые дополнительные записи.
Пока еще не нашли серьезных недостатков для моего подхода, кроме уродливой строки в коде для регистрации.
Вы могли бы упростить логику здесь. Это предполагает, что ваш глобальный флаг отладки НЕ является динамическим и устанавливается при загрузке приложения или передается в виде некоторой конфигурации. Это предназначено для использования для маркировки среды (например, печать только в режиме разработки, а не в производстве)
Ваниль JS:
(function(window){
var Logger = {},
noop = function(){};
['log', 'debug', 'info', 'warn', 'error'].forEach(function(level){
Logger[level] = window.isDebug ? window.console[level] : noop;
});
window.Logger = Logger;
})(this);
ES6:
((window) => {
const Logger = {};
const noop = function(){};
['log', 'debug', 'info', 'warn', 'error'].forEach((level) => {
Logger[level] = window.isDebug ? window.console[level] : noop;
});
window.Logger = Logger;
})(this);
Модуль:
const Logger = {};
const noop = function(){};
['log', 'debug', 'info', 'warn', 'error'].forEach((level) => {
Logger[level] = window.isDebug ? window.console[level] : noop;
});
export default Logger;
Угловой 1.x:
angular
.module('logger', [])
.factory('Logger', ['$window',
function Logger($window) {
const noop = function(){};
const logger = {};
['log', 'debug', 'info', 'warn', 'error'].forEach((level) => {
logger[level] = $window.isDebug ? $window.console[level] : noop;
});
return logger;
}
]);
Все, что вам нужно сделать сейчас, это заменить все ссылки на консоли на Logger
Вот моя функция регистратора (на основе некоторых ответов). Надеюсь, кто-то сможет это использовать:
const DEBUG = true;
let log = function ( lvl, msg, fun ) {};
if ( DEBUG === true ) {
log = function ( lvl, msg, fun ) {
const d = new Date();
const timestamp = '[' + d.getHours() + ':' + d.getMinutes() + ':' +
d.getSeconds() + '.' + d.getMilliseconds() + ']';
let stackEntry = new Error().stack.split( '\n' )[2];
if ( stackEntry === 'undefined' || stackEntry === null ) {
stackEntry = new Error().stack.split( '\n' )[1];
}
if ( typeof fun === 'undefined' || fun === null ) {
fun = stackEntry.substring( stackEntry.indexOf( 'at' ) + 3,
stackEntry.lastIndexOf( ' ' ) );
if ( fun === 'undefined' || fun === null || fun.length <= 1 ) {
fun = 'anonymous';
}
}
const idx = stackEntry.lastIndexOf( '/' );
let file;
if ( idx !== -1 ) {
file = stackEntry.substring( idx + 1, stackEntry.length - 1 );
} else {
file = stackEntry.substring( stackEntry.lastIndexOf( '\\' ) + 1,
stackEntry.length - 1 );
}
if ( file === 'undefined' || file === null ) {
file = '<>';
}
const m = timestamp + ' ' + file + '::' + fun + '(): ' + msg;
switch ( lvl ) {
case 'log': console.log( m ); break;
case 'debug': console.log( m ); break;
case 'info': console.info( m ); break;
case 'warn': console.warn( m ); break;
case 'err': console.error( m ); break;
default: console.log( m ); break;
}
};
}
Примеры:
log( 'warn', 'log message', 'my_function' );
log( 'info', 'log message' );
window.line = function () {
var error = new Error(''),
brower = {
ie: !-[1,], // !!window.ActiveXObject || "ActiveXObject" in window
opera: ~window.navigator.userAgent.indexOf("Opera"),
firefox: ~window.navigator.userAgent.indexOf("Firefox"),
chrome: ~window.navigator.userAgent.indexOf("Chrome"),
safari: ~window.navigator.userAgent.indexOf("Safari"), // /^((?!chrome).)*safari/i.test(navigator.userAgent)?
},
todo = function () {
// TODO:
console.error('a new island was found, please told the line()\'s author(roastwind)');
},
line = (function(error, origin){
// line, column, sourceURL
if(error.stack){
var line,
baseStr = '',
stacks = error.stack.split('\n');
stackLength = stacks.length,
isSupport = false;
// mac版本chrome(55.0.2883.95 (64-bit))
if(stackLength == 11 || brower.chrome){
line = stacks[3];
isSupport = true;
// mac版本safari(10.0.1 (12602.2.14.0.7))
}else if(brower.safari){
line = stacks[2];
isSupport = true;
}else{
todo();
}
if(isSupport){
line = ~line.indexOf(origin) ? line.replace(origin, '') : line;
line = ~line.indexOf('/') ? line.substring(line.indexOf('/')+1, line.lastIndexOf(':')) : line;
}
return line;
}else{
todo();
}
return '';
})(error, window.location.origin);
return line;
}
window.log = function () {
var _line = window.line.apply(arguments.callee.caller),
args = Array.prototype.slice.call(arguments, 0).concat(['\t\t\t@'+_line]);
window.console.log.apply(window.console, args);
}
log('hello');
здесь было мое решение по этому вопросу. когда вы вызываете метод: log, он напечатает номер строки, где вы печатаете свой журнал
Эта реализация основана на выбранном ответе и помогает уменьшить количество шума в консоли ошибок: /questions/33388224/pravilnaya-obertka-dlya-consolelog-s-pravilnyim-nomerom-stroki/33388236#33388236
var Logging = Logging || {};
const LOG_LEVEL_ERROR = 0,
LOG_LEVEL_WARNING = 1,
LOG_LEVEL_INFO = 2,
LOG_LEVEL_DEBUG = 3;
Logging.setLogLevel = function (level) {
const NOOP = function () { }
Logging.logLevel = level;
Logging.debug = (Logging.logLevel >= LOG_LEVEL_DEBUG) ? console.log.bind(window.console) : NOOP;
Logging.info = (Logging.logLevel >= LOG_LEVEL_INFO) ? console.log.bind(window.console) : NOOP;
Logging.warning = (Logging.logLevel >= LOG_LEVEL_WARNING) ? console.log.bind(window.console) : NOOP;
Logging.error = (Logging.logLevel >= LOG_LEVEL_ERROR) ? console.log.bind(window.console) : NOOP;
}
Logging.setLogLevel(LOG_LEVEL_INFO);
Код от http://www.briangrinstead.com/blog/console-log-helper-function:
// Full version of `log` that:
// * Prevents errors on console methods when no console present.
// * Exposes a global 'log' function that preserves line numbering and formatting.
(function () {
var method;
var noop = function () { };
var methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
'timeStamp', 'trace', 'warn'
];
var length = methods.length;
var console = (window.console = window.console || {});
while (length--) {
method = methods[length];
// Only stub undefined methods.
if (!console[method]) {
console[method] = noop;
}
}
if (Function.prototype.bind) {
window.log = Function.prototype.bind.call(console.log, console);
}
else {
window.log = function() {
Function.prototype.apply.call(console.log, console, arguments);
};
}
})();
var a = {b:1};
var d = "test";
log(a, d);
//isDebug controls the entire site.
var isDebug = true;
//debug.js
function debug(msg, level){
var Global = this;
if(!(Global.isDebug && Global.console && Global.console.log)){
return;
}
level = level||'info';
return 'console.log(\'' + level + ': '+ JSON.stringify(msg) + '\')';
}
//main.js
eval(debug('Here is a msg.'));
Это даст мне info: "Here is a msg." main.js(line:2)
,
Но дополнительный eval
нужно, жалко.
Для регистратора консоли Angular/Typescript с правильным номером строки вы можете сделать следующее:
пример файла : console-logger.ts
export class Log {
static green(title: string): (...args: any) => void {
return console.log.bind(console, `%c${title}`, `background: #222; color: #31A821`);
}
static red(title: string): (...args: any) => void {
return console.log.bind(console, `%c${title}`, `background: #222; color: #DA5555`);
}
static blue(title: string): (...args: any) => void {
return console.log.bind(console, `%c${title}`, `background: #222; color: #5560DA`);
}
static purple(title: string): (...args: any) => void {
return console.log.bind(console, `%c${title}`, `background: #222; color: #A955DA`);
}
static yellow(title: string): (...args: any) => void {
return console.log.bind(console, `%c${title}`, `background: #222; color: #EFEC47`);
}
}
Затем вызовите его из любого другого файла:
пример файла: auth.service.ts
import { Log } from 'path to console-logger.ts';
const user = { user: '123' }; // mock data
Log.green('EXAMPLE')();
Log.red('EXAMPLE')(user);
Log.blue('EXAMPLE')(user);
Log.purple('EXAMPLE')(user);
Log.yellow('EXAMPLE')(user);
Старый вопрос, я знаю, но я уже некоторое время работаю над своим собственным решением для этого. Возвращаюсь, чтобы посмотреть, нет ли новой информации. Поскольку не похоже, что кто-то подошел намного ближе, я подумал, что брошу свое решение в отжиматель (поскольку это, похоже, все еще самая активная тема по этому вопросу):
https://github.com/fatlard1993/log
Сначала я использовал аналогичный подход к некоторым другим ответам здесь, пока не узнал о прокси. Это дало мне идею и мотивацию воплотить ее в жизнь.
Основываясь на других ответах (в основном @arctelix one), я создал это для Node ES6, но быстрый тест показал хорошие результаты и в браузере. Я просто передаю другую функцию в качестве справки.
let debug = () => {};
if (process.argv.includes('-v')) {
debug = console.log;
// debug = console; // For full object access
}
Я решил это путем создания объекта, а затем создания нового свойства объекта с помощью Object.defineProperty() и возврата свойства console, которое затем использовалось как обычная функция, но теперь с расширенной способностью.
var c = {};
var debugMode = true;
var createConsoleFunction = function(property) {
Object.defineProperty(c, property, {
get: function() {
if(debugMode)
return console[property];
else
return function() {};
}
});
};
Затем, чтобы определить свойство, которое вы просто делаете...
createConsoleFunction("warn");
createConsoleFunction("log");
createConsoleFunction("trace");
createConsoleFunction("clear");
createConsoleFunction("error");
createConsoleFunction("info");
И теперь вы можете использовать свою функцию так же, как
c.error("Error!");
Я нашел некоторые ответы на эту проблему слишком сложными для моих нужд. Вот простое решение, представленное в Coffeescript. Это адаптировано из версии Брайана Гринстеда здесь
Предполагается глобальный консольный объект.
# exposes a global 'log' function that preserves line numbering and formatting.
(() ->
methods = [
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
'timeStamp', 'trace', 'warn']
noop = () ->
# stub undefined methods.
for m in methods when !console[m]
console[m] = noop
if Function.prototype.bind?
window.log = Function.prototype.bind.call(console.log, console);
else
window.log = () ->
Function.prototype.apply.call(console.log, console, arguments)
)()
Это то, что сработало для меня. Он создает новый объект со всеми функциями исходного объекта консоли и сохраняет объект консоли.
let debugOn=true; // we can set this from the console or from a query parameter, for example (&debugOn=true)
const noop = () => { }; // dummy function.
const debug = Object.create(console); // creates a deep copy of the console object. This retains the console object so we can use it when we need to and our new debug object has all the properties and methods of the console object.
let quiet = false;
debug.log = (debugOn) ? debug.log : noop;
if (debugOn&&quiet) {
debug.info = noop;
debug.warn = noop;
debug.assert = noop;
debug.error = noop;
debug.debug = noop;
}
console.log(`we should see this with debug off or on`);
debug.log(`we should not see this with debugOn=false`);
Ничто здесь действительно не имело того, что мне нужно, поэтому я добавляю свой собственный подход: переопределение консоли и чтение исходной строки ошибки из синтетическогоError
. В этом примере консольные предупреждения и ошибки сохраняются вconsole.appTrace
, имеющие ошибки очень подробно и многословно; так просто (console.appTrace.join("")
говорит мне все, что мне нужно от сеанса пользователя.
Обратите внимание, что на данный момент это работает только в Chrome.
(function () {
window.console.appTrace = [];
const defaultError = console.error;
const timestamp = () => {
let ts = new Date(), pad = "000", ms = ts.getMilliseconds().toString();
return ts.toLocaleTimeString("cs-CZ") + "." + pad.substring(0, pad.length - ms.length) + ms + " ";
};
window.console.error = function () {
window.console.appTrace.push("ERROR ",
(new Error().stack.split("at ")[1]).trim(), " ",
timestamp(), ...arguments, "\n");
defaultError.apply(window.console, arguments);
};
const defaultWarn = console.warn;
window.console.warn = function () {
window.console.appTrace.push("WARN ", ...arguments, "\n");
defaultWarn.apply(window.console, arguments);
};
})();
вдохновлено получением имени и строки вызывающей функции в node.js и подходом к форматированию даты в этом потоке.