如何根据特定 javascript 源(方法、文件)或消息内容的条件禁用 console.log 消息

2024-01-14

我正在开发一个使用相当多的 js 库的项目,其中一个库向控制台输出大量数据,它对电波的污染非常严重,以至于很难调试......

我知道如何禁用日志记录 https://stackoverflow.com/questions/1215392/how-to-quickly-and-conveniently-disable-all-console-log-statements-in-my-code完全通过覆盖console.log有了这个,

(function (original) {
    console.enableLogging = function () {
        console.log = original;
    };
    console.disableLogging = function () {
        console.log = function () {};
    };
})(console.log);

but 它是如何根据消息来源(文件/url)来做到这一点的?


Preamble

一开始讨论了事物的一般工作原理。如果您只关心代码,请跳过介绍并滚动到Solution标题。

介绍

Problem:

Web 应用程序中有很多控制台噪音。大量噪音来自我们无法访问的第三方代码。一些日志噪音也可能来自我们的代码。

要求:

通过停止日志来减少噪音。Some日志仍应保留,并且有关这些日志的决策应与执行日志记录的代码分离。所需的粒度是“每个文件”。我们应该能够选择哪些文件添加或不添加日志消息。最后,这将not在生产代码中使用。

假设:这将在开发人员控制的浏览器中运行。在这种情况下,我不会关注向后兼容性。

之前的工作:

可以使用此全局启用/禁用首次日志记录

(function (original) {
    console.enableLogging = function () {
        console.log = original;
    };
    console.disableLogging = function () {
        console.log = function () {};
    };
})(console.log);

(问题中发布的代码,但也在这里供参考)

  • 然而,这不允许任何粒度。
  • 这可以修改为仅适用于特定模块,但不能用于第三方代码。
  • 一种混合方法是全局禁用日志记录,但在每个模块中启用它。问题是我们必须修改each我们的文件,我们将不会收到一些可能有用的外部消息。

可以使用日志框架,但它可能有点过头了。虽然说实话,我认为这就是我想要的,但它可能需要一些集成到产品中。

因此,我们需要一些轻量级的东西,具有一定的配置,并且不需要很漂亮。

提议:

The 登录器(标题可能会更改)

让我们从基础开始 - 我们已经知道我们可以覆盖全局日志函数。我们将接受并与之合作。但首先,让我们认识到console对象支持的不仅仅是.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并且可以停止所有日志记录。事实上,console.error可能应该留下来console.warn可能也有用。但这并不是万能的解决方案。

接下来,由于我们can覆盖控制台功能...为什么不提供我们自己的?

自定义日志记录

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.");

这就是我们推出自己的迷你日志框架所需的所有工具。

如何进行选择性日志记录

唯一缺少的是确定某些内容来自哪个文件。我们只需要堆栈跟踪 https://davidwalsh.name/javascript-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 中使用。另外,来吧 - 这实际上是一行 - 我们想要简单,不介意肮脏,所以我很高兴做出这样的权衡。

Solution

把它们放在一起。Warning:不要在生产中使用它

