.NET 應用程式中的記錄和追蹤
當您繼續開發應用程式而使其變得越來越複雜時,您會想要對應用程式套用額外的偵錯診斷。
追蹤是一種在應用程式運行時監控其執行狀態的方法。 您可以在開發 .NET 應用程式時,將追蹤和偵錯檢測功能新增至您的 .NET 應用程式。 您可以在開發應用程式時,以及在部署之後使用該檢測。
這種簡單的技術出奇的強大。 您可以在需要比除錯程式更多功能的情況使用它:
- 長時間出現的問題,可能很難利用傳統的偵錯工具進行偵錯。 記錄允許進行涵蓋長時間範圍的詳細事後檢討。 相反地,偵錯工具受限於即時分析。
- 多執行緒應用程式與分散式應用程式通常很難偵錯。 連結偵錯工具往往會修改行為。 您可以視需要分析詳細的記錄,以了解複雜的系統。
- 分散式應用程式中的問題可能是因為許多元件之間複雜的互動所引起。 將偵錯工具連接到系統的每個部分可能並不合理。
- 許多服務都不應該停止。 連結偵錯工具通常會導致逾時失敗。
- 問題不一定可以預見。 記錄和追蹤是針對低額外負荷而設計,因此,在發生問題時,程式一律會進行記錄。
將資訊寫入到輸出視窗
到目前為止,我們一直使用主控台來向應用程式使用者顯示資訊。 使用 .NET 建置的其他類型應用程式具有使用者介面,例如行動裝置、Web 和桌面應用程式,而且沒有可見的控制台。 在這些應用程式中, System.Console 記錄「幕後」的訊息。這些訊息可能會顯示在 Visual Studio 或 Visual Studio Code 的輸出視窗中。 其可能也會輸出到系統記錄檔,例如 Android 的 logcat。 因此,當您在非主控台應用程式中使用 System.Console.WriteLine 時,應該謹慎考慮清楚。
您可在此處除了 System.Console 之外,還使用 System.Diagnostics.Debug 與 System.Diagnostics.Trace。 Debug 與 Trace 都屬於 System.Diagnostics,而且只有在連結適當的接聽程式時,才會寫入到記錄。
選擇要使用的列印樣式 API 完全取決於您。 主要差異包括:
- System.Console
- 一律啟用且一律寫入到主控台。
- 適用於客戶可能需要在發行版本中看到的資訊。
- 因為這是最簡單的方法,所以通常用於進行臨機操作的暫時性偵錯。 此偵錯程式碼通常絕對不會簽入到原始程式碼控制。
- System.Diagnostics.Trace
- 只有在定義
TRACE時才會啟用。 - 寫入到已連結的接聽程式,預設為 DefaultTraceListener。
- 在建立將在大部分組建中啟用的記錄時,請使用此 API。
- 只有在定義
- System.Diagnostics.Debug
- 只有在已定義
DEBUG時才會啟用 (在偵錯模式中)。 - 寫入到已連結的偵錯工具。
- 在建立將只在偵錯組建中啟用的記錄時,請使用此 API。
- 只有在已定義
Console.WriteLine("This message is readable by the end user.");
Trace.WriteLine("This is a trace message when tracing the app.");
Debug.WriteLine("This is a debug message just for developers.");
當您設計追蹤和偵錯策略時,請考慮您想要什麼樣的輸出。 填入不相關信息的多個 Write 語句會建立難以讀取的記錄。 相反地,若使用 WriteLine 將相關的陳述式置於不同行,可能造成難以區別哪些資訊有所關聯。 一般而言,當您想要結合多個來源的資訊來建立單一資訊訊息時,請使用多個 Write 陳述式。 當您想要建立單一完整訊息時,請使用 WriteLine 陳述式。
Debug.Write("Debug - ");
Debug.WriteLine("This is a full line.");
Debug.WriteLine("This is another full line.");
此輸出來自先前使用 Debug 的記錄:
Debug - This is a full line.
This is another full line.
定義 TRACE 和 DEBUG 常數
根據預設,當應用程式在偵錯期間執行時,會定義 DEBUG 常數。 您可透過在屬性群組的專案檔中新增 DefineConstants 項目來加以控制。 以下範例會針對 Debug 與 Release 設定開啟 TRACE,以及針對 Debug 設定開啟 DEBUG。
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
當您在未附加至調試程式時使用 Trace 時,您必須設定追蹤接聽程式,例如 dotnet-trace。
條件式追蹤
除了簡單的 Write 與 WriteLine 方法,還能使用 WriteIf 與 WriteLineIf 來新增條件。 例如,下列邏輯會檢查計數是否為零,然後寫入偵錯訊息:
if(count == 0)
{
Debug.WriteLine("The count is 0 and this may cause an exception.");
}
您可以在單行程式代碼中重寫此內容:
Debug.WriteLineIf(count == 0, "The count is 0 and this may cause an exception.");
您也可以搭配 Trace 與您在應用程式中定義的旗標來使用這些條件:
bool errorFlag = false;
System.Diagnostics.Trace.WriteIf(errorFlag, "Error in AppendData procedure.");
System.Diagnostics.Debug.WriteIf(errorFlag, "Transaction abandoned.");
System.Diagnostics.Trace.Write("Invalid value for data request");
確認特定條件是否存在
判斷提示 (或 Assert 陳述式) 會測試您指定為 Assert 陳述式之引數的條件。 如果條件評估為 true,則不會發生任何動作。 如果條件評估為 false,則斷言失敗。 如果您是使用偵錯組建執行,您的程式會進入中斷模式。
您可以從 System.Diagnostics 命名空間中的 Debug 或 Trace 使用 Assert 方法。 Debug 類別方法未包含在程式的發行版本中,因此不會增加發行程式碼的大小或減緩其速度。
隨意使用 System.Diagnostics.Debug.Assert 方法,來測試在您程式碼正確的情況下應保留 True 的條件。 例如,假設您已撰寫整數除法函式。 根據數學的規則,除數不得為零。 您可以使用判斷提示來測試此條件:
int IntegerDivide(int dividend, int divisor)
{
Debug.Assert(divisor != 0, $"{nameof(divisor)} is 0 and will cause an exception.");
return dividend / divisor;
}
當您在偵錯工具下執行此程式碼時,會評估判斷提示陳述式。 不過,不會在發行版本中進行比較,因此不會有額外的額外負荷。
備註
當您使用 System.Diagnostics.Debug.Assert 時,請確定在移除了判斷提示時,Assert 中的任何程式碼都不會變更程式的結果。 否則,您可能會不小心引進了只會出現在程式發行版本中的錯誤 (Bug)。 特別注意包含函式或程序呼叫的判斷提示。
當您執行和偵錯應用程式時,從 System.Diagnostics 命名空間使用 Debug 和 Trace 是提供額外背景資訊的絕佳方式。