| IntelliTrace使用 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 中開啟解決方案並啟動調試。當網站啟動時,我將導航到“關於我們”頁,並收到來自伺服器的錯誤。如何才能診斷問題?如果您像我一樣,則您首先想到的是配置 web.config 檔案以不顯示自訂錯誤,然後重新啟動調試器。但如果此問題是間歇性的,又將如何呢?如果您可以在錯誤發生後就在此時進入進程,並從 Visual Studio 中獲得應用程式中所發生情形的記錄,是不是很好? 當您進行調試時,IntelliTrace 將在後台收集有關託管應用程式的資料,其中包括來自許多架構組件(例如 ADO.NET、ASP.NET 和 System.XML)的資訊。這些 IntelliTrace 事件使開發人員能夠查看先前在執行過程中發生的情況,並且最重要的是,能夠進行“回溯”以查看應用程式的先前狀態,而不必重新啟動調試器。當我進入調試器時,我立即看到了按順序列出的以前收集的 IntelliTrace 事件(請參見圖 1)。 圖 1 IntelliTrace 收集的診斷資訊 正如您可從圖 1 中看到的,IntelliTrace 事件的列表不僅僅局限於您在 Process Monitor 中看到的檔案和註冊表訪問。我們為 Visual Studio 2010 定義了將近 150 個 IntelliTrace 事件,並計劃隨著時間的推移用其他事件擴充此列表。圖 2 重點列出了一些 IntelliTrace 所收集事件的類別。 圖 2 IntelliTrace 事件可跨 Microsoft .NET Framework 使用
| 類別 |
描述和收集的資料 |
| ADO.NET |
與針對 SQL 執行查詢、執行的命令以及連接字串相關的事件。 |
| MVC |
與 ASP.NET 管道以及請求處理和重新導向相關的事件。 |
| 控制台 |
控制台輸出。 |
| 資料繫結 |
Windows 表單資料繫結。 |
| 環境變數 |
對進程中的環境變數進行求值和檢索。 |
| 檔案 |
建立、刪除和訪問檔案。 |
| 手勢 |
使用者對 Web Form、Windows 表單和 WPF 中的常見控制項執行的操作。除了收集有關與控制項的互動的資料之外,單擊其中一個事件還會自動將您重新導向到相應的事件處理常式。 |
| 延遲初始設定 |
初始化消極式載入的變數。 |
| 註冊表 |
建立、刪除和查詢註冊表資訊。 |
| 服務模型 |
從 WCF 中進行的 Web 服務調用。 |
| 線程處理 |
使用者工作項目和並行計算任務的排隊。 |
| 跟蹤 |
調試器跟蹤輸出和斷言。 |
| 使用者提示 |
顯示 Windows 表單和 WPF 訊息框以及對話方塊的結果。 |
| 工作流程 |
執行個體化和完成活動。 |
| XML |
XML 檔案載入。 |
IntelliTrace 視窗允許我按類別(圖 2 中顯示的類別)或按線程對所收集事件的列表進行篩選。此外,我可以執行基於文本的搜尋來尋找可快速跳轉到的重要事件。由於 IntelliTrace 還會收集異常,因此我可以搜尋字詞條“異常”,列表將進行篩選以列出導致出現 ASP.NET 錯誤頁的異常,既包括在其中引發的異常,也包括在其中捕獲的異常。在本例中,錯誤是在分析位於第 10 行位置 53 的實體時由 XMLException 導致的(請參見圖 3)。當我單擊引發的例外狀況事件時,其他調試器視窗(例如“呼叫堆疊”和“監視”視窗)將顯示與事件本身相關的資料,因此就好像引發異常時您進行中調試一樣。此外,就像進入呼叫堆疊一樣,編輯器將開啟相應的源檔案,並以橙色反白與事件對應的程式碼以表示 IntelliTrace。 圖 3 在分析位於第 10 行位置 53 上的實體時引發了 XMLException IntelliTrace 為我提供了用於診斷問題的一段很有用的資訊:載入了 XML 檔案,而該 XML 檔案中的特定字元為意外字元或不正確。但我仍然不知道訪問了哪個檔案。同樣,IntelliTrace 收集了我所需的資訊(即檔案訪問)。 再次查看圖 3 中的 IntelliTrace 視窗,我可以看到緊靠異常之前的事件是“Content\Xml\Ads.xml”的 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 作為 Microsoft .NET Framework 和 Visual Studio 一部分提供的模組之外的所有其他模組。採用這種方式收集到的資料可能非常多,因此您可以考慮將此列表更改為一個包含列表,並僅指定您關注的模組。相反,如果您使用某些常見的第三方庫,則可能希望排除這些模組,因為它們超出了您的控制範圍。 調查使用者代碼錯誤現在,我已驗證了“關於我們”頁在示範應用程式中可正常工作,讓我們確保購物車同樣也工作正常。當我將一架紙飛機添加到購物車進行購買時,我看到它確實已正常添加到購物車。但是,當我重複此操作將該物品的第二個執行個體添加到購物車時,數量仍然顯示為 1,然而我預計數量會顯示為 2。我希望使用調試器來解決問題而無需重新啟動,但 IntelliTrace 事件的列表在這種情況下可能無助於事(所有工作都是在My Code而不是 .NET Framework 中完成的)。在這裡,IntelliTrace 的“IntelliTrace 事件和調用資訊”模式可以協助顯示我的應用程式的執行記錄。讓我們進入調試器,看看我可以使用 IntelliTrace 的哪些其他功能來解決此問題。 我首先假設我的“將物品添加到購物車”邏輯出現了問題。由於此應用程式是一個模型-視圖-控制器 (MVC) 應用程式,因此沒有用於按鈕單擊的事件處理常式,而是會發送一個 POST 訊息並由 MVC 處理。此 POST 訊息已記錄為一個 IntelliTrace 事件,並且,儘管該事件本身沒有作用,但我使用它作為起點來進行調查。通過單擊此 IntelliTrace 事件,我可以跳轉到偵錯工作階段中“添加物品”邏輯的開始位置。通過在 IntelliTrace 視窗中搜尋單詞“POST”,我可以快速找到這些 POST 訊息。使用者進行了此操作兩次,因此,不出所料,搜尋返回了兩個結果。選擇第二個事件之後,如果清除搜尋欄位,則會在包含所有已收集事件的上下文中顯示該事件(請參見圖 6)。 圖 6 “IntelliTrace 事件”視圖可協助您開始進行調查 既然我有了有關我處於應用時間線的何處的上下文,那麼我希望進一步深入瞭解所進行的方法調用。從“事件”視圖中,我可以切換視圖以查看執行記錄。通過單擊視窗頂部的“切換到 IntelliTrace 調用視圖”連結,我可以轉換到“調用”視圖以查看應用程式的完整執行記錄(請參見圖 7)。我可以隨時通過單擊“切換到 IntelliTrace 事件檢視”連結返回到“事件”視圖。 圖 7 IntelliTrace 的“調用”視圖顯示應用程式的執行記錄 用於瀏覽執行記錄的一種機制是使用“調用”視圖深入瞭解您在調查時感興趣的調用。每次雙擊“調用”視圖下半部分中的某個調用時,該調用將彈出到視圖的上半部分,並且指令指標將在代碼編輯器中與調用的方法進入點同步,就像您進入呼叫堆疊時的Just-in-Time 偵錯一樣。您可以繼續導航,並採用這種方式在 IntelliTrace 記錄收集的資料中向後和向前瀏覽。通過瀏覽“調用”視圖這種機制,可以快速瞭解執行記錄的概況,並在程式碼程式庫中進行大幅跳轉。 使用“調用”視圖是唯一的導航方法。我還可以通過逐步執行代碼來進行導航。在原始碼視窗的裝訂邊中,有一組新的 DVR 樣式的控制項,您可以利用這些控制項來逐步執行代碼,就像在傳統的偵錯工作階段中一樣(請參見圖 8)。由於我處於 IntelliTrace 偵錯模式中,因此逐步執行由在每次調用網站、函數進入或函數退出時發生的事件記錄。當然,如果您喜歡使用鍵盤控制,F10/F11 也可按預期方式工作。 圖 8 導覽列提供了 DVR 樣式的控制項,使您能夠逐步執行應用程式 這兩種導航方法非常適合於調查,但有時您確切知道將在何處設定斷點。對於此應用程式,我知道將物品添加到購物車的函數的名稱:Kona.Model.ShoppingCart::AddItem。我真正要做的是跳轉到第二次調用此函數的位置,並檢查傳入函數和從函數返回的值。更具體地說,我希望搜尋進行“AdjustQuantity”函數調用的程式碼。當然,IntelliTrace 也支援這種導航技術。 在編輯器中,我可以按右鍵要搜尋的行,並從操作功能表中選擇“在 IntelliTrace 中搜尋此行”(請參見圖 9)。搜尋將開始,並且結果將呈現在編輯器視窗頂部的搜尋欄中,從而使我能夠在搜尋結果之間導航。與第二個搜尋結果同步後,我的指令指標恰好位於我希望的位置,並且我可以使用其他調試器視窗來調查調用(請參見圖 10)。 圖 9 搜尋功能使我能夠恰好跳轉到特定的函數調用 圖 10 搜尋結果顯示在編輯器視窗頂部的搜尋結果欄中 此時查看“局部變數”視窗,您可以看到購物車正在被調整,以使購物車中產品的新數量為 1。這是 Bug;我預期的調整後的數量為 2。查看程式碼,新的 Quantity 參數不僅應考慮“item.Quantity”,而且應考慮傳入函數調用的“quantity”變數。解決方案是將函數調用更改為: 複製代碼 AdjustQuantity(product, item.Quantity + quantity); 消除令人生畏的“無法重現”情況測試人員和開發人員經常會遇到“無法重現”情形,在這種情形中,測試人員會提交指出發生了某種錯誤的 Bug,最終又歸結於一句註解“它沒有在我的電腦上重現”。開發人員和測試人員都不想遇到這種情形,但他們沒有適當的工具集來協助他們傳達出現故障時所發生的情況。我們之所以將系統設計為 IntelliTrace 在偵錯工作階段期間向開發人員提供的診斷資訊與通過 Microsoft Test Manager (MTM) 執行手動測試時可收集的診斷資訊相同,這就是原因所在。 讓我們重新探討我調試的第一個情況,即“關於我們”頁未能正常呈現的情況。如果測試人員提交了此 Bug,它的標題將可能是諸如“查看關於頁時發生應用程式錯誤”之類的標題,或許,如果開發人員幸運的話,還會附上錯誤的螢幕。如果您當前收到像這樣的 Bug,可能會如何對其進行調試?您很有可能會從原始程式碼控制中載入應用程式的解決方案,並在您的開發人員電腦上重現問題。在本例中,您將能夠調試和解決問題,但想一想這種方法花費了多少時間。或者,如果問題是由您的電腦和測試人員的電腦之間的配置不同導致的,又該怎麼辦?就工作效率而言,開發人員在調試問題時的工作效率要比建立重現環境時高得多。 利用 Visual Studio 2010,MTM 使測試人員能夠方便地創作、管理和執行手動測試和自動化的測試。但該工具的功能並非僅限於此。MTM 使測試人員能夠讓診斷資料配接器在測試執行的同時在後台收集資訊。例如,您可以自動收集所執行測試的錄影,以便開發人員能夠看到與測試人員完全相同的情形。其他收集器能夠從所測試的架構中收集系統資訊和事件記錄。 我們增加了 IntelliTrace 診斷資料配接器,以便自動在後台收集 IntelliTrace 檔案。當測試人員的某個測試步驟失敗並選擇提交 Bug 時,收集的 IntelliTrace 檔案將自動上傳到 TFS 並連結到該 Bug。這樣將可為開發人員提供一組更為豐富的用於調試的資訊,而不僅僅是一組重現步驟。當開發人員開啟連結到 Bug 的 IntelliTrace 檔案時,他將體驗到與調試小型傾印類似的感覺,但卻是有關整個應用時間線的轉儲,而不僅僅是應用程式崩潰時的轉儲。可以為本地或遠程測試代理程式上的任何託管應用程式(包括運行於 IIS 下的 ASP.NET 應用程式)收集 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 下載正確版本的符號和原始碼。您甚至不必知道符號伺服器路徑。 從摘要頁中啟動偵錯工作階段後,調試器的工作方式就好像Just-in-Time 偵錯會話一樣(請參見圖 13)。您可以使用大多數調試器視窗,並可以導航到 IntelliTrace 收集的任何資料。 圖 13 當調試從摘要頁中啟動時,Visual Studio 的運行方式就像Just-in-Time 偵錯會話一樣 總結在本文中,您瞭解了 IntelliTrace 如何能夠大幅改善您的日常開發活動,並提升您快速輕鬆診斷問題的能力,而不必重新啟動應用程式和使用傳統的“中斷-逐步執行-檢查”技術進行調試。我還向您介紹了組織如何能夠通過在測試過程中收集 IntelliTrace 資料來減少“無法重現”的 Bug 數,從而使開發人員能夠離線調試問題,而無需訪問即時重現。這隻是功能的簡要介紹,當您越來越熟悉 IntelliTrace 的強大功能時,它將開始改變您的調試方式。 Justin Marks 在麻省理工學院獲得電腦科學與工程學士學位後,於 2002 年加入 Microsoft。他作為系統工程師參與過 MSN.com 的開發工作,作為測試軟體設計工程師參與過 Windows 的開發工作,現在作為專案經理參與 Visual Studio 的開發工作。作為診斷團隊的專案經理,Marks 一直參與開發 Visual Studio 2010 下一版本的 IntelliTrace 功能。 衷心感謝以下技術專家,感謝他們審閱了本文:Bill Boris、David Gray、Habib Heydarian 和 John Robbins |