重写并自定义console.log()输出样式

0. 背景

笔者在开发的实践过程中对于控制台内容的输出情况有一些特殊的需求,然而,普通的console.log()函数不能提供很好的支持,因此需要探索一些自定义的实现方式,以便满足开发需求,一些开发需求如下:

  1. 输出内容统一管理,调整开启或关闭;
  2. 不同的开发阶段显示不同的输出样式,如:测试、调试、生产;
  3. 统一样式调整;
  4. ……

1. 实现

1.1 简单重写:使用变量保存console.log

let fun = console.log
console.log = function () {
	fun(...arguments)
}

1.2 简单重写:使用立即执行函数

console.log = (function (oriLogFunc) {
	return function () {
		oriLogFunc('debug : ', ...arguments)
	}
})(console.log)

1.3 自定义封装

export default {
  // 输出等级: 0-no, 1-error, 2-warning, 3-info, 4-debug, 5-log
  level: 5,
  // 输出模式: 0-default, 1-normal, 2-random
  mode: 1,
  // 是否输出图标
  hasIcon: false,
  // 是否打印函数名和所在文件行号
  isPrintLine: true,
  // 图标
  icons: ['🌵', '🎍', '🐾', '🌀', '🐚', '🥝', '🥜', '🥕', '🥒', '🌽', '🍒', '🍅', '🍑', '🍋', '🍈', '🌶', '🌰', '🍠', '🍆', '🍄', '🍐', '🍌', '🍍', '🍇', '🍏', '🍓', '🍎', '🍊', '🐴', '🐗', '🦄', '🐑', '🐶', '🐔', '🐼', '🐒', '🌝', '💄', '💋', '👠', '👗', '👙', '🧣', '🍰', '🍭', '🍳', '🎄', '🎱', '⚽', '🏀', '🎵', '🚄', '⭕', '❌', '❓', '❗', '💯'],
  // 标准颜色
  colors: {
    error: '#f7630c',
    warning: '#ca5010',
    info: '#0078d7',
    debug: '#13a10e',
    log: '#1f1f1f'
  },
  // 获取随机图标
  randomIcon: function () {
    return this.icons[Math.floor(Math.random() * this.icons.length)]
  },
  // 获取随机颜色
  randomColor: function () {
    const r = Math.floor(Math.random() * 256)
    const g = Math.floor(Math.random() * 256)
    const b = Math.floor(Math.random() * 256)
    // 返回随机生成的颜色
    return `rgb(${r}, ${g}, ${b})`
  },
  // 默认打印
  printDefault: function (tag, args) {
    console.log(tag, ...args)
  },
  // 标准打印
  printNormal: function (tag, args) {
    console.log(`%c ${tag} : `, `color: ${this.colors[tag]}`, ...args)
  },
  // 随机打印
  printRandom: function (tag, args) {
    const icon = this.randomIcon()
    const bgColor = this.randomColor()
    const color = this.randomColor()
    console.log(`%c ${icon}`, `font-size:20px;background-color: ${bgColor};color: ${color};`, tag + ' : ', ...args)
  },
  print: function (tag, args) {
    if (this.isPrintLine) {
      // 获取函数名和行号
      const err = new Error()
      // console.log(err.stack)
      const stack = err.stack.split('\n').slice(3).map(line => line.trim())
      const caller = stack[0].match(/at (.+) \(/) ? stack[0].match(/at (.+) \(/)[1] : stack[0].match(/at (.+):\d+:/)[1]
      const fileLine = stack[0].match(/\(.*\/(.+)\)/) ? stack[0].match(/\(.*\/(.+)\)/)[1] : stack[0].match(/(\d+:\d+)/)[1]
      // console.log(`${caller} (${fileLine}):\n`)

      args.push(`\n at : ${caller} (${fileLine})`)
    }

    switch (this.mode) {
      case 0: {
        this.printDefault(tag, args)
        break
      }
      case 1: {
        this.printNormal(tag, args)
        break
      }
      case 2: {
        this.printRandom(tag, args)
        break
      }
    }
  },
  error: (function (oriLogFunc) {
    return function (...args) {
      const tag = 'error'
      if (this.level >= 1) {
        // oriLogFunc.call(console, 'error : ', args)
        this.print(tag, args)
      }
    }
  })(console.log),

  warning: (function (oriLogFunc) {
    return function (...args) {
      const tag = 'warning'
      if (this.level >= 2) {
        // oriLogFunc.call(console, 'warning : ', args)
        this.print(tag, args)
      }
    }
  })(console.log),

  info: (function (oriLogFunc) {
    return function (...args) {
      const tag = 'info'
      if (this.level >= 3) {
        // oriLogFunc.call(console, 'info : ', args)
        this.print(tag, args)
      }
    }
  })(console.log),

  debug: (function (oriLogFunc) {
    return function (...args) {
      const tag = 'debug'
      if (this.level >= 4) {
        // oriLogFunc.call(console, 'debug : ', ...args)
        this.print(tag, args)
      }
    }
  })(console.log),

  log: (function (oriLogFunc) {
    return function (...args) {
      const tag = 'log'
      if (this.level >= 5) {
        // oriLogFunc.call(console, 'log : ', ...args)
        this.print(tag, args)
      }
    }
  })(console.log)
}

2. 测试

目录
在这里插入图片描述

  1. 新建一个html文件
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>123123123</div>
    <button id="logBtn">log</button>
    <script type="module">
        import iceLog from './iceLog.js'
        window.onload = () => {
            window.iceLog = iceLog
            iceLog.log('hello new log')
            iceLog.debug('hello new debug')
            iceLog.info('hello new info')
            iceLog.warning('hello new warning')
            iceLog.error('hello new error')
        }

        document.getElementById('logBtn').addEventListener('click', () => {
            iceLog.log('click log button')
        })
    </script>
</body>
</html>
  1. 结果
    在这里插入图片描述

x. 参考

  1. 重写console.log方法
  2. 重写 console.log() 让其变的花里胡哨
  3. console.log格式输出全解及console的其他方法
  4. console 打印函数名和行号
  5. console.log输出打印日志所在代码行数
  6. 在html的script标签中使用import
  7. JS函数怎么实现传入任意数量参数?
  8. 重写console.log的一些理解
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要获取 CEF 中的 `console.log` 内容,可以使用 `CefMessageRouterBrowserSide` 类来实现。 以下是一个简单的例子,展示如何使用 `CefMessageRouterBrowserSide` 来获取 `console.log` 内容: ```cpp // 创建一个实现了 CefMessageRouterBrowserSide::Handler 接口的对象 class ConsoleMessageHandler : public CefMessageRouterBrowserSide::Handler { public: // 处理 JavaScript 发送过来的消息 virtual bool OnQuery(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int64 query_id, const CefString& request, bool persistent, CefRefPtr<Callback> callback) OVERRIDE { if (request == "get-console-log") { // 获取 console.log 内容并发送回去 CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create("console-log"); message->GetArgumentList()->SetString(0, GetConsoleLog()); browser->SendProcessMessage(PID_BROWSER, message); return true; } return false; } // 获取 console.log 内容 CefString GetConsoleLog() { CefRefPtr<CefFrame> frame = browser_->GetMainFrame(); CefRefPtr<CefV8Context> context = frame->GetV8Context(); CefRefPtr<CefV8Value> window = context->GetGlobal(); CefRefPtr<CefV8Value> console = window->GetValue("console"); CefRefPtr<CefV8Value> logFn = console->GetValue("log"); CefRefPtr<CefV8Value> logArray = CefV8Value::CreateArray(0); CefRefPtr<CefV8Exception> exception; CefRefPtr<CefV8Value> result = logFn->ExecuteFunctionWithContext(context, window, logArray); CefString consoleLog; if (result->IsArray()) { CefRefPtr<CefV8Value> arr = result; int len = arr->GetArrayLength(); for (int i = 0; i < len; i++) { CefRefPtr<CefV8Value> val = arr->GetValue(i); consoleLog += val->GetStringValue() + "\n"; } } return consoleLog; } IMPLEMENT_REFCOUNTING(ConsoleMessageHandler); }; // 创建一个实现了 CefRenderProcessHandler 接口的对象 class RenderProcessHandler : public CefRenderProcessHandler { public: // 创建一个 CefMessageRouterBrowserSide 对象 virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) OVERRIDE { CefRefPtr<CefMessageRouterBrowserSide> messageRouter = CefMessageRouterBrowserSide::Create( CefMessageRouterBrowserSide::Config(), new ConsoleMessageHandler()); messageRouter->AddHandler(new ConsoleMessageHandler(), false); messageRouter->OnContextCreated(browser, frame, context); } // 注册一个 JavaScript 扩展 virtual void OnWebKitInitialized() OVERRIDE { CefRegisterExtension("console", "var console = {log: function() {native function consoleLog(); consoleLog(Array.prototype.slice.call(arguments));}};", new ConsoleMessageHandler()); } IMPLEMENT_REFCOUNTING(RenderProcessHandler); }; ``` 在上面的代码中,我们首先创建了一个实现了 `CefMessageRouterBrowserSide::Handler` 接口的对象 `ConsoleMessageHandler`。该对象实现了 `OnQuery` 方法,用于处理 JavaScript 发送过来的消息。当接收到 `get-console-log` 消息时,我们调用 `GetConsoleLog` 方法获取 `console.log` 内容,并将其发送回 JavaScript 端。 `GetConsoleLog` 方法首先获取当前浏览器上下文和主框架,然后使用 `CefV8Context::GetGlobal` 方法获取全局对象。接着,我们使用 `CefV8Value::GetValue` 方法获取 `console` 对象和 `log` 函数,并将其保存在 `logFn` 变量中。我们使用 `CefV8Value::CreateArray` 方法创建一个空的数组 `logArray`,并调用 `logFn->ExecuteFunctionWithContext` 方法执行 `console.log` 函数。最后,我们遍历返回的数组 `result`,获取每条 `console.log` 的内容,并将其保存在 `consoleLog` 变量中。 为了使 CEF 能够调用 `console.log` 函数,我们还需要在 `OnWebKitInitialized` 方法中注册一个 JavaScript 扩展。在这个扩展中,我们将 `console.log` 函数重写为一个 JavaScript 函数,该函数会调用 C++ 中的原生函数 `consoleLog`,并将 `console.log` 的参数传递给该函数。在 `consoleLog` 函数中,我们可以将 `console.log` 的参数保存起来,以便在需要时返回给 JavaScript 端。 最后,我们还需要在渲染进程中创建一个实现了 `CefRenderProcessHandler` 接口的对象 `RenderProcessHandler`,并在其中通过 `OnContextCreated` 方法创建一个 `CefMessageRouterBrowserSide` 对象,并将其注册到当前上下文中。通过这样的方式,我们就可以在 CEF 中获取 `console.log` 内容了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值