方便快捷的调试 Node.js 程序
在调试程序时总是会遇到各种挑战。Node.js 的异步工作流为这一艰巨的过程增加了额外的复杂性。尽管 V8 引擎为了方便访问异步栈跟踪进行了一些更新,但是在很多数情况下,我们只会在程序主线程上遇到错误,这使得调试有些困难。同样,当我们的 Node.js 程序崩溃时,通常需要依靠一些复杂的 CLI 工具来分析核心转储[1]。
在本文中,我们将介绍一些调试 Node.js 程序的简便方法。
日志记录
当然,没有哪一个开发工具箱是不提供日志的。我们倾向于在本地开发中的整个代码中放置 console.log
语句,但这并不是生产中真正可扩展的策略。你可能需要进行一些过滤和清理,或者实施一致的日志记录策略,以便从中识别出重要的信息。
要实施适当的面向日志的调试策略,可以用 Pino[2]或 Winston[3] 之类的日志记录工具。这些将允许你设置日志级别(INFO
、 WARN
、ERROR
),它们允许你在本地打印详细的日志消息,同时在生产环境下仅打印严重的日志消息。你还可以将这些日志流式传输到聚合器或其他地方,例如 LogStash,Papertrail 甚至 Slack。
使用 Node Inspect 和 Chrome DevTools
日志记录只能使我们了解程序为何无法按预期运行。对于复杂的调试,我们将希望使用断点来检查代码在执行时的行为。
为此,可以使用 Node Inspect。Node Inspect 是 Node.js 附带的调试工具。它实际上只是程序的 Chrome DevTools[4] 的实现,可让你添加断点、控制分步执行、查看变量、并遵循调用堆栈。
有两种方法启动 Node Inspect,但最简单的方法可能就是使用 --inspect-brk
标志来调用 Node.js 应用程序:
$ node --inspect-brk $your_script_name
Node inspector
启动程序后,前往 Chrome 浏览器中的 chrome://inspect
URL 进入 Chrome DevTools。借助 Chrome DevTools,你可以拥有在浏览器中调试 JavaScript 时的所有功能。最有用的功能是检查内存的能力[5]。你可以获取堆快照[6]并配置内存使用情况,以了解内存的分配方式以及可能的方式及内存泄漏的情况。
使用受支持的IDE
许多现代 IDE 不但能够以某种方式启动程序,而且还支持调试 Node 程序。除了具有 Chrome DevTools 中的许多功能外,它们还具有自己的功能,例如可以创建日志点[7]并允许你创建多个调试配置文件。可以通过查阅有关检查器客户端的 Node.js 指南[8]来获取有关这些 IDE 的更多信息。
使用NDB
NDB
另一种选择是安装 ndb[9],它是 Node.js 的独立调试器,和浏览器中的 DevTools 类似,就像一个隔离的本地调试器一样。它还有一些在 DevTools 中不可用的额外功能。它支持本地编辑,这意味着你可以修改代码并得到调试器平台直接支持的更新逻辑。这对于进行快速迭代非常有用。w
事后调试
假设你的程序由于灾难性错误(例如内存访问错误)而崩溃。这些可能很少见,但确实会发生,特别是如果你的应用程序依赖于本机代码。
要调查这类问题,可以使用 llnode[10]。当程序崩溃时,llnode
可以通过将 JavaScript 堆栈框架和对象映射到 C/C++ 端的对象来检查它们。为了使用它,你首先需要程序的核心转储。为此你需要使用 process.abort
而不是process.exit
来关闭代码中的进程。当你使用 process.abort
时,Node 进程在退出时会生成一个核心转储文件。
为了更好地理解 llnode
可以提供的功能,这个视频演示了其一些功能[11]。
有用的 Node 模块
除了上述所有以外,还建议用第三方软件包做进一步调试。
debug
第一个被简单地称为 debug[12]。使用 debug,你可以基于函数名或整个模块为日志消息分配特定的命名空间。然后可以通过特定的环境变量选择将哪些消息打印到控制台。
例如,这是一个 Node.js 服务器,它正在记录来自整个程序和中间件栈的几条消息,例如 sequelize
,express:application
和 express:router
:
Debug 模块完整输出
如果我们将 DEBUG 环境变量设置为 express:router
并启动相同的程序,则仅显示标记为 express:router
的消息:
Debug 模块过滤后的输出
通过以这种方式过滤消息,可以深入研究程序单个部分的行为方式,而无需大幅度更改代码的日志记录。
trace 与 clarify
trace[13] 和 clarify[14] 两个模块最好在一起配合使用。
trace
通过提供有关被调用的异步方法的更多详细信息来扩展你的异步栈跟踪,这是 Node.js 默认不提供的路线图。clarify
通过从特定于 Node.js 内部的栈跟踪中删除所有信息来提供帮助。这使你可以专注于仅针对程序的函数调用。
这些模块都不建议在生产环境中运行!仅在本地开发环境中进行调试时才应启用它们。
- Collaborative Filtering(协同过滤)算法详解
- 【Hadoop】三句话告诉你 mapreduce 中MAP进程的数量怎么控制?
- Spark系列课程-00xxSpark RDD持久化
- RDD持久化
- P02_Hadoop CDH 5.3.6集群搭建
- P01_Spark开发测试运行环境安装Spark开发测试运行环境安装
- spark2.x依赖包POM
- P03_Hive 安装
- P06_flume-ng-1.5.0-cdh5.3.6安装
- P04_zookeeper-cdh5集群搭建
- P05_kafka_2.9.2-0.8.1集群搭建
- 再探matplotlib
- 分布式系统(Distributed System)资料
- Python性能提升20倍居然不是标题党?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 使用Source Monitor检测Java代码的环复杂度
- AndroidStdio1_2
- 使用扩展技术对SAP Fiori应用进行端到端的增强,一个实际案例介绍
- python Unhandled exception in event loop:错误解决
- SAP Fiori image的显示原理
- 解决Error:All flavors must now belong to a named flavor dimension.
- 同时搞定Android和iOS的Dart语言(3):数值类型
- SAP Fiori图标(icon)设计原理
- SAP Fiori应用发生超时错误的一个可能原因
- 如何用云开发快速搭建实时 Todo List 应用
- Angular应用的入口
- Angular里的structural directive的一个例子
- Angular条件指令ngIf的一个例子
- Angular的property binding一个例子
- Angular里的按钮事件注册方法一例