.NET アプリケーションでのログとトレース

完了

アプリケーションの開発を続けて複雑さが増した場合、追加のデバッグ診断をアプリケーションに適用することが必要になります。

トレースは、実行中にアプリケーションの実行を監視するための手段です。 トレースとデバッグのインストルメンテーションは、開発時に .NET アプリケーションに追加できます。 アプリケーションの開発中と配置後に、そのインストルメンテーションを使用できます。

この単純な手法は、驚くほど強力です。 デバッガーを超えるものが必要な状況でこれを使用できます。

  • 長期間にわたって発生する問題は、従来のデバッガーではデバッグが難しい場合があります。 ログを使用すると、長期間にわたる詳細な事後レビューを行うことができます。 これに対し、デバッガーはリアルタイム分析に制約されます。
  • 多くの場合、マルチスレッド アプリケーションと分散アプリケーションはデバッグが困難です。 デバッガーをアタッチすると、動作が変更される傾向があります。 複雑なシステムを理解するために、必要に応じて詳細なログを分析できます。
  • 分散アプリケーションの問題は、多くのコンポーネント間の複雑な相互作用から生じることがあります。 デバッガーをシステムのすべての部分に接続することは合理的ではない場合があります。
  • 多くのサービスは停止することができません。 デバッガーをアタッチすると、多くの場合、タイムアウト エラーが発生します。
  • 問題は常に予測できるとは限りません。 ログとトレースは、問題が発生した場合に備えてプログラムで常に記録できるように、オーバーヘッドが低くなるように設計されています。

出力ウィンドウに情報を書き込む

ここまで、コンソールを使用して、アプリケーション ユーザーに情報を表示してきました。 モバイル、Web、デスクトップ アプリなどのユーザー インターフェイスを持ち、表示されるコンソールがない、.NET で構築されるその他の種類のアプリケーションがあります。 これらのアプリケーションでは、System.Console が "表示されない" メッセージを記録します。これらのメッセージは、Visual Studio や Visual Studio Code の出力ウィンドウに表示されることがあります。 また、Android の logcat のようなシステム ログに出力される場合もあります。 そのため、コンソール以外のアプリケーションで System.Console.WriteLine を使用する場合は、十分な検討を行う必要があります。

この場合、System.Console に加えて System.Diagnostics.DebugSystem.Diagnostics.Trace を使用できます。 DebugTrace はどちらも 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 を使用して関連のあるステートメントを別々の行に出力すると、どの情報が関連し合っているかを読み取るのが困難になります。 一般に、複数のソースの情報を組み合わせて 1 つの情報メッセージを作成する場合は、複数の Write ステートメントを使用します。 1 つの完全なメッセージを作成する場合は、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 構成の DEBUG に加えて、DebugRelease の両方の構成に対して TRACE をオンにする例を次に示します。

<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 メソッドに加えて、WriteIfWriteLineIf を使用して条件を追加する機能もあります。 例として、次のロジックは、カウントがゼロかどうかを確認し、デバッグ メッセージを書き込みます。

if(count == 0)
{
    Debug.WriteLine("The count is 0 and this may cause an exception.");
}

これは、1 行のコードに書き直すことができます。

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 の場合、アサーションは失敗します。 デバッグ ビルドで実行している場合、プログラムは中断モードになります。

Debug または Trace から Assert メソッドを使用できます。これらは、System.Diagnostics 名前空間にあります。 Debug クラスのメソッドはプログラムのリリース バージョンには含まれないので、リリース コードのサイズを増加させたり処理速度を低下させることはありません。

System.Diagnostics.Debug.Assert メソッドを自由に使用して、コードが正しい場合に true になる条件をテストできます。 たとえば、整数の除算関数を記述したとします。 数学の規則により、0 での除算は不可能です。 アサーションを使用して、この条件をテストできます。

int IntegerDivide(int dividend, int divisor)
{
    Debug.Assert(divisor != 0, $"{nameof(divisor)} is 0 and will cause an exception.");

    return dividend / divisor;
}

このコードをデバッガーで実行すると、アサート ステートメントが評価されます。 ただし、リリース バージョンではこの比較が行われないため、追加のオーバーヘッドはありません。

Note

System.Diagnostics.Debug.Assert を使用する場合は、Assert が削除される場合、Assert 内のコードによってプログラムの結果が変化しないことを確認します。 そうしないと、プログラムのリリース バージョンにのみ見られるバグが誤って発生する可能性があります。 関数またはプロシージャの呼び出しが含まれるアサートに特に注意してください。

System.Diagnostics 名前空間の DebugTrace を使用すると、アプリケーションの実行およびデバッグ時に追加のコンテキストが的確にわかります。