二方土君

怎么用目前最好的工具来调试Node.js

二方土君 · 2017-05-06翻译 · 2642阅读 原文链接 huangxiaolu审校

调试是一个在软件中查找和修复缺陷的过程,也是在所有语言中非常有挑战的一个任务。Node.js 也不例外。

幸运的是,到目前为止用于排查问题的工具已经改善很多了。让我们看看在 Node.js 应用中查找和修复问题的方法有哪些。

我们将会从两个方面来深入介绍 Node.js 应用的调试——第一个是记录日志(logging),这样就可以跟踪生产环境及其发出的事件。在记录日志之后,将会讨论怎么在开发环境中调试应用

在 Node.js 中记录日志

记录日志发生在应用的执行过程中,用以提供审查问题的线索。这些线索用于理解应用的执行路径,诊断问题并修复 bug。

在构建 Node.js 应用的时候,有很多方法来记录日志。一些 npm 模块自带记录日志的功能,使用的是debug(https://www.npmjs.com/package/debug)模块,当有需要的时候开启即可。对于自己的应用程序,你也应该选择一个记录日志的工具。这里介绍一下pino

在我们查看日志库之前, 先看看它们应该满足哪些要求

  • 时间戳(timestamps) - 知道某个事件在什么时候发生是很重要的;

  • 格式(formatting) - 每行日志必须对人类来说是可理解的,并且对程序来说是易于解析的;

  • 日志目的地(log destination) - 它应该总是标准的输出/错误,应用不应该关心日志路径;

  • 日志级别(log levels) - 日志事件有不同的严重程度,在大多数情况下,你并不会关心 debug 或者 info 级别的事件。

Node.js 里的debug模块

建议:用于发布到 npm 的模块

debug是一个轻型的 Node.js 调试的实用模块,它模仿了 Node.js 的核心调试技术@RisingStack

看看它是如何让你的工作变简单的!假设你有一个收发若干请求的 Node.js 模块:

// index.js
const debugHttpIncoming = require('debug')('http:incoming')
const debugHttpOutgoing = require('debug')('http:outgoing')

let outgoingRequest = {  
  url: 'https://risingstack.com'
}

// sending some request
debugHttpOutgoing('sending request to %s', outgoingRequest.url)

let incomingRequest = {  
  body: '{"status": "ok"}'
}

// serving some request
debugHttpOutgoing('got JSON body %s', incomingRequest.body)

写完以上代码后,用下面的命令来启动:

DEBUG=http:incoming,http:outgoing node index.js

输出如下:

Output of Node.js Debugging

当然 debug 模块也支持通配符*,为了得到与之前相同的结果,你可以用DEBUG=http:* node index.js来启动应用。

我们觉得 debug 模块很方便是因为在 npm 上的许多模块(比如 Express 或 Koa)都内置了 debug,在写这篇文章时已经有超过 14000 个模块在用它

pino 日志模块

建议:用于重视性能的应用

Pino 是一个非常快的 Node.js 日志模块,它参考了bunyan在很多情况下,pino 相比其他框架(如 bunyan 或者 winston)快 6 倍

benchWinston*10000:     2226.117ms  
benchBunyan*10000:      1355.229ms  
benchDebug*10000:       445.291ms  
benchLogLevel*10000:    322.181ms  
benchBole*10000:        291.727ms  
benchPino*10000:        269.109ms  
benchPinoExtreme*10000: 102.239ms

启动 pino 非常简单:

const pino = require('pino')()

pino.info('hello pino')  
pino.info('the answer is %d', 42)  
pino.error(new Error('an error'))

上面的代码片断会输出以下的 log 消息:

{"pid":28325,"hostname":"Gergelys-MacBook-Pro.local","level":30,"time":1492858757722,"msg":"hello pino","v":1}
{"pid":28325,"hostname":"Gergelys-MacBook-Pro.local","level":30,"time":1492858757724,"msg":"the answer is 42","v":1}
{"pid":28325,"hostname":"Gergelys-MacBook-Pro.local","level":50,"time":1492858757725,"msg":"an error","type":"Error","stack":"Error: an error\n    at Object.<anonymous> (/Users/gergelyke/Development/risingstack/node-js-at-scale-debugging/pino.js:5:12)\n    at Module._compile (module.js:570:32)\n    at Object.Module._extensions..js (module.js:579:10)\n    at Module.load (module.js:487:32)\n    at tryModuleLoad (module.js:446:12)\n    at Function.Module._load (module.js:438:3)\n    at Module.runMain (module.js:604:10)\n    at run (bootstrap_node.js:394:7)\n    at startup (bootstrap_node.js:149:9)\n    at bootstrap_node.js:509:3","v":1}

Node.js 内置的 Debugger 模块

Node.js 内置了一个进程外的调试工具,可以通过 TCP 协议和内置的客户端来使用。你可以通过以下命令来启动它:

`$ node debug index.js`

它并不是一个功能完全的调试工具,没有很高大上的界面,但是可以用来进行简单的调试。

你可以在代码中添加一行debugger来添加一个断点:

const express = require('express')  
const app = express()

app.get('/', (req, res) => {  
  debugger
  res.send('ok')
})

通过这种方式你的脚本将会在那一行暂停下来,然后你可以用这个调试工具提供的命令来调试应用:

  • cont or c - 继续执行;

  • next or n - 执行下一条;

  • step or s - 单步进入;

  • out or o - 跳出当前语句;

  • repl - 计算脚本的上下文。

V8 集成的 Node.js 监听器

V8 集成的监视器使用 Chrome 调试协议(Chrome Debugging Protocol)将 Chrome DevTools 应用到 Node.js 实例中进行调试

在启动应用时添加--inspect标志,能够启用 V8 监视器。

$ node --inspect index.js

在多数情况下,会需要在第一行代码就停止执行,然后再调试执行后续代码。输入下面的命令可以一行一行执行你的代码,这样就不会错过任何执行的语句。

$ node --inspect-brk index.js

我建议全屏地观看视频来学习更详细的内容!

如何通过 Visual Studio Code 来调试 Node.js

**很多现代 IDE 已经支持调试应用,比如 VS Code。它内置了 Node.js 的调试器。

下面你看到的是 VS Code 的调试界面,界面上有上下文变量面板、监听面板和函数调用栈面板和断点面板。

VS Code Debugging Layout

图片来源:Visual Studio Code

一个非常有用的特性是 Visual Studio Code 调试工具能够添加条件断点。有了条件断点,只要表达式结果为 true,就能触发断点。

如果你要使用 VS Code 里更高级的调试功能,就需要配置一份.vscode/launch.json文件,里面定义一系列的调试规则。通常默认的launch.json会如下所示:

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Program",
            "program": "${workspaceRoot}/index.js"
        },
        {
            "type": "node",
            "request": "attach",
            "name": "Attach to Port",
            "address": "localhost",
            "port": 5858
        }
    ]
}

想了解更多launch.json的配置说明,请查阅:https://code.visualstudio.com/docs/editor/debugging#_launchjson-attributes.

了解更多Visual Studio Code的调试信息,请访问官方网站:https://code.visualstudio.com/docs/editor/debugging

相关文章