在 Chrome 中拦截对 console.log 的调用

问题描述 投票:0回答:8

我有一个无法更改的脚本,它会发出大量

console.log
调用。我想添加另一层并在调用包含某些字符串时进行响应。这在 Firefox 中有效,但在 Chrome 中的第 4 行抛出“
Illegal invocation
”错误:

var oldConsole = {};
oldConsole.log = console.log;
console.log = function (arg) {
    oldConsole.log('MY CONSOLE!!');
    oldConsole.log(arg);
}

有什么想法可以解决这个问题吗?我也尝试过克隆控制台...

javascript debugging console
8个回答
61
投票

您需要在 chrome 的

console.log
上下文中调用
console

(function () {
  var log = console.log;
  console.log = function () {
    log.call(this, 'My Console!!!');
    log.apply(this, Array.prototype.slice.call(arguments));
  };
}());

现代语言功能可以显着简化此片段:

{
  const log = console.log.bind(console)
  console.log = (...args) => {
    log('My Console!!!')
    log(...args)
  }
}

8
投票

我知道这是一篇旧帖子,但无论如何它都是有用的,因为其他解决方案与旧版浏览器不兼容。

您可以重新定义控制台的每个功能(以及对于所有浏览器)的行为,如下所示:

// define a new console
var console = (function(oldCons){
    return {
        log: function(text){
            oldCons.log(text);
            // Your code
        },
        info: function (text) {
            oldCons.info(text);
            // Your code
        },
        warn: function (text) {
            oldCons.warn(text);
            // Your code
        },
        error: function (text) {
            oldCons.error(text);
            // Your code
        }
    };
}(window.console));

//Then redefine the old console
window.console = console;

5
投票

您也可以使用相同的逻辑,但将其从控制台对象中调用,以便上下文是相同的。

if(window.console){
  console.yo = console.log;
  console.log = function(str){
    console.yo('MY CONSOLE!!');
    console.yo(str);
  }
}

3
投票

使用 ES6 新的展开运算符,你可以这样写

(function () {
  var log = console.log;
  console.log = function () {
    log.call(this, 'My Console!!!', ...arguments);
  };
}());

1
投票

可以简单地:

console.log = (m) => terminal.innerHTML = JSON.stringify(m)
#terminal {background: black; color:chartreuse}
$ > <span id="terminal"></span>
<hr>        
<button onclick="console.log('Hello world!!')">3V3L</button>
<button onclick="console.log(document)">3V3L</button>
<button onclick="console.log(Math.PI)">3V3L</button>


1
投票

要完全拦截控制台,我们可以重写每个方法:

const bindConsole=function(onMessage){
    Object.keys(console)
    .filter(type=>typeof(console[type])==='function')// *1
    .forEach(type=>{
        let _old=console[type];
        console[type] = function (...args) {
            _old.apply(console,args);
            onMessage(type,args);// *2
        };
    });
};

对于旧浏览器:

var bindOldConsole=function(onMessage){
    for(var k in console){// *1
        if(typeof(console[k])=='function')(function(type){
            var _old=console[type];
            console[type] = function () {
                _old.apply(console,arguments);
                onMessage(type,arguments);
            };
        })(k);
    }
};

  • *1 看起来 console 只有方法,但最好确定一下。

  • *2 您可以通过将此行替换为 : 来阻止从 onMessage

    对控制台的循环调用

if(!isCyclic())onMessage(type,args);

// es6. Not sure concerning old browsers :(
const isCyclic=function (){
    let erst=(new Error()).stack.split('\n');
    return erst.includes(erst[1],2);
};

0
投票

由于我(还)无法对 @ludovic-feltz 的答案发表评论,所以这里是他的答案,已更正以允许在控制台中进行字符串插值:

// define a new console
var console = (function(oldCons){
    return {
        log: function(...text){
            oldCons.log(...text);
            // Your code
        },
        info: function (...text) {
            oldCons.info(...text);
            // Your code
        },
        warn: function (...text) {
            oldCons.warn(...text);
            // Your code
        },
        error: function (...text) {
            oldCons.error(...text);
            // Your code
        }
    };
}(window.console));

//Then redefine the old console
window.console = console;

0
投票

既然我们都在这里玩得很开心,我可以提供吗:

var console = (function(csl=window.console){
    let consoleFns = Object.fromEntries(Object.keys(console).map(key=>{
        return [
            key, function(...text) {
                csl[key].apply(csl, ['Look ma!', ...text])
            }
        ]
    }))
    // Any additional method-specific code lives here
    return consoleFns;
}());

这带来了维护所有有效控制台功能的额外好处,同时提供了附加功能(在这个精心设计的示例中,在每个输出之前添加“Look ma!”。

我将由

map
构造的对象设置为
consoleFns
变量而不是简单地返回
map
的输出的原因,a la

return Object.fromEntries(Object.keys(console).map(key=>{

这样就可以替代

// Any additional method-specific code lives here

类似的东西
consoleFns.error = ()=>{}                         // Render console.error ineffective
consoleFns.warn  = consoleFns.log                 // Treat warn the same as log
consoleFns.flibbityGibbit = function(...text) {   // Prefix flibbityGibbit messages with "WoO-hOo, wOo-HoO!" in a lovely shade of violet
    csl.log.apply(csl, ["%cWoO-hOo, wOo-HoO!", "font-weight:bold; color: rebeccapurple;", ...text]);
}

尽管如果您的唯一目标是调整输出文本,您当然可以按照上面的方式简单地返回它。

© www.soinside.com 2019 - 2024. All rights reserved.