Как отключить сообщения console.log на основе критериев из определенного источника javascript (метод, файл) или содержимого сообщения
Я работаю над проектом, который использует довольно много библиотек js, и одна из них выводит очень много в консоль, она настолько сильно загрязняет эфир, что затрудняет отладку....
Я знаю, как полностью отключить ведение журнала, переопределив console.log
с этим,
(function (original) {
console.enableLogging = function () {
console.log = original;
};
console.disableLogging = function () {
console.log = function () {};
};
})(console.log);
но как это сделать для каждого источника (файла / URL), откуда возникло сообщение?
6 ответов
преамбула
В начале обсуждается, как все работает в целом. Если вам нужен только код, пропустите Введение и перейдите к заголовку Решение.
Вступление
Проблема:
в веб-приложении много шума консоли. Значительное количество этого шума исходит от стороннего кода, к которому у нас нет доступа. Некоторый шум журнала может также исходить из нашего кода.
Требование:
уменьшить шум, остановив журнал. Некоторые журналы все еще должны храниться, и решение о них должно быть отделено от кода, который выполняет регистрацию. Необходимая гранулярность "на файл". Мы должны иметь возможность выбирать, какие файлы добавляют или не добавляют сообщения журнала. Наконец, это не будет использоваться в производственном коде.
Предположение: это будет выполняться в браузере, контролируемом разработчиком. В этом случае я не буду фокусироваться на обратной совместимости.
Предыдущая работа:
В первую очередь ведение журнала может быть включено / отключено с помощью этого
(function (original) {
console.enableLogging = function () {
console.log = original;
};
console.disableLogging = function () {
console.log = function () {};
};
})(console.log);
(код размещен в вопросе, но также здесь для справки)
- Однако это не учитывает какую-либо гранулярность.
- Это может быть изменено для работы только с определенными модулями, но это не может быть сделано для стороннего кода.
- Смешанный подход состоит в том, чтобы отключить ведение журнала глобально, но включить его в каждом из наших модулей. Проблема в том, что мы должны изменить каждый из наших файлов, и мы не получим некоторые потенциально полезные внешние сообщения.
Можно использовать каркас ведения журнала, но это может быть излишним. Хотя, если честно, я бы на это пошел, думаю, но для этого может потребоваться некоторая интеграция в продукт.
Итак, нам нужно нечто более легковесное, которое имеет некоторую конфигурацию и не должно быть симпатичным.
Предложение:
The Loginator (название может быть изменено)
Давайте начнем с основ - мы уже знаем, что можем переопределить функцию глобального журнала. Мы возьмем это и будем работать с этим. Но сначала давайте признаем, что console
объект поддерживает больше, чем просто .log
, Могут быть использованы различные функции регистрации. Итак, давайте отключим их всех.
Тишина все
//shorthand for further code.
function noop() {}
const savedFunctions = Object.keys(console)
.reduce((memo, key) => {
if(typeof console[key] == "function") {
//keep a copy just in case we need it
memo[key] = console[key];
//de-fang any functions
console[key] = noop;
}
return memo;
},
{});
console.log("Hello?");
console.info("Hello-o-o-o?");
console.warn("Can anybody hear me?");
console.error("I guess there is nobody there...");
savedFunctions.log("MUAHAHAHA!")
Это, очевидно, может быть улучшено, но оно показывает, как можно остановить любое и любое ведение журнала. В действительности, console.error
вероятно, следует оставить и console.warn
может быть также полезным. Но это не самое главное решение.
Далее, поскольку мы можем переопределить функциональность консоли... почему бы не предоставить нашу собственную?
Пользовательская регистрация
const originalLog = console.log;
console.log = function selectiveHearing() {
if (arguments[0].indexOf("die") !== -1) {
arguments[0] = "Have a nice day!";
}
return originalLog.apply(console, arguments)
}
console.log("Hello.");
console.log("My name is Inigo Montoya.");
console.log("You killed my father.");
console.log("Prepare to die.");
Это все инструменты, которые нам нужны для создания нашей собственной платформы мини-журналов.
Как сделать выборочную регистрацию
Единственное, чего не хватает, это определить, из какого файла что-то происходит. Нам просто нужен след стека.
// The magic
console.log(new Error().stack);
/* SAMPLE:
Error
at Object.module.exports.request (/home/vagrant/src/kumascript/lib/kumascript/caching.js:366:17)
at attempt (/home/vagrant/src/kumascript/lib/kumascript/loaders.js:180:24)
at ks_utils.Class.get (/home/vagrant/src/kumascript/lib/kumascript/loaders.js:194:9)
at /home/vagrant/src/kumascript/lib/kumascript/macros.js:282:24
at /home/vagrant/src/kumascript/node_modules/async/lib/async.js:118:13
at Array.forEach (native)
at _each (/home/vagrant/src/kumascript/node_modules/async/lib/async.js:39:24)
at Object.async.each (/home/vagrant/src/kumascript/node_modules/async/lib/async.js:117:9)
at ks_utils.Class.reloadTemplates (/home/vagrant/src/kumascript/lib/kumascript/macros.js:281:19)
at ks_utils.Class.process (/home/vagrant/src/kumascript/lib/kumascript/macros.js:217:15)
*/
(Соответствующий бит скопирован здесь.)
Правда, есть несколько лучших способов сделать это, но не так много. Для этого потребуется либо платформа, либо браузер - стеки ошибок официально не поддерживаются, но они работают в Chrome, Edge и Firefox. Кроме того, давай - это буквально одна строка - мы хотим простого и не возражаем против грязного, поэтому я рад за компромисс.
Решение
Собираем все вместе. Предупреждение: НЕ используйте это в производстве
(function(whitelist = [], functionsToPreserve = ["error"]) {
function noop() {}
//ensure we KNOW that there is a log function here, just in case
const savedFunctions = { log: console.log }
//proceed with nuking the rest of the chattiness away
Object.keys(console)
.reduce((memo, key) => {
if(typeof console[key] == "function" && functionsToPreserve.indexOf(key) != -1 ) {
memo[key] = console[key];
console[key] = noop;
}
return memo;
},
savedFunctions); //<- it's a const so we can't re-assign it. Besides, we don't need to, if we use it as a seed for reduce()
console.log = function customLog() {
//index 0 - the error message
//index 1 - this function
//index 2 - the calling function, i.e., the actual one that did console.log()
const callingFile = new Error().stack.split("\n")[2];
if (whitelist.some(entry => callingFile.includes(entry))) {
savedFunctions.log.apply(console, arguments)
}
}
})(["myFile.js"]) //hey, it's SOMEWHAT configurable
Или черный список
(function(blacklist = [], functionsToPreserve = ["error"]) {
function noop() {}
//ensure we KNOW that there is a log function here, just in case
const savedFunctions = {
log: console.log
}
//proceed with nuking the rest of the chattiness away
Object.keys(console)
.reduce((memo, key) => {
if (typeof console[key] == "function" && functionsToPreserve.indexOf(key) != -1) {
memo[key] = console[key];
console[key] = noop;
}
return memo;
},
savedFunctions); //<- it's a const so we can't re-assign it. Besides, we don't need to, if we use it as a seed for reduce()
console.log = function customLog() {
//index 0 - the error message
//index 1 - this function
//index 2 - the calling function, i.e., the actual one that did console.log()
const callingFile = new Error().stack.split("\n")[2];
if (blacklist.some(entry => callingFile.includes(entry))) {
return;
} else {
savedFunctions.log.apply(console, arguments);
}
}
})(["myFile.js"])
Итак, это пользовательский логгер. Конечно, это не идеально, но это сделает работу. И, эй, поскольку белый список немного свободен, его можно превратить в преимущество:
- внести в белый список группу файлов, которые разделяют подстроку, скажем, все
myApp
может включатьmyApp1.js
,myApp2.js
, а такжеmyApp3.js
, - хотя, если вам нужны конкретные файлы, вы можете просто передать полное имя, включая расширение. Я сомневаюсь, что там будет куча повторяющихся имен файлов.
- наконец, трассировка стека будет включать имя вызывающей функции, если таковая имеется, так что вы можете просто передать это, и это будет в белом списке для каждой функции. Тем не менее, он опирается на функцию, имеющую имя, и более вероятно, что имена функций конфликтуют, поэтому используйте с осторожностью
Помимо этого, безусловно, могут быть улучшения, но это основа этого. info
/ warn
методы также могут быть переопределены, например.
Таким образом, это, если используется, должно быть только в сборках dev. Есть много способов заставить его не запускаться в производство, поэтому я не буду их обсуждать, но могу упомянуть одну вещь: вы также можете использовать это где угодно, если сохраните его как букмарклет
javascript:!function(){function c(){}var a=arguments.length<=0||void 0===arguments[0]?[]:arguments[0],b=arguments.length<=1||void 0===arguments[1]?["error"]:arguments[1],d={log:console.log};Object.keys(console).reduce(function(a,d){return"function"==typeof console[d]&&b.indexOf(d)!=-1&&(a[d]=console[d],console[d]=c),a},d),console.log=function(){var c=(new Error).stack.split("\n")[2];a.some(function(a){return c.includes(a)})&&d.log.apply(console,arguments)}}(["myFile.js"]);
Это минимизировано (хотя я сначала пропустил его через Babel, чтобы использовать минификацию ES5) и все еще настраивается, в некоторой степени, так как вы можете изменить тот самый конец, где вы можете передать белый список. Но кроме этого, он будет работать так же и полностью отделен от базы кода. Он не будет работать при загрузке страницы, но если это необходимо, вы можете использовать его как пользовательский скрипт (все еще не связанный) или включить его до того, как другие файлы JS будут только в сборках dev/debug.
Примечание здесь - это будет работать в Chrome, Edge и Firefox. Это все последние браузеры, поэтому я предполагаю, что разработчик будет использовать хотя бы один из них. Вопрос помечен как Chrome, но я решил расширить поддержку. Решение только для Chrome могло бы работать немного лучше, но на самом деле это не большая потеря функциональности.
Я был так же обеспокоен, как и вы. Это мой подход. https://github.com/jchnxu/guard-с-отладкой
Простое использование:
localStorage.debug = [
'enable/console/log/in/this/file.ts',
'enable/console/log/in/this/folder/*',
'-disable/console/log/in/this/file.ts',
'-disable/console/log/in/this/folder/*',
// enable all
'*',
].join(',');
Преимущество: это нулевое время выполнения.
Отказ от ответственности: я являюсь автором этой крошечной утилиты
Это работает в Chrome:... index.html
<html>
<body>
<script>
(function(){
var original = console.log;
console.log = function(){
var script = document.currentScript;
alert(script.src);
if(script.src === 'file:///C:/Users/degr/Desktop/script.js') {
original.apply(console, arguments)
}
}
})();
console.log('this will be hidden');
</script>
<script src="script.js"></script>
</body>
</html>
... script.js
console.log('this will work');
Console.log не работает из index.html, но работает из script.js. Оба файла находятся на моем desctop.
Если есть возможность изменить файл, вы можете установить флаг в верхней части файла для отключения журналов для этого:
var DEBUG = false;
DEBUG && console.log("cyberpunk 2077");
Чтобы отключить журналы для всех файлов js, поместите его один раз в начало любого файла js:
var DEBUG = false;
if (!DEBUG) {
console.log = () => {};
}
Я обнаружил, что эти настройки в последней (июль 2020 г.) консоли Chrome DevTools могут оказаться полезными:
- DevTools | Консоль | (значок боковой панели) | сообщения пользователей
- DevTools | Консоль | (значок шестеренки) | Выбрать только контекст
- DevTools | Консоль | (значок шестеренки) | Скрыть сеть
Мне больше всего нравится (1), я вижу сообщения только из "своего" кода. (2) скрывает сообщения из моего iframe.
Это не красиво, но будет работать.
Поместите что-то вроде этого в свой файл перед <script>
тег "плохой" библиотеки:
<script>function GetFile(JSFile) {
var MReq = new XMLHttpRequest();
MReq.open('GET', JSFile, false);
MReq.send();
eval(MReq.responseText.replace(/console.log\(/g,"(function(){})("));
}</script>
Затем замените тег
<script src="badLib.js">
С:
GetFile("badLib.js")
Только для кратковременной отладки.