【问题标题】:How to disable console.log messages based on criteria from specific javascript source (method, file) or message contents如何根据来自特定 javascript 源(方法、文件)或消息内容的条件禁用 console.log 消息
【发布时间】:2017-01-30 18:55:30
【问题描述】:

我正在做一个项目,该项目使用了很多 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);

但是如何根据消息来源的来源(文件/网址)做到这一点?

【问题讨论】:

  • 我猜你需要一个解决方案,JS文件没有定义一些标准的模块或者有一个IIFE来保护全局命名空间?
  • 如何确定应该替换哪个console.log
  • 您想要外部控制(例如,使用某种配置)还是逐个文件控制(例如,在每个文件中更改)?
  • @vlaz 我无法真正更改它们从第三方加载的所有文件,但我想我可以在加载后进行调整,因为这仅适用于我调试时......如果我愿意可以访问然后只需替换 console.log -> \\console.log :)
  • 好的,所以我猜你有第三方的东西记录了你不感兴趣的信息,你想禁用它。您要禁用所有第三方日志记录还是只禁用其中一些?

标签: javascript console.log google-chrome-console


【解决方案1】:

如果是修改文件的选项,您可以在文件顶部设置一个标志来禁用日志:

var DEBUG = false;
DEBUG && console.log("cyberpunk 2077");

要禁用所有 js 文件的日志,请将其放在任何 js 文件的顶部一次:

var DEBUG = false;
if (!DEBUG) {
   console.log = () => {};
 }

【讨论】:

    【解决方案2】:

    我发现最新(2020 年 7 月)Chrome DevTools 控制台中的这些设置很有帮助:

    1. 开发工具 |控制台 | (侧边栏图标)|用户留言
    2. 开发工具 |控制台 | (齿轮图标)|仅选择上下文
    3. 开发工具 |控制台 | (齿轮图标)|隐藏网络

    我最喜欢 (1),我只看到来自“我的”代码的消息。 (2) 隐藏 iframe 中的消息。

    【讨论】:

      【解决方案3】:

      序言

      开头讨论了事物的一般运作方式。如果您只关心代码,请跳过Introduction并滚动到Solution标题。

      简介

      问题:

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

      要求:

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

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

      之前的工作:

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

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

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

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

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

      所以,我们需要一些轻量级的东西,它有一些配置并且不需要漂亮。

      建议:

      登录者(标题可能会更改)

      让我们从基础开始——我们已经知道我们可以覆盖全局日志功能。我们会接受它并与之合作。但首先,让我们认识到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 和 ll 日志记录。实际上,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.");

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

      如何进行选择性日志记录

      唯一缺少的是确定某些内容来自哪个文件。我们只需要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.jsmyApp2.jsmyApp3.js
      • 虽然如果你想要特定的文件,你可以只传递全名,包括扩展名。我怀疑会有一堆重复的文件名。
      • 最后,堆栈跟踪将包括调用函数的名称(如果有的话),因此您实际上可以直接传递它,然后将按函数列入白名单。但是,它依赖于具有名称的函数,并且函数名称更有可能发生冲突,因此请谨慎使用

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

      所以,如果使用,它应该只在开发版本中。有很多方法可以使它不投入生产,所以我不会讨论它们,但我可以提一件事:如果你将它保存为书签,你也可以在任何地方使用它

      javascript:!function(){function c(){}var a=arguments.length&lt;=0||void 0===arguments[0]?[]:arguments[0],b=arguments.length&lt;=1||void 0===arguments[1]?["error"]:arguments[1],d={log:console.log};Object.keys(console).reduce(function(a,d){return"function"==typeof console[d]&amp;&amp;b.indexOf(d)!=-1&amp;&amp;(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)})&amp;&amp;d.log.apply(console,arguments)}}(["myFile.js"]);

      这是缩小的(尽管我首先通过 Babel 传递它,使用 ES5 缩小)并且在一定程度上仍然是可配置的,因为您可以更改可以传递白名单的最后。但除此之外,它的工作原理相同,并且与代码库完全解耦。它不会在页面加载时运行,但如果需要,您可以将其用作用户脚本(仍然解耦)或在其他 JS 文件之前包含它仅在 dev/debug 构建中

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

      【讨论】:

      • 早上好 vlaz,最后一个(带有白名单文件名)没有为我飞行,但是在我的情况下,所有污染消息都有“已接收”字样,所以我修改了您的选择性听证示例 const originalLog = console.log; console.log = function selectiveHearing() { if (arguments[0].indexOf("RECEIVED:") !== -1) { return; } return originalLog.apply(console, arguments) } 和这做到了。我可以建议不要将文件列入白名单而是将它们列入黑名单以将其关闭。无论如何,谢谢这是一个很好的答案......
      • 我的错...它确实有效,必须更改此位 if (whitelist.some(entry =&gt; callingFile.includes(entry))) { return; }else{savedFunctions.log.apply(console, arguments); } 以将其用作黑名单...。
      • 是的,我加入白名单的原因是您通常不知道哪些文件会产生噪音,哪些不会,所以如果您只对某些文件感兴趣,您可以添加这些文件。当然,如果这样更有意义,您也可以将其列入黑名单。
      • Ofc 你这样做 :) i.stack.imgur.com/H5lfW.png 我现在正等着奖励你这么棒的答案......
      【解决方案4】:

      这并不漂亮,但会起作用。
      在“坏”库的 &lt;script&gt; 标记之前将这样的内容放入文件中:

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

      仅用于短时间调试。

      【讨论】:

        【解决方案5】:

        它在 chrome 中工作: ...索引.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。这两个文件都位于我的桌面上。

        【讨论】:

        • 嗨,degr,感谢您的回答,不幸的是document.currentScript; 返回null,然后在alert(script.src); 上以VM119:5 Uncaught TypeError: Cannot read property 'src' of null 失败
        • 来自here 需要注意的是,如果脚本中的代码作为回调或事件处理程序被调用,这将不会引用
        • 根据@Maximus 的注释,认为这是不可能的。如果 currentScrip 仅在初始过程中可用,则无法获得唯一标识符来区分应显示的内容。
        • @degr 没有什么是不可能的... :) 我现在正在尝试使用arguments.callee...。stackoverflow.com/questions/280389/…
        • 是的,有道理,你可以在arguments.callee.caller.caller.caller....链上找到顶级组件,但这取决于你的项目结构。跨度>
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-07-14
        • 2013-03-21
        • 2019-11-15
        • 1970-01-01
        • 2015-04-09
        • 1970-01-01
        • 2018-02-18
        相关资源
        最近更新 更多