尝试以扩展 VS Code 中的代理模式!

介绍日志点和自动附加

2018 年 7 月 12 日,Kenneth Auchenberg,@auchenberg

在过去的几个月里,我们一直忙于改进 Visual Studio Code 中的调试体验,在这篇文章中,我将讨论我们如何看待调试,介绍我们从用户那里听到的反馈,并解释我们为使 VS Code 中的调试更容易、更简单而采取的步骤。

自 VS Code 诞生以来,我们就提供了集成调试体验,因为我们相信调试应该是您编写和编辑源代码的地方——您的编辑器——不可或缺的一部分。

VS Code debugger

VS Code 调试体验由一个通用调试器 UI 提供支持,该 UI 通过调试适配器协议 (DAP) 与我们称为调试适配器 (DA) 的特定类型的 VS Code 扩展进行通信。DA 与真正的调试器通信,并在 DAP 和调试器的特定运行时调试协议或 API 之间进行转换。

这意味着 VS Code 的核心与特定调试器完全解耦,这种架构允许 VS Code 调试任何内容,只要有调试适配器可用,如下图所示:


VS Code debugging architecture


观察与痛点

今天,有大量满意的开发人员定期使用 VS Code 进行调试,但是,作为我们使命的一部分,我们希望让更多的开发人员更容易地使用调试。

为此,我们开始对话,以更好地了解 VS Code 中调试的痛点,并了解为什么有些开发人员根本不使用我们的调试器。

以下是我们的观察结果:

调试配置难以正确设置

VS Code 是一个通用编辑器,带有通用调试器,不专用于特定的堆栈或运行时。因此,我们无法提供一个适用于所有人的主观默认调试配置。

这意味着 VS Code 要求您配置调试器设置,并指定如何使用正确的参数等启动运行时。

我们认识到这可能很难正确设置,但我们看不到完全消除每个人的调试配置的方法。但是,我们确实相信调试配置可以简化,并且根据上下文,可以最小化。

我稍后会回到这个问题。

启动和附加配置之间的混淆

在 VS Code 中,我们有两个核心调试概念:**启动**和**附加**,它们处理两种不同的工作流和开发人员群体。根据您的工作流,了解哪种类型的配置适合您的项目可能会令人困惑。

如果您有浏览器 DevTools 背景,您不习惯“从您的工具启动”的概念,因为您的浏览器实例已经打开。当您打开 DevTools 时,您只是**附加**DevTools 到您打开的浏览器标签页。另一方面,如果您有 Java 背景,让您的编辑器**启动**您的 Java 进程是很正常的,并且您的编辑器会自动将其调试器附加到新启动的进程。

解释**启动**和**附加**之间区别的最佳方法是,将启动配置视为在 VS Code 附加到应用程序**之前**如何在调试模式下启动应用程序的配方,而附加配置是关于如何将 VS Code 的调试器连接到**已经**运行的应用程序或进程的配方。

启动配置的价值在于,它们为您提供了一种通过创建可重复并与您的项目和团队共享的配置,来减轻使用正确调试参数启动应用程序的一些认知开销的方法。

然而,当我们与开发人员讨论他们如何启动应用程序时,我们看到了一个模式并做出了一项重要观察:

**观察**:许多使用 VS Code 的开发人员非常喜欢集成终端,并依赖命令行工具来启动他们的应用程序。对许多人来说,在终端中运行命令,然后从编辑器附加调试器是一种更自然的工作流。这类似于在浏览器启动后打开 DevTools。

这项观察是关键,我们意识到许多用户不希望在他们的编辑器中获得一个完整的“神奇”启动体验。他们希望将编辑器作为编辑和调试源代码的地方,并使用终端启动应用程序、运行构建脚本等。这也是我们在 VS Code 中提供集成终端体验的原因之一,因为我们相信一个良好实用的 UI 应该与终端共存并良好集成。

许多开发人员不使用断点,因为他们正在检查状态更改

在观察开发人员如何调试他们的应用程序时,我们还看到了另一个有趣的模式:使用日志代替断点。

用于调试的日志记录并不是一个新概念,但观察结果很重要:

**观察**:传统的调试工作流主要侧重于减慢执行速度以检查程序逻辑,而日志工作流通常涉及检查程序状态及其在应用程序正常执行期间如何变化。这里的基本观察是,这两种技术用于不同的调试目的。

这项观察对于 JavaScript 开发人员尤其相关,他们主要处理管理状态的复杂性,这或许可以解释为什么大多数 JavaScript 开发人员仍然更喜欢将 console.log 添加到他们的源代码中,而不是使用脚本调试器。

