2023年12月6日发(作者:)
使用 IntelliTrace 调试应用程序
文章原地址:这里
Justin Marks
下载代码示例
用户如何修复他们的代码中的Bug?您设置一些断点、在调试器下运行程序、进行一点单步调试–并祈求能够轻而易举地发现问题,这样您就能继续处理其他事情。
几乎自ENIAC发明以来,我们就一直在进行着同样方式的调试。这种繁琐而耗时的调试方法为我们提供了很好的帮助,但是时候使调试更加轻松了。随着Visual Studio 2010 Ultimate的发布,新的IntelliTrace功能使开发人员能够更深入地了解应用程序的执行情况,从而使调试进入了21世纪。
与其他监视和跟踪工具(例如Windows Sysinternals中的Process
Monitor)非常类似,Visual Studio 2010在应用程序执行时收集有关应用程序的数据,来帮助开发人员诊断错误。收集的数据称为IntelliTrace事件。这些事件将在默认调试过程中收集,此外,它们使开发人员能够进行回溯以查看应用程序中发生的情形,而不必重新启动调试器。
在本文中,我将向您介绍IntelliTrace,并演示它如何在开发人员的日常开发活动中体现出价值。我将演示IntelliTrace如何提供在应用程序执行过程中所发生事件的时间线,以及开发人员如何能够使用这些事件来帮助调试。接着,我将论述一些设置,开发人员可以更改这些设置来收集有关应用程序的一组更深层的信息,从而获得完整的执行历史记录。最后,我将演示如何使用其他人(测试人员)创建的以前记录的IntelliTrace文件来调试应用程序,而不必运行应用程序来重现错误。
当Visual Studio诊断团队开始规划Visual Studio 2010时,我们花费了很多时间与客户讨论,了解客户如何诊断其应用程序中的问题。尽管每个人都有不同的方式和喜欢使用的工具集,但有一点是绝对清楚的:传统的应用程序问题诊断方法困难、耗时而且成本高昂。开发人员收到的Bug报告几乎从没有任何用于重现问题的步骤,并且大部分都是由像"我正在使用程序,突然间程序崩溃了"这样的语句组成。即使在极个别的情况下提供了有效的重现步骤,也可能会在特定的环境中出现Bug,而这又会导致出现一组需要解决的全新问题。而且,Bug通常是由于误解了框架或其他代码的运行方式而导致的。
考虑到这些难题,我们着手创建了一个新的调试器功能,用于在问题发生时收集到正确的信息。我们的目标是为开发人员提供准确的重现步骤和系统环境设置,以及公开他们所使用的框架和代码的行为,从而大幅提高可诊断性。随着Visual Studio 2010 Ultimate的发布,IntelliTrace使开发人员能够更深入地了解应用程序和框架行为,并能够打开由测试人员收集的IntelliTrace文件来解决"无法重现"的情况,从而大大改善了调试体验。
IntelliTrace简介
当开发人员需要更深入地了解代码执行情况时,IntelliTrace提供了一种"加速调试"的方式来收集应用程序的完整执行历史记录。
为了阐释这一点,我将使用Tailspin Toys演示应用程序来演示IntelliTrace可收集的信息类型。首先,我将在Visual Studio中打开解决方案并启动调试。当网站启动时,我将导航到"关于我们"页,并收到来自服务器的错误。如何才能诊断问题?如果您像我一样,则您首先想到的是配置文件以不显示自定义错误,然后重新启动调试器。但如果此问题是间歇性的,又将如何呢?如果您可以在错误发生后就在此时进入进程,并从Visual Studio中获得应用程序中所发生情形的历史记录,是不是很好?
当您进行调试时,IntelliTrace将在后台收集有关托管应用程序的数据,其中包括来自许多框架组件(例如、和)的信息。这些IntelliTrace事件使开发人员能够查看先前在执行过程中发生的情况,并且最重要的是,能够进行"回溯"以查看应用程序的先前状态,而不必重新启动调试器。当我进入调试器时,我立即看到了按顺序列出的以前收集的IntelliTrace事件(请参见图1)。 图1 IntelliTrace收集的诊断信息
正如您可从图1中看到的,IntelliTrace事件的列表不仅仅局限于您在Process Monitor中看到的文件和注册表访问。我们为Visual Studio 2010定义了将近150个IntelliTrace事件,并计划随着时间的推移用其他事件扩充此列表。图2重点列出了一些IntelliTrace所收集事件的类别。
图2 IntelliTrace事件可跨 Framework使用
类别描述和收集的数据
与针对SQL执行查询、执行的命令以及连接字符串相关的事件。
MVC与管道以及请求处理和重定向相关的事件。
控制台控制台输出。
数据绑定Windows窗体数据绑定。
环境变量对进程中的环境变量进行求值和检索。
文件创建、删除和访问文件。
手势用户对Web窗体、Windows窗体和WPF中的常见控件执行的操作。除了收集有关与控件的交互的数据之外,单击其中一个事件还会自动将您重定向到相应的事件处理程序。
迟缓初始化初始化延迟加载的变量。
注册表创建、删除和查询注册表信息。
服务模型从WCF中进行的Web服务调用。
线程处理用户工作项和并行计算任务的排队。
跟踪调试器跟踪输出和断言。 用户提示显示Windows窗体和WPF消息框以及对话框的结果。
工作流实例化和完成活动。
XMLXML文件加载。
IntelliTrace窗口允许我按类别(图2中显示的类别)或按线程对所收集事件的列表进行筛选。此外,我可以执行基于文本的搜索来查找可快速跳转到的重要事件。由于IntelliTrace还会收集异常,因此我可以搜索词条"异常",列表将进行筛选以列出导致出现错误页的异常,既包括在其中引发的异常,也包括在其中捕获的异常。在本例中,错误是在分析位于第10行位置53的实体时由XMLException导致的(请参见图3)。当我单击引发的异常事件时,其他调试器窗口(例如"调用堆栈"和"监视"窗口)将显示与事件本身相关的数据,因此就好像引发异常时您正在进行调试一样。此外,就像进入调用堆栈一样,编辑器将打开相应的源文件,并以橙色突出显示与事件对应的代码行以表示IntelliTrace。
图3在分析位于第10行位置53上的实体时引发了XMLException
IntelliTrace为我提供了用于诊断问题的一段很有用的信息:加载了XML文件,而该XML文件中的特定字符为意外字符或不正确。但我仍然不知道访问了哪个文件。同样,IntelliTrace收集了我所需的信息(即文件访问)。
再次查看图3中的IntelliTrace窗口,我可以看到紧靠异常之前的事件是""的XML文件加载事件。此文件肯定是导致错误的文件。我可以轻松地在Visual Studio中打开此文件。查看第10行的位置53,我看到此文件中确实有一个错误,即"&b=1"对于NavigateUrl XML元素无效。通过删除这些无效字符,网站现在应可正常加载。
现在,我希望您考虑一下您用传统调试技术调试的上一个未处理异常。如果它是像这一样的异常,您将会看到异常的发生位置,但肯定看不到确切原因或无效字符。这就是IntelliTrace的关键所在–它为您提供了更好的信息来更快捷轻松地诊断问题。您有更重要的事情要做,而不是浪费时间来四处寻找信息。 使用IntelliTrace来跟踪调试器事件
我刚刚向您演示了IntelliTrace如何收集在应用程序的执行过程中发生的异常(已处理异常和未处理异常),以及如何通过跨框架的IntelliTrace事件来深入了解应用程序在后台执行的操作。但IntelliTrace的功能并非仅限于此。IntelliTrace还可收集调试器所导致的事件,即断点、跟踪点和单步执行事件。
最常见的调试技术之一是在您认为存在问题的位置附近设置断点,然后单步执行代码并监视变量变化。在调试循环步骤、监视变量变为特定值时,这一点特别有用。遗憾的是,大多数开发人员都没有耐心,并连续按F10键来快速单步执行代码,结果却发现他们单步执行过了头。然后,他们需要重新启动其调试会话并重试。利用IntelliTrace,将会记录所有断点和单步执行事件,以及这些事件的上下文数据,这样,您就能够快速导航到之前停止的位置。
如果我单击其中一个调试器事件,"监视"窗口将显示我之前查看的所有数据,其中包括我在"局部变量"、"监视"和"自动变量"窗口中计算的值,以及"快速监视"和"数据提示"。
通常,以前开发和部署的代码没有内置所需的跟踪来帮助调试可能出现的问题。利用断点,可以详细了解应用程序在后台所执行的操作。但大多数情况下,开发人员不需要在断点处停止;而是希望收集某些数据并继续执行。在您希望记录迭代器值而不必在每个迭代处停止的循环内,情况尤为如此。在这些情况下,跟踪点是绝佳的替代方案。利用跟踪点,开发人员能够让调试器执行自定义操作;也就是说,执行宏或输出跟踪消息,而不是中断执行。利用IntelliTrace,将会收集跟踪点输出,并可在与其他IntelliTrace事件同样的界面中查看这些输出(请参见图4)。
图4跟踪点可向代码中动态添加跟踪输出
加速调试
默认情况下,IntelliTrace配置为仅收集IntelliTrace事件。此解决方案开销很低,但不会提供应用程序的完整执行历史记录。如果您需要更深层的信息,则可以配置IntelliTrace来收集更多数据。像其他调试器设置一样,IntelliTrace也可通过"选项"对话框(可从"工具"菜单中访问)进行配置(请参见图5)。
图5可通过"选项"对话框更改IntelliTrace设置
通过选择"IntelliTrace事件和调用信息",可将IntelliTrace配置为不仅收集IntelliTrace事件,而且在每个方法进入、退出和调用站点时收集调用信息,例如位于这些位置的参数和返回值。遗憾的是,启用此模式会导致"编辑并继续"在调试会话过程被禁用。很明显,您选择收集更多信息意味着应用程序的开销更高。我们致力于找到有用的信息和性能之间的平衡点,但我们将完全控制权给予您。
每个调试会话都会创建一个存储在磁盘上的IntelliTrace文件,当Visual Studio关闭时,将会自动清理该文件。利用IntelliTrace的"高级"窗格(通过"选项"对话框访问),您可以配置要将在调试过程中创建的文件存储在何处,以及这些文件的最大文件大小。如果达到最大文件大小,则会使用一个循环缓冲区来帮助压缩和截断存储在IntelliTrace日志中的信息,从而减小日志文件在磁盘上占用的空间。利用"高级"窗格上的两项其他设置,您可以隐藏导航装订线,并禁用可用符号的Team Foundation Server(TFS)查找。
由于存在性能问题,因此默认情况下只会为集合启用定义的IntelliTrace事件的一个子集。您可能需要考虑启用的某些事件包括控制台输出、文件访问、迟缓初始化、注册表访问以及线程处理事件。您可以从"选项"对话框的"IntelliTrace事件"窗格中启用或禁用整个事件类别或个别事件。
最后一个IntelliTrace"选项"窗格允许您控制IntelliTrace从哪些模块中收集数据。默认情况下,将会收集除Microsoft作为
Framework和Visual Studio一部分提供的模块之外的所有其他模块。采用这种方式收集到的数据可能非常多,因此您可以考虑将此列表更改为一个包含列表,并仅指定您关注的模块。相反,如果您使用某些常见的第三方库,则可能希望排除这些模块,因为它们超出了您的控制范围。
调查用户代码错误 现在,我已验证了"关于我们"页在演示应用程序中可正常工作,让我们确保购物车同样也工作正常。当我将一架纸飞机添加到购物车进行购买时,我看到它确实已正常添加到购物车。但是,当我重复此操作将该物品的第二个实例添加到购物车时,数量仍然显示为1,然而我预计数量会显示为2。我希望使用调试器来解决问题而无需重新启动,但IntelliTrace事件的列表在这种情况下可能无助于事(所有工作都是在我的代码而不是.NET Framework中完成的)。在这里,IntelliTrace的"IntelliTrace事件和调用信息"模式可以帮助显示我的应用程序的执行历史记录。让我们进入调试器,看看我可以使用IntelliTrace的哪些其他功能来解决此问题。
我首先假设我的"将物品添加到购物车"逻辑出现了问题。由于此应用程序是一个模型-视图-控制器(MVC)应用程序,因此没有用于按钮单击的事件处理程序,而是会发送一个POST消息并由MVC处理。此POST消息已记录为一个IntelliTrace事件,并且,尽管该事件本身没有作用,但我使用它作为起点来进行调查。通过单击此IntelliTrace事件,我可以跳转到调试会话中"添加物品"逻辑的开始位置。通过在IntelliTrace窗口中搜索单词"POST",我可以快速找到这些POST消息。用户进行了此操作两次,因此,不出所料,搜索返回了两个结果。选择第二个事件之后,如果清除搜索字段,则会在包含所有已收集事件的上下文中显示该事件(请参见图6)。
图6"IntelliTrace事件"视图可帮助您开始进行调查
既然我有了有关我处于应用程序时间线的何处的上下文,那么我希望进一步深入了解所进行的方法调用。从"事件"视图中,我可以切换视图以查看执行历史记录。通过单击窗口顶部的"切换到IntelliTrace调用视图"链接,我可以转换到"调用"视图以查看应用程序的完整执行历史记录(请参见图7)。我可以随时通过单击"切换到IntelliTrace事件视图"链接返回到"事件"视图。
图7 IntelliTrace的"调用"视图显示应用程序的执行历史记录
用于浏览执行历史记录的一种机制是使用"调用"视图深入了解您在调查时感兴趣的调用。每次双击"调用"视图下半部分中的某个调用时,该调用将弹出到视图的上半部分,并且指令指针将在代码编辑器中与调用的方法入口点同步,就像您进入调用堆栈时的实时调试一样。您可以继续导航,并采用这种方式在IntelliTrace历史记录收集的数据中向后和向前浏览。通过浏览"调用"视图这种机制,可以快速了解执行历史记录的概况,并在代码库中进行大幅跳转。
使用"调用"视图是唯一的导航方法。我还可以通过单步执行代码来进行导航。在源代码窗口的装订线中,有一组新的DVR样式的控件,您可以利用这些控件来单步执行代码,就像在传统的调试会话中一样(请参见图8)。由于我处于IntelliTrace调试模式中,因此单步执行由在每次调用站点、函数进入或函数退出时发生的事件记录。当然,如果您喜欢使用键盘控制,F10/F11也可按预期方式工作。
图8导航栏提供了DVR样式的控件,使您能够单步执行应用程序
这两种导航方法非常适合于调查,但有时您确切知道将在何处设置断点。对于此应用程序,我知道将物品添加到购物车的函数的名称:ngCart:AddItem。我真正要做的是跳转到第二次调用此函数的位置,并检查传入函数和从函数返回的值。更具体地说,我希望搜寻进行"AdjustQuantity"函数调用的代码行。当然,IntelliTrace也支持这种导航技术。
在编辑器中,我可以右键单击要搜寻的行,并从上下文菜单中选择"在IntelliTrace中搜索此行"(请参见图9)。搜索将开始,并且结果将呈现在编辑器窗口顶部的搜索栏中,从而使我能够在搜索结果之间导航。与第二个搜索结果同步后,我的指令指针恰好位于我希望的位置,并且我可以使用其他调试器窗口来调查调用(请参见图10)。
图9搜索功能使我能够恰好跳转到特定的函数调用
图10搜索结果显示在编辑器窗口顶部的搜索结果栏中
此时查看"局部变量"窗口,您可以看到购物车正在被调整,以使购物车中产品的新数量为1。这是Bug;我预期的调整后的数量为2。查看代码行,新的Quantity参数不仅应考虑"ty",而且应考虑传入函数调用的"quantity"变量。解决方法是将函数调用更改为: 复制代码AdjustQuantity(product,ty+quantity);消除令人生畏的"无法重现"情况
测试人员和开发人员经常会遇到"无法重现"情形,在这种情形中,测试人员会提交指出发生了某种错误的Bug,最终又归结于一句注解"它没有在我的计算机上重现"。开发人员和测试人员都不想遇到这种情形,但他们没有适当的工具集来帮助他们传达出现故障时所发生的情况。我们之所以将系统设计为IntelliTrace在调试会话期间向开发人员提供的诊断信息与通过Microsoft
Test Manager(MTM)执行手动测试时可收集的诊断信息相同,这就是原因所在。
让我们重新探讨我调试的第一个情况,即"关于我们"页未能正常呈现的情况。如果测试人员提交了此Bug,它的标题将可能是诸如"查看关于页时发生应用程序错误"之类的标题,或许,如果开发人员幸运的话,还会附上错误的屏幕截图。如果您当前收到像这样的Bug,可能会如何对其进行调试?您很有可能会从源代码管理中加载应用程序的解决方案,并在您的开发人员计算机上重现问题。在本例中,您将能够调试和解决问题,但想一想这种方法花费了多少时间。或者,如果问题是由您的计算机和测试人员的计算机之间的配置不同导致的,又该怎么办?就工作效率而言,开发人员在调试问题时的工作效率要比建立重现环境时高得多。
利用Visual Studio 2010,MTM使测试人员能够方便地创作、管理和执行手动测试和自动测试。但该工具的功能并非仅限于此。MTM使测试人员能够让诊断数据适配器在测试执行的同时在后台收集信息。例如,您可以自动收集所执行测试的录像,以便开发人员能够看到与测试人员完全相同的情形。其他收集器能够从所测试的框架中收集系统信息和事件日志。
我们增加了IntelliTrace诊断数据适配器,以便自动在后台收集IntelliTrace文件。当测试人员的某个测试步骤失败并选择提交Bug时,收集的IntelliTrace文件将自动上载到TFS并链接到该Bug。这样将可为开发人员提供一组更为丰富的用于调试的信息,而不仅仅是一组重现步骤。当开发人员打开链接到Bug的IntelliTrace文件时,他将体验到与调试小型转储类似的感觉,但却是有关整个应用程序时间线的转储,而不仅仅是应用程序崩溃时的转储。可以为本地或远程测试代理上的任何托管应用程序(包括运行于IIS下的应用程序)收集IntelliTrace数据。
当我打开TFS Bug时,MTM已根据测试人员描述的手动测试步骤自动添加了重现步骤。更酷的是,如果我查看Bug的"所有链接"选项卡(请参见图11),我可以看到同时收集的IntelliTrace文件。通过双击此文件,我将看到IntelliTrace文件的摘要页视图(请参见图12)。
图11可通过"所有链接"选项卡访问收集的IntelliTrace文件
图12 IntelliTrace摘要提供了所收集数据的概览
摘要页为我提供了许多有关IntelliTrace文件所包含内容的信息。在该页的顶部,我可以看到应用程序中各个线程的时间线视图。如果我展开摘要页的"线程列表"部分,我可以看到以表格格式显示的相同数据。如果双击某个线程,将会从IntelliTrace文件中启动调试会话,并将我的指令指针置于该线程的开头。
我还将在IntelliTrace文件中看到收集的所有异常的列表。如果我选择某个异常,线程时间线上将出现一条橙色竖线,显示异常发生的时间点。如果双击某个异常,将会启动IntelliTrace调试会话,并且将在"IntelliTrace事件"视图中选择异常事件。在摘要页上进一步向下看,我可以看到与手动重现步骤匹配的所有测试事件的列表。还会显示每个步骤的结果。单击其中某个事件也会向线程时间线上放置一条竖线,而双击事件将会启动IntelliTrace调试会话,同时选择尽可能最近的事件。摘要页的底部显示收集的有关计算机(测试的应用程序在该计算机上运行)的系统信息的列表,该列表下面列出了加载到进程中的所有模块及其文件路径。
您可能会问自己,它是否适合于发布版?当然可以!此外,在收集或查看IntelliTrace数据时,您无需访问符号。符号只有在将收集的数据链接到源文件时才是必要的,以便它们在您打开调试会话时有所帮助。
Visual Studio 2010和TFS还增加了对符号和源服务器的支持,因此,如果您的应用程序是作为TFS生成系统的一部分生成的,则会按照IntelliTrace的需要自动从TFS下载正确版本的符号和源代码。您甚至不必知道符号服务器路径。
从摘要页中启动调试会话后,调试器的工作方式就好像实时调试会话一样(请参见图13)。您可以使用大多数调试器窗口,并可以导航到IntelliTrace收集的任何数据。
图13当调试从摘要页中启动时,Visual Studio的运行方式就像实时调试会话一样
总结
在本文中,您了解了IntelliTrace如何能够大幅改善您的日常开发活动,并提升您快速轻松诊断问题的能力,而不必重新启动应用程序和使用传统的"中断-单步执行-检查"技术进行调试。我还向您介绍了组织如何能够通过在测试过程中收集IntelliTrace数据来减少"无法重现"的Bug数,从而使开发人员能够脱机调试问题,而无需访问实时重现。这只是功能的简要介绍,当您越来越熟悉IntelliTrace的强大功能时,它将开始改变您的调试方式。
Justin Marks在麻省理工学院获得计算机科学与工程学士学位后,于2002年加入Microsoft。他作为系统工程师参与过的开发工作,作为测试软件设计工程师参与过Windows的开发工作,现在作为项目经理参与Visual
Studio的开发工作。作为诊断团队的项目经理,Marks一直参与开发Visual
Studio 2010下一版本的IntelliTrace功能。
衷心感谢以下技术专家,感谢他们审阅了本文:Bill Boris、David Gray、Habib Heydarian和John Robbins
作者:Brave Heart发表于2010-12-22 23:51原文链接
评论:0查看评论发表评论
最新新闻: ·10大最适合编程的字体推荐下载,让代码看起来更美更舒服!(2010-12-25 23:12)
·Erbix:适合CommonJS的服务端JavaScript托管平台(2010-12-25 23:09)
·外媒评Google 2010年十大是非:Android大获全胜(2010-12-25 22:15)
·网易创始人丁磊:这十年很纠结(2010-12-25 22:14)
·五角大楼研制超强3D眼镜(2010-12-25 21:31)
编辑推荐:Tangram前端库通过Github开源了
网站导航:博客园首页我的园子新闻闪存小组博问知识库
特别声明:
1:资料来源于互联网,版权归属原作者
2:资料内容属于网络意见,与本账号立场无关
3:如有侵权,请告知,立即删除。
发布评论