.NET 應用程式中的記錄和追蹤

已完成

當您繼續開發應用程式而使其變得越來越複雜時,您會想要對應用程式套用額外的偵錯診斷。

追蹤是一種方式,可讓您在應用程式執行時監視其執行狀況。 您可以在開發 .NET 應用程式時,將追蹤和偵錯檢測功能新增至您的 .NET 應用程式。 您可以在開發應用程式時,以及在部署之後使用該檢測。

這種簡單的技術出奇的強大。 您可將其用於需要除了偵錯工具外之其他功能的情況:

  • 長時間出現的問題,可能很難利用傳統的偵錯工具進行偵錯。 記錄可讓您進行長時間的詳盡事後檢討。 相反地,偵錯工具受限於即時分析。
  • 多執行緒應用程式與分散式應用程式通常很難偵錯。 連結偵錯工具往往會修改行為。 您可以視需要分析詳細的記錄,以了解複雜的系統。
  • 分散式應用程式中的問題可能是因為許多元件之間複雜的互動所引起。 將偵錯工具連接到系統的每個部分可能並不合理。
  • 許多服務都不應該停止。 連結偵錯工具通常會導致逾時失敗。
  • 問題不一定可以預見。 記錄和追蹤是針對低額外負荷而設計,因此,在發生問題時,程式一律會進行記錄。

將資訊寫入到輸出視窗

到目前為止,我們一直使用主控台來向應用程式使用者顯示資訊。 還有以 .NET 建置的其他類型應用程式,這類應用程式包含使用者介面 (例如,行動、Web 與傳統型應用程式),而且沒有任何可見的主控台。 在這些應用程式中,System.Console 會「在幕後」記錄訊息。這些訊息可能會顯示在 Visual Studio 或 Visual Studio Code 的輸出視窗中。 其可能也會輸出到系統記錄檔,例如 Android 的 logcat。 因此,當您在非主控台應用程式中使用 System.Console.WriteLine 時,應該謹慎考慮清楚。

您可在此處除了 System.Console 之外,還使用 System.Diagnostics.DebugSystem.Diagnostics.TraceDebugTrace 都屬於 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 項目來加以控制。 以下範例會針對 DebugRelease 設定開啟 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

條件式追蹤

除了簡單的 WriteWriteLine 方法,還能使用 WriteIfWriteLineIf 來新增條件。 例如,下列邏輯會檢查計數是否為零,然後寫入偵錯訊息:

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 命名空間中的 DebugTrace 使用 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 命名空間的 DebugTrace,是在執行應用程式及對其進行偵錯時提供額外內容的絕佳方式。