自动附加到 Node 进程

在反思一些开发人员如何使用集成终端启动调试会话时,我们看到了一个独特的机会。通过利用我们在 VS Code 中从编辑器和集成终端获得的上下文信息,我们可以检测您的上下文并推断您的调试意图,这可以为 Node.js 开发人员提供更简单的调试体验。

因此,在 我们三月迭代的 VS Code 中,我们发布了一个名为**Node 自动附加**的新功能,它使 Node 调试器能够自动附加到从 VS Code 的集成终端以调试模式启动的 Node.js 进程。

您可以通过从命令面板运行**调试:切换自动附加**命令来启用自动附加,一旦激活,您也可以从状态栏切换自动附加。


Auto attach


此功能完全消除了任何调试配置,因为我们将任何以 `node --inspect` 启动的 Node.js 进程解释为调试意图。当与集成终端结合使用时,它是一种更简单的调试体验,允许开发人员以自己的方式启动应用程序,同时消除了调试配置!🎉

NPM 脚本和调试

许多 Node.js 开发人员依赖 npm 脚本来启动应用程序或开始调试会话,我们在这方面也有一些好消息:自动附加也适用于 npm 脚本。如果您运行 `npm run debug` 并且 `"debug"` 脚本是 `"node --inspect"` 或任何其他包含 `--inspect` 的命令,那么自动附加将检测到并附加调试器 🎉

我们还认识到一些开发人员希望以更可视化的方式查找和运行他们的 npm 脚本,因此在 我们 2018 年 4 月的迭代中,我们添加了一个新的 NPM 脚本资源管理器,允许您直接从 UI 浏览和运行您的 NPM 脚本。作为我们简化调试配置工作的一部分,我们还可以在不创建调试配置的情况下直接从资源管理器启动 Node.js 调试。

如果您有一个包含调试参数(例如 `--inspect`)的 npm 脚本,我们将自动检测到这一点并提供一个启动调试器的调试操作,如下图所示:

NPM scripts

日志点介绍

基于日志记录是一项重要调试技术的经验,我们看到了将状态检查添加到现有调试体验的机会。在 VS Code 的三月迭代中,我们发布了我们称之为日志点的调试功能的首次实现。

日志点是一种断点变体,它不会“中断”到调试器中,而是将消息记录到控制台。

Logpoints

日志点的概念并不新鲜,在过去几年中,我们看到了各种形式的概念,例如在 Visual StudioEdge DevToolsGDB 等工具中,它们有多个名称,如 Tracepoints 和 Logpoints

为什么要使用日志点,以及何时使用?

日志点基于以下观察:在许多情况下,您不想在应用程序的特定部分停止执行,而是希望检查状态在应用程序生命周期内如何变化。

日志点允许您按需将日志语句“注入”到应用程序逻辑中,就像您在启动应用程序之前已经添加了日志语句一样。日志点在执行时注入,不保留在源代码中,因此您无需提前计划,但可以根据需要注入日志点。另一个好处是,调试完成后,您无需担心清理源代码。

对于 JavaScript 开发人员来说,这意味着您不必再担心留下 `console.log` 了——只需使用日志点!更好的是,您可以结合使用 `console.log` 和日志点。如果您将日志点插入到已经有 `console.log` 的源代码块中,您将在调试控制台中看到两种类型的日志语句。

云上下文中的日志点

日志点在云上下文(或任何远程上下文)中特别有用,因为它们使您能够将日志注入到远程环境中,而无需重新部署应用程序。同样重要的是,您不会通过日志点暂停脚本执行,因此您的用户不会受到影响,这与在常规断点处暂停运行的应用程序不同。

您可以在此处阅读更多关于如何在 Azure 上将日志点用于 Node.js 的信息。

支持的语言

自 VS Code 中首次发布日志点以来,我们看到 VS Code 调试适配器越来越多地采用日志点,今天以下语言都支持日志点:

VS Code 中的日志点

如果您有兴趣在 VS Code 的调试适配器中添加日志点支持,请查看协议中的这些更改。您还可以查看上述调试适配器,了解每个运行时如何选择实现日志点。

后续步骤

目前就这些,但我们还没结束。在我们七月的迭代中,我们根据用户反馈,正在改进自动附加功能,以提高可发现性(#53640)。

我们希望自动附加、NPM 脚本资源管理器和日志点的引入将使使用 VS Code 进行调试变得更容易。一如既往,我们渴望听到您的反馈,因此请通过 GitHubTwitter 上的 @code 联系我们。

代表 VS Code 团队:祝您编码愉快!

/Kenneth Auchenberg - @auchenberg on Twitter