(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"])

所以,这是一个自定义记录器。当然,这不是perfect但它会完成这项工作。而且,嘿,由于白名单有点宽松,它可以变成一个优势:

  • 将一堆共享子字符串的文件列入白名单,例如所有myApp可以包括myApp1.js, myApp2.js, and myApp3.js.
  • 不过,如果您想要特定文件,您可以只传递全名,包括扩展名。我怀疑会有一堆重复的文件名。
  • 最后,堆栈跟踪将包括调用函数的名称(如果有),因此您实际上可以直接传递该名称,并且它将根据每个函数将其列入白名单。但是,它依赖于具有名称的函数,并且函数名称更容易发生冲突,因此请谨慎使用

除此之外,当然可以有改进,但这是它的基础。这info/warn例如,方法也可以被重写。

因此,如果使用的话,应该只在开发版本中使用。有很多方法可以让它不投入生产,所以我不会讨论它们,但我可以提到一件事:你也可以使用这个anywhere如果您将其另存为小书签

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 文件之前仅在开发/调试版本中.

请注意 - 这适用于 Chrome、Edge 和 Firefox。它们都是最新的浏览器,因此我假设开发人员至少会使用其中一种。该问题被标记为 Chrome,但我决定扩大支持范围。仅限 Chrome 的解决方案could工作稍微好一些,但这并不是真正的功能损失。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何根据特定 javascript 源(方法、文件)或消息内容的条件禁用 console.log 消息 的相关文章

  • 主干关系事件未触发?

    class TheModel extends Backbone RelationalModel relations type Backbone HasMany key subModels relatedModel SubModel coll
  • ReferenceError:找不到变量:需要

    我在加载时遇到问题node modules到我的网页之一 我已经安装了 npm node js 并且我想使用require 函数在我的网站上初始化 Firebase 我不知道为什么 但它抛出引用错误 ReferenceError 找不到变量
  • 无法显示由 Fine-uploader 上传到 Amazon s3 的图像

    我现在尝试设置fineuploader s3以显示在aws服务器上成功上传的文件的图像 如示例页面上所做的那样 http fineuploader com s3 demo http fineuploader com s3 demo 我 仍然
  • HTMLImageElement 作为 React Child 无效

    我正在尝试异步加载图像 并且仅在加载图像后才将其显示在 React 应用程序中 componentDidMount const img new Image img onload gt this setState originalImage
  • 使用selenium IDE提取部分文本并将其放入变量中

    有人可以告诉我应该使用哪个命令来使用 Selenium Ide 从文本中仅提取数字 694575 并将其放入变量中以供进一步使用 这是带有文本的 div div class loginBoxTitle Edit Exhibition Cen
  • 如何向 jQuery Tokeninput 添加占位符?

    如何将占位符添加到 jQuery Tokeninput 字段 一个正常的placeholder属性在这里不起作用 对于这样的输入
  • 如何通过 HTML 按钮播放声音

    我目前通过网站播放音乐的方法是通过 HTML 音频标签 不过我希望能够通过 HTML 按钮来播放它 该按钮应该能够在播放和停止之间切换音乐 我在 JSFiddle 创建了一个示例 但不知道如何实现它 有人可以告诉我如何使用我的 JSFidd
  • 在 BIRT 中输入参数后更新数据集查询

    在 BIRT 报告设计中传递参数后 如何更改或更新数据集的查询 详细说明 我有一个如下所示的查询 WHERE 该参数标记可以保存不同的值 在用户输入参数后 它看起来像这样 例如 WHERE column name 1 or WHERE co
  • Flask wtf.quick_form 运行一些 javascript 并设置表单变量

    我正在创建博客文章 到目前为止已经使用普通的 html 表单完成了 我所做的一个有趣的想法是运行 javascript onclick 并使用页面中的额外数据在表单中设置一个隐藏变量 这很好地传递到服务器并通过 request form 获
  • 将音频与视频流合并 Node.js

    我正在创建 YouTube 视频下载器并且正在使用ytdl core库 它无法下载带有音频的高质量视频 因为 youtube 将其放在另一个文件中 但我需要将其全部下载到一个文件中 我已经这样做了 app get download asyn
  • 使用模态表单 ajax 超出 HTMLFormElement.toString 的最大调用堆栈大小

    我想使用模态窗口中的 ajax 请求提交表单 单击此链接可打开该模式 a class btn btn primary i class fa fa edit i Write a review a 模态窗口 div class modal fa
  • 在 MVC Razor 中的 C# 和 Javascript 之间共享常量

    我想在服务器上的 C 和客户端上的 Javascript 中都使用字符串常量 我将常量封装在 C 类中 namespace MyModel public static class Constants public const string
  • 如何使用 jQuery 向表中添加新行,并为其分配递增的 id

    我有一个现有的 HTML 表格 它是用户输入 GPS 点的表单的一部分 用户还可以选择上传 GPS 数据点 我想要一个用户可以按下的按钮 其中一些 Javascript 会向表中添加一个或多个新行 但新行必须继续增加表中使用的名称和 id
  • 如何改变HTML5视频的播放速度?

    如何更改 HTML5 中的视频播放速度 我查过视频标签的属性 https www w3schools com html html5 video asp在 w3school 但无法做到这一点 根据这个网站 http www chipwreck
  • 用数组反向查找对象

    假设我有一个这样的对象 resourceMap a 0 1 2 3 4 5 6 7 8 9 10 b 11 12 c 21 23 d 54 55 56 57 510 确定是否的最佳方法是什么resourceId 21将会 c 我们不知道钥匙
  • jQuery 选择器:为什么 $("#id").find("p") 比 $("#id p") 更快

    该页面的作者 http 24ways org 2011 your jquery now with less suck http 24ways org 2011 your jquery now with less suck断言 jQuery
  • 选中复选框时提交表单

    有没有办法在选中复选框时提交表单
  • 如何在网页上实现文件上传进度条?

    当用户将文件上传到我的网络应用程序时 我想显示比动画 gif 更有意义的内容 我还有哪些可能性 编辑 我正在使用 Net 但我不介意是否有人向我展示与平台无关的版本 如果您对这一切在客户端通常如何工作感兴趣 就是这样 所有解决方案都通过 J
  • Jquery,清除/清空 tbody 元素的所有内容?

    我认为这会相当简单 但似乎空方法无法清除我拥有的 tbody 如果有人知道执行此操作的正确方法 我将不胜感激 我只想删除 tbody 中包含的所有内容 到目前为止我正在尝试 tbodyid empty HTML table tbody tr
  • 在javascript中动态生成行?

    我是 javascript 新手 我想在按下 Tab 时动态生成行 并希望获取在动态生成的行中输入的值 以便我可以在 servlet 代码中使用这些值 这是我的html

随机推荐