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

Mat*_*ius 5 javascript console.log google-chrome-console

我正在研究使用相当多js库的项目,其中一个正在向控制台输出非常多的东西,它正在污染无线电波,这使得它很难调试....

我知道如何通过覆盖console.log这个完全禁用日志记录,

(function (original) {
    console.enableLogging = function () {
        console.log = original;
    };
    console.disableLogging = function () {
        console.log = function () {};
    };
})(console.log);
Run Code Online (Sandbox Code Playgroud)

但是如何根据消息来源的源(文件/网址)执行此操作?

VLA*_*LAZ 6

前言

一开始讨论了一般情况下的工作原理.如果您只关心代码,请跳过" 简介"并滚动到" 解决方案"标题.

介绍

问题:

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

需求:

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

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

以前的工作:

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

(function (original) {
    console.enableLogging = function () {
        console.log = original;
    };
    console.disableLogging = function () {
        console.log = function () {};
    };
})(console.log);
Run Code Online (Sandbox Code Playgroud)

(代码贴在问题上,但也在这里供参考)

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

可以使用日志框架,但它可能是一种矫枉过正.虽然,老实说,我认为这就是我想要的,但它可能需要与产品进行一些整合.

因此,我们需要一些轻量级的东西,它具有一些配置而且不需要漂亮.

提案:

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!")
Run Code Online (Sandbox Code Playgroud)

这显然可以改进,但它展示了如何停止任何和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.");
Run Code Online (Sandbox Code Playgroud)

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

如何进行选择性记录

唯一缺少的是确定来自哪个文件.我们只需要一个堆栈跟踪.

// 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)
*/
Run Code Online (Sandbox Code Playgroud)

(相关位在这里复制.)

没错,有一些更好的方法可以做到但不是很多.它要么需要框架,要么需要特定于浏览器 - 错误堆栈不受官方支持,但它们可以在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
Run Code Online (Sandbox Code Playgroud)

或黑名单

(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"])
Run Code Online (Sandbox Code Playgroud)

所以,这是一个自定义记录器.当然,它并不完美,但它会完成这项工作.而且,嘿,因为白名单有点松散,它可以变成一个优势:

  • 到白名单一堆共享一个子文件的,也就是说,所有myApp可以包括myApp1.js,myApp2.js,和myApp3.js.
  • 虽然如果你想要特定的文件,你可以只传递全名,包括扩展名.我怀疑会有一堆重复的文件名.
  • 最后,堆栈跟踪将包含调用函数的名称(如果有),因此您实际上可以只传递它,并且将按功能列入白名单.但是,它依赖于具有名称的函数,并且函数名称更容易发生冲突,因此请小心使用

除此之外,肯定会有改进,但这是它的基础.例如,info/ warnmethods也可以被覆盖.

所以,如果使用的话,这应该只在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"]);
Run Code Online (Sandbox Code Playgroud)

这是缩小的(虽然我首先通过Babel,使用ES5缩小)并且仍然可以配置,在某种程度上,因为你可以改变你可以通过白名单的最终结果.但除此之外,它将工作相同,并完全脱离代码库.它不会在页面加载时运行,但如果需要,您可以将其用作用户脚本(仍然解耦)或仅在dev/debug构建中的其他JS文件之前包含它.

这里有一个注释 - 这适用于Chrome,Edge和Firefox.它是所有最新的浏览器,因此我假设开发人员将至少使用其中一个.这个问题被标记为Chrome,但我决定扩大支持范围.只有Chrome的解决方案可以稍微好一些,但实际上并没有太大的功能损失.