You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现保留行号、支持前缀及字符串替换的console Proxy?

实现带前缀、保留行号且支持字符串替换的Console Proxy

问题背景

我实现了一个Console Proxy用于给每条控制台输出添加前缀,现有两种方案但各有缺陷:

  1. 基于bind的方案:能保留原始行号,但前缀会成为第一个参数,导致含%c/%s等替换标记的消息无法正确匹配后续参数;
  2. 参数捕获转发的方案:能正确处理替换标记,但会丢失原始调用的行号,控制台显示代理函数的行号。

希望找到能同时兼顾添加前缀、保留原始行号、支持字符串替换的方案,也可接受放弃替换的折中方案。

初始方案(保留行号但破坏替换)

const disabledMethodsInProduction = ['debug', 'log', 'trace'];
logger = new Proxy(console, {
    get (target, method) {
        if (method in target) {
            if (!developmentMode && disabledMethodsInProduction.includes(method)) {
                return () => { /* NOP */ };
            }
            // 'loggingID' 为外部定义的字符串标识
            return target[method].bind(console, `${loggingID}:`);
        }
        throw new Error(`Method '${method}()' not implemented in console.`);
    }
});

参数捕获方案(支持替换但丢失行号)

return function () {
    const args = Array.from(arguments);
    if (typeof args[0] === 'string') {
        args[0] = `${loggingID}: ` + args[0];
    } else {
        args.unshift(`${loggingID}:`);
    }
    target[method](...args);
}

解决方案

方案1:兼顾所有需求(推荐)

利用new Function动态生成处理函数,浏览器会将调用该动态函数的位置作为控制台消息的来源行号,同时在函数内部正确拼接前缀、处理替换标记:

const disabledMethodsInProduction = ['debug', 'log', 'trace'];
const loggingID = 'YOUR_LOG_ID'; // 替换为实际的标识字符串

logger = new Proxy(console, {
    get(target, method) {
        if (!(method in target)) {
            throw new Error(`Method '${method}()' not implemented in console.`);
        }

        if (!developmentMode && disabledMethodsInProduction.includes(method)) {
            return () => {};
        }

        // 动态生成包装函数,确保行号指向原始调用位置
        const wrappedFn = new Function('target', 'method', 'loggingID', `
            return function (...args) {
                // 给第一个字符串参数添加前缀,非字符串则插入前缀作为第一个参数
                if (args.length > 0 && typeof args[0] === 'string') {
                    args[0] = \`\${loggingID}: \${args[0]}\`;
                } else {
                    args.unshift(\`\${loggingID}:\`);
                }
                // 调用原始console方法
                target[method](...args);
            };
        `)(target, method, loggingID);

        return wrappedFn;
    }
});

测试效果:

logger.log('Hello %s', 'World'); // 输出:YOUR_LOG_ID: Hello World,行号为当前代码行
logger.log('Hello %cWorld', 'color: red'); // 输出带红色样式的文本,行号正确
logger.log({ foo: 'bar' }); // 输出:YOUR_LOG_ID: {foo: "bar"},行号正确

该方案在Chrome、Firefox等现代浏览器中均能正常工作,完美满足所有需求。

方案2:折中方案(保留行号,放弃替换)

如果可以接受%c等替换标记失效,直接使用初始的bind方案即可,代码简单且能完美保留原始行号:

const disabledMethodsInProduction = ['debug', 'log', 'trace'];
logger = new Proxy(console, {
    get (target, method) {
        if (method in target) {
            if (!developmentMode && disabledMethodsInProduction.includes(method)) {
                return () => { /* NOP */ };
            }
            return target[method].bind(target, `${loggingID}:`);
        }
        throw new Error(`Method '${method}()' not implemented in console.`);
    }
});

内容的提问来源于stack exchange,提问作者Raúl Núñez de Arenas Coronado

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 08:56:10