如何根据来自特定 javascript 源(方法、文件)或消息内容的条件禁用 console.log 消息
How to disable console.log messages based on criteria from specific javascript source (method, file) or message contents
我正在做的项目使用了很多 js 库,其中一个正在向控制台输出大量内容,它严重污染了电波,以至于很难调试....
I know how to disable logging 完全通过覆盖 console.log
,
(function (original) {
console.enableLogging = function () {
console.log = original;
};
console.disableLogging = function () {
console.log = function () {};
};
})(console.log);
但是 它如何根据消息来源(file/url)做到这一点?
它适用于 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。这两个文件都位于我的桌面上。
这不是很漂亮,但可以用。
在 "bad" 库的 <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")
仅供短时间调试。
前言
开头讨论了一般情况下的工作原理。如果您只关心代码,请跳过 简介 并滚动到 解决方案 标题。
简介
问题:
Web 应用程序中有很多控制台噪音。大量的噪音来自我们无法访问的第三方代码。一些日志噪音也可能来自我们的代码。
要求:
通过停止日志来减少噪音。 一些 日志仍应保留,有关这些的决定应与执行日志记录的代码分离。所需的 g运行 通用性是 "per-file"。我们应该能够选择哪些文件添加或不添加日志消息。最后,这将不会用于生产代码。
假设:这将是 运行 在开发人员控制的浏览器中。那样的话,我就不会关注向后兼容性了。
之前的工作:
首次关闭日志记录可以 enabled/disabled 全局使用此
(function (original) {
console.enableLogging = function () {
console.log = original;
};
console.disableLogging = function () {
console.log = function () {};
};
})(console.log);
(问题中贴出的代码也在这里供参考)
- 然而,这并不允许任何 g运行普遍性。
- 这可以修改为仅适用于特定模块,但不能用于第三方代码。
- 一种混合方法是全局禁用日志记录,但在我们的每个模块中启用它。问题是我们必须修改 each 我们的文件,我们不会得到一些可能有用的外部消息。
可以使用日志记录框架,但它可能有点矫枉过正。虽然,老实说,我认为这就是我想要的,但它可能需要与产品进行一些集成。
所以,我们需要一些 light-weight-ish 具有一定配置且不需要很漂亮的东西。
提案:
登录器(标题可能会更改)
让我们从基础开始——我们已经知道我们可以覆盖全局日志功能。我们会接受并使用它。但首先,让我们认识到 console
object 支持的不仅仅是 .log
。可以使用各种日志记录功能。 So-o-o,让我们将它们全部禁用。
沉默一切
//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!")
这显然可以改进,但它展示了如何停止 any 和 ll 日志记录。实际上,console.error
可能应该保留,console.warn
可能也有用。但这不是 be-all-and-end-all 解决方案。
接下来,既然我们可以覆盖控制台功能...为什么不提供我们自己的?
自定义日志记录
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.");
这就是我们推出自己的 mini-logging 框架所需的所有工具。
如何进行选择性日志记录
唯一缺少的是确定某些内容来自哪个文件。我们只需要 a stack trace.
// 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
。
- 虽然如果你想要特定的文件,你可以只传递全名,包括扩展名。我怀疑会有一堆重复的文件名。
- 最后,堆栈跟踪将包括调用函数的名称(如果有),因此您实际上只需传递它,它将在 per-function 基础上列入白名单。但是,它依赖于有名字的函数,函数名更容易发生冲突,所以谨慎使用
除此之外,当然可以改进,但这是它的基础。例如,info
/warn
方法也可以被覆盖。
所以,这个,如果使用,应该只在开发版本中。有很多方法可以让它不投入生产,所以我不会讨论它们,但我可以提一件事:如果你保存它,你也可以使用这个 anywhere作为书签t
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 文件之前 in dev/debug 仅构建 .
此处请注意 - 这将适用于 Chrome、Edge 和 Firefox。这些都是最新的浏览器,所以我假设开发人员至少会使用其中的一种。问题被标记为 Chrome 但我决定扩大支持范围。仅 Chrome 的解决方案 可以 工作得稍微好一些,但这并不是真正的功能损失。
我在最新的(2020 年 7 月)Chrome DevTools 控制台中发现这些设置很有帮助:
- 开发工具 |控制台 | (边栏图标) |用户留言
- 开发工具 |控制台 | (齿轮图标) | Select 仅上下文
- 开发工具 |控制台 | (齿轮图标) |隐藏网络
我最喜欢 (1),我只看到来自“我的”代码的消息。 (2) 隐藏来自我的 iframe 的消息。
如果它是修改文件的选项,您可以在文件顶部设置一个标志以禁用该文件的日志:
var DEBUG = false;
DEBUG && console.log("cyberpunk 2077");
要禁用所有 js 文件的日志,请将其放在任何 js 文件的顶部:
var DEBUG = false;
if (!DEBUG) {
console.log = () => {};
}
我正在做的项目使用了很多 js 库,其中一个正在向控制台输出大量内容,它严重污染了电波,以至于很难调试....
I know how to disable logging 完全通过覆盖 console.log
,
(function (original) {
console.enableLogging = function () {
console.log = original;
};
console.disableLogging = function () {
console.log = function () {};
};
})(console.log);
但是 它如何根据消息来源(file/url)做到这一点?
它适用于 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。这两个文件都位于我的桌面上。
这不是很漂亮,但可以用。
在 "bad" 库的 <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")
仅供短时间调试。
前言
开头讨论了一般情况下的工作原理。如果您只关心代码,请跳过 简介 并滚动到 解决方案 标题。
简介
问题:
Web 应用程序中有很多控制台噪音。大量的噪音来自我们无法访问的第三方代码。一些日志噪音也可能来自我们的代码。
要求:
通过停止日志来减少噪音。 一些 日志仍应保留,有关这些的决定应与执行日志记录的代码分离。所需的 g运行 通用性是 "per-file"。我们应该能够选择哪些文件添加或不添加日志消息。最后,这将不会用于生产代码。
假设:这将是 运行 在开发人员控制的浏览器中。那样的话,我就不会关注向后兼容性了。
之前的工作:
首次关闭日志记录可以 enabled/disabled 全局使用此
(function (original) {
console.enableLogging = function () {
console.log = original;
};
console.disableLogging = function () {
console.log = function () {};
};
})(console.log);
(问题中贴出的代码也在这里供参考)
- 然而,这并不允许任何 g运行普遍性。
- 这可以修改为仅适用于特定模块,但不能用于第三方代码。
- 一种混合方法是全局禁用日志记录,但在我们的每个模块中启用它。问题是我们必须修改 each 我们的文件,我们不会得到一些可能有用的外部消息。
可以使用日志记录框架,但它可能有点矫枉过正。虽然,老实说,我认为这就是我想要的,但它可能需要与产品进行一些集成。
所以,我们需要一些 light-weight-ish 具有一定配置且不需要很漂亮的东西。
提案:
登录器(标题可能会更改)
让我们从基础开始——我们已经知道我们可以覆盖全局日志功能。我们会接受并使用它。但首先,让我们认识到 console
object 支持的不仅仅是 .log
。可以使用各种日志记录功能。 So-o-o,让我们将它们全部禁用。
沉默一切
//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!")
这显然可以改进,但它展示了如何停止 any 和 ll 日志记录。实际上,console.error
可能应该保留,console.warn
可能也有用。但这不是 be-all-and-end-all 解决方案。
接下来,既然我们可以覆盖控制台功能...为什么不提供我们自己的?
自定义日志记录
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.");
这就是我们推出自己的 mini-logging 框架所需的所有工具。
如何进行选择性日志记录
唯一缺少的是确定某些内容来自哪个文件。我们只需要 a stack trace.
// 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
。 - 虽然如果你想要特定的文件,你可以只传递全名,包括扩展名。我怀疑会有一堆重复的文件名。
- 最后,堆栈跟踪将包括调用函数的名称(如果有),因此您实际上只需传递它,它将在 per-function 基础上列入白名单。但是,它依赖于有名字的函数,函数名更容易发生冲突,所以谨慎使用
除此之外,当然可以改进,但这是它的基础。例如,info
/warn
方法也可以被覆盖。
所以,这个,如果使用,应该只在开发版本中。有很多方法可以让它不投入生产,所以我不会讨论它们,但我可以提一件事:如果你保存它,你也可以使用这个 anywhere作为书签t
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 文件之前 in dev/debug 仅构建 .
此处请注意 - 这将适用于 Chrome、Edge 和 Firefox。这些都是最新的浏览器,所以我假设开发人员至少会使用其中的一种。问题被标记为 Chrome 但我决定扩大支持范围。仅 Chrome 的解决方案 可以 工作得稍微好一些,但这并不是真正的功能损失。
我在最新的(2020 年 7 月)Chrome DevTools 控制台中发现这些设置很有帮助:
- 开发工具 |控制台 | (边栏图标) |用户留言
- 开发工具 |控制台 | (齿轮图标) | Select 仅上下文
- 开发工具 |控制台 | (齿轮图标) |隐藏网络
我最喜欢 (1),我只看到来自“我的”代码的消息。 (2) 隐藏来自我的 iframe 的消息。
如果它是修改文件的选项,您可以在文件顶部设置一个标志以禁用该文件的日志:
var DEBUG = false;
DEBUG && console.log("cyberpunk 2077");
要禁用所有 js 文件的日志,请将其放在任何 js 文件的顶部:
var DEBUG = false;
if (!DEBUG) {
console.log = () => {};
}