System.Diagnostics.Debug

.NET標準のデバッグ出力クラス。DEBUG条件付きコンパイルにより本番ビルドでは自動的に無効化。Visual Studio等のIDEでのデバッグセッションに特化し、開発時のトレース情報出力に使用される軽量なデバッグツール。

ロギング.NETC#デバッグシステム診断

ライブラリ

System.Diagnostics.Debug

概要

System.Diagnostics.Debugは「.NET Framework/.NET Core向けの組み込みデバッグ・診断ライブラリ」として提供される、Microsoftの標準ロギングソリューションです。.NET Frameworkに最初から含まれているため、外部依存関係なしで利用可能。主にデバッグビルド時の開発支援とトラブルシューティングを目的とし、コンパイル時条件付きコンパイルによりリリースビルドでは自動的に除去される設計。Visual Studioとの密接な統合により、ブレークポイント、ステップ実行、変数ウォッチとシームレスに連携し、.NET開発者にとって最も身近なデバッグツールとして位置づけられています。

詳細

System.Diagnostics.Debug 2025年版は、.NET 8以降の最新ランタイムと完全統合され、高度なパフォーマンス診断とメモリ分析機能を提供しています。従来のDebug.WriteLine()からStructured Loggingサポートまで幅広い出力オプションを提供し、クラウドネイティブアプリケーションでの分散トレーシングとも連携可能。リリースビルドでは完全にコンパイル除去されるため、本番環境でのパフォーマンスへの影響がゼロ。Visual Studio Diagnostic Tools、Application Insights、Event Tracing for Windows (ETW)との統合により、包括的なアプリケーション監視エコシステムを構築できます。

主な特徴

  • 標準組み込み: .NET Framework/.NET Coreに標準搭載、追加依存なし
  • 条件付きコンパイル: デバッグビルドのみ有効、リリースで自動除去
  • Visual Studio統合: IDEとの完璧な統合とリアルタイム診断
  • トレースリスナー: カスタム出力先への柔軟なログ転送
  • パフォーマンス監視: CPU使用率、メモリ、スレッド状態の詳細分析
  • ETW統合: Windows Event Tracingとの高度な連携機能

メリット・デメリット

メリット

  • .NET標準ライブラリのため追加インストール・設定不要の即座利用
  • 条件付きコンパイルによる本番環境での完全なパフォーマンス影響ゼロ
  • Visual Studioとの完璧な統合による最高の開発者体験
  • Microsoft エコシステム(Azure、Application Insights)との自然な連携
  • 学習コストが最小限で .NET 開発者なら即座に活用可能
  • Windows Event Tracingによる高度なシステム監視機能

デメリット

  • 主にデバッグ用途のため、本格的なアプリケーションログには不向き
  • 構造化ログやフィルタリング機能が他専用ライブラリより限定的
  • クロスプラットフォーム環境では一部機能が制限される場合あり
  • 大規模分散システムでの包括的ログ管理には専用ソリューション必要
  • 設定オプションが限定的で高度なカスタマイズが困難
  • ログローテーションや永続化機能の自動サポートが限定的

参考ページ

書き方の例

インストール・セットアップ

// .NET Framework/.NET Core標準ライブラリのため追加インストール不要
using System;
using System.Diagnostics;

namespace DebuggingExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // 基本的な動作確認
            Debug.WriteLine("System.Diagnostics.Debug is ready to use!");
            Console.WriteLine("Debug output configured successfully");
        }
    }
}
<!-- プロジェクトファイル(.csproj) - 診断機能の設定 -->
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <!-- デバッグビルドでのDEBUGシンボル有効化 -->
    <DefineConstants Condition="'$(Configuration)' == 'Debug'">DEBUG;TRACE</DefineConstants>
    <!-- リリースビルドでのTRACEのみ有効化 -->
    <DefineConstants Condition="'$(Configuration)' == 'Release'">TRACE</DefineConstants>
  </PropertyGroup>
</Project>

基本的なログ出力

using System;
using System.Diagnostics;
using System.Collections.Generic;

public class BasicDebuggingExample
{
    public static void DemonstrateBasicDebugging()
    {
        // 基本的なデバッグ出力
        Debug.WriteLine("=== 基本的なデバッグ出力 ===");
        Debug.WriteLine("アプリケーション開始");
        Debug.WriteLine($"現在時刻: {DateTime.Now}");
        
        // フォーマット付きデバッグ出力
        string userName = "田中太郎";
        int userId = 12345;
        Debug.WriteLine($"ユーザー情報: ID={userId}, 名前={userName}");
        Debug.WriteLine("ユーザー {0} (ID: {1}) がログインしました", userName, userId);
        
        // 条件付きデバッグ出力
        bool isDevelopmentMode = true;
        Debug.WriteLineIf(isDevelopmentMode, "開発モードで実行中");
        
        // インデント付きデバッグ出力(階層表示)
        Debug.WriteLine("メイン処理開始");
        Debug.Indent();
        Debug.WriteLine("サブ処理1実行");
        Debug.Indent();
        Debug.WriteLine("詳細処理実行中...");
        Debug.Unindent();
        Debug.WriteLine("サブ処理1完了");
        Debug.Unindent();
        Debug.WriteLine("メイン処理完了");
        
        // アサーション(条件チェック)
        int result = CalculateSum(5, 3);
        Debug.Assert(result == 8, $"計算結果が期待値と異なります。期待値: 8, 実際値: {result}");
        
        // オブジェクトの状態出力
        var user = new User { Id = 123, Name = "山田花子", Email = "[email protected]" };
        Debug.WriteLine($"ユーザーオブジェクト: {user}");
        
        // コレクションの内容出力
        var numbers = new List<int> { 1, 2, 3, 4, 5 };
        Debug.WriteLine($"数値リスト: [{string.Join(", ", numbers)}]");
        
        // 例外情報の出力
        try
        {
            int divResult = 10 / 0;
        }
        catch (DivideByZeroException ex)
        {
            Debug.WriteLine($"例外発生: {ex.GetType().Name}");
            Debug.WriteLine($"メッセージ: {ex.Message}");
            Debug.WriteLine($"スタックトレース: {ex.StackTrace}");
        }
        
        // パフォーマンス測定
        var stopwatch = Stopwatch.StartNew();
        PerformSomeWork();
        stopwatch.Stop();
        Debug.WriteLine($"処理時間: {stopwatch.ElapsedMilliseconds}ms");
    }
    
    private static int CalculateSum(int a, int b)
    {
        Debug.WriteLine($"計算実行: {a} + {b}");
        return a + b;
    }
    
    private static void PerformSomeWork()
    {
        Debug.WriteLine("何らかの作業を実行中...");
        System.Threading.Thread.Sleep(100);
    }
    
    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        
        public override string ToString()
        {
            return $"User{{Id={Id}, Name='{Name}', Email='{Email}'}}";
        }
    }
}

ログレベル設定

using System;
using System.Diagnostics;

public class DebugLevelConfiguration
{
    // カスタムデバッグレベルの実装
    public enum DebugLevel
    {
        None = 0,
        Error = 1,
        Warning = 2,
        Info = 3,
        Debug = 4,
        Trace = 5
    }
    
    private static DebugLevel currentLevel = DebugLevel.Debug;
    
    public static void SetDebugLevel(DebugLevel level)
    {
        currentLevel = level;
        Debug.WriteLine($"デバッグレベルを {level} に設定しました");
    }
    
    public static void LogError(string message)
    {
        if (currentLevel >= DebugLevel.Error)
        {
            Debug.WriteLine($"[ERROR] {DateTime.Now:HH:mm:ss.fff} {message}");
        }
    }
    
    public static void LogWarning(string message)
    {
        if (currentLevel >= DebugLevel.Warning)
        {
            Debug.WriteLine($"[WARN]  {DateTime.Now:HH:mm:ss.fff} {message}");
        }
    }
    
    public static void LogInfo(string message)
    {
        if (currentLevel >= DebugLevel.Info)
        {
            Debug.WriteLine($"[INFO]  {DateTime.Now:HH:mm:ss.fff} {message}");
        }
    }
    
    public static void LogDebug(string message)
    {
        if (currentLevel >= DebugLevel.Debug)
        {
            Debug.WriteLine($"[DEBUG] {DateTime.Now:HH:mm:ss.fff} {message}");
        }
    }
    
    public static void LogTrace(string message)
    {
        if (currentLevel >= DebugLevel.Trace)
        {
            Debug.WriteLine($"[TRACE] {DateTime.Now:HH:mm:ss.fff} {message}");
        }
    }
    
    public static void DemonstrateLevels()
    {
        SetDebugLevel(DebugLevel.Warning);
        
        LogError("これはエラーメッセージです");          // 表示される
        LogWarning("これは警告メッセージです");          // 表示される
        LogInfo("これは情報メッセージです");             // 表示されない
        LogDebug("これはデバッグメッセージです");        // 表示されない
        LogTrace("これはトレースメッセージです");        // 表示されない
        
        SetDebugLevel(DebugLevel.Trace);
        
        LogError("エラー: データベース接続失敗");
        LogWarning("警告: メモリ使用量が高くなっています");
        LogInfo("情報: ユーザーがログインしました");
        LogDebug("デバッグ: SQL実行 - SELECT * FROM Users");
        LogTrace("トレース: メソッド開始 - UserService.GetUser()");
    }
}

.NET固有機能

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;

public class DotNetSpecificFeatures
{
    public static void DemonstrateAdvancedFeatures()
    {
        // 条件付きメソッド(DEBUGシンボル定義時のみ実行)
        PerformDebugOnlyOperation();
        
        // カスタムトレースリスナーの設定
        SetupCustomTraceListener();
        
        // パフォーマンスカウンターの使用
        DemonstratePerformanceCounters();
        
        // 非同期処理でのデバッグ
        DemonstrateAsyncDebugging().Wait();
        
        // LINQ式でのデバッグ
        DemonstrateLINQDebugging();
        
        // プロセス情報の取得
        DemonstrateProcessInformation();
    }
    
    [Conditional("DEBUG")]
    public static void PerformDebugOnlyOperation()
    {
        Debug.WriteLine("この処理はDEBUGビルドでのみ実行されます");
        
        // 詳細なメモリ情報の表示
        var process = Process.GetCurrentProcess();
        Debug.WriteLine($"プロセス名: {process.ProcessName}");
        Debug.WriteLine($"作業セット: {process.WorkingSet64 / 1024 / 1024} MB");
        Debug.WriteLine($"仮想メモリ: {process.VirtualMemorySize64 / 1024 / 1024} MB");
        Debug.WriteLine($"GCメモリ: {GC.GetTotalMemory(false) / 1024 / 1024} MB");
    }
    
    public static void SetupCustomTraceListener()
    {
        Debug.WriteLine("カスタムトレースリスナーの設定");
        
        // ファイルトレースリスナーの追加
        var fileListener = new TextWriterTraceListener("debug.log");
        Debug.Listeners.Add(fileListener);
        
        // コンソールトレースリスナーの追加
        var consoleListener = new ConsoleTraceListener();
        Debug.Listeners.Add(consoleListener);
        
        Debug.WriteLine("複数出力先に同時出力されています");
        
        // リスナーの削除
        Debug.Listeners.Remove(fileListener);
        Debug.Listeners.Remove(consoleListener);
        
        // ファイルクリーンアップ
        fileListener.Close();
    }
    
    public static void DemonstratePerformanceCounters()
    {
        Debug.WriteLine("=== パフォーマンス監視 ===");
        
        var process = Process.GetCurrentProcess();
        
        Debug.WriteLine($"CPU使用時間: {process.TotalProcessorTime.TotalMilliseconds}ms");
        Debug.WriteLine($"ユーザーCPU時間: {process.UserProcessorTime.TotalMilliseconds}ms");
        Debug.WriteLine($"システムCPU時間: {process.PrivilegedProcessorTime.TotalMilliseconds}ms");
        Debug.WriteLine($"スレッド数: {process.Threads.Count}");
        Debug.WriteLine($"ハンドル数: {process.HandleCount}");
        
        // GC情報の表示
        for (int generation = 0; generation <= GC.MaxGeneration; generation++)
        {
            Debug.WriteLine($"GC Gen{generation} コレクション回数: {GC.CollectionCount(generation)}");
        }
    }
    
    public static async Task DemonstrateAsyncDebugging()
    {
        Debug.WriteLine("=== 非同期処理デバッグ ===");
        
        var tasks = new List<Task>();
        
        for (int i = 0; i < 3; i++)
        {
            int taskId = i;
            var task = Task.Run(async () =>
            {
                Debug.WriteLine($"タスク {taskId} 開始 - スレッドID: {System.Threading.Thread.CurrentThread.ManagedThreadId}");
                
                await Task.Delay(100 * (taskId + 1));
                
                Debug.WriteLine($"タスク {taskId} 完了 - スレッドID: {System.Threading.Thread.CurrentThread.ManagedThreadId}");
                
                return taskId * 10;
            });
            
            tasks.Add(task);
        }
        
        Debug.WriteLine("全タスクの完了を待機中...");
        await Task.WhenAll(tasks);
        Debug.WriteLine("全タスク完了");
    }
    
    public static void DemonstrateLINQDebugging()
    {
        Debug.WriteLine("=== LINQ式デバッグ ===");
        
        var numbers = Enumerable.Range(1, 10).ToList();
        Debug.WriteLine($"元データ: [{string.Join(", ", numbers)}]");
        
        var result = numbers
            .Where(n => { 
                Debug.WriteLine($"フィルタ処理: {n}");
                return n % 2 == 0; 
            })
            .Select(n => { 
                Debug.WriteLine($"変換処理: {n} -> {n * n}");
                return n * n; 
            })
            .OrderByDescending(n => { 
                Debug.WriteLine($"ソート処理: {n}");
                return n; 
            })
            .ToList();
        
        Debug.WriteLine($"最終結果: [{string.Join(", ", result)}]");
    }
    
    public static void DemonstrateProcessInformation()
    {
        Debug.WriteLine("=== プロセス情報 ===");
        
        var currentProcess = Process.GetCurrentProcess();
        
        Debug.WriteLine($"プロセスID: {currentProcess.Id}");
        Debug.WriteLine($"プロセス名: {currentProcess.ProcessName}");
        Debug.WriteLine($"開始時刻: {currentProcess.StartTime}");
        Debug.WriteLine($"実行時間: {DateTime.Now - currentProcess.StartTime}");
        Debug.WriteLine($"優先度: {currentProcess.BasePriority}");
        Debug.WriteLine($"メインモジュール: {currentProcess.MainModule?.FileName}");
        
        // 環境変数の表示(一部)
        Debug.WriteLine("=== 環境変数(抜粋) ===");
        var envVars = new[] { "OS", "PROCESSOR_ARCHITECTURE", "NUMBER_OF_PROCESSORS" };
        foreach (var envVar in envVars)
        {
            Debug.WriteLine($"{envVar}: {Environment.GetEnvironmentVariable(envVar)}");
        }
        
        // アセンブリ情報の表示
        Debug.WriteLine("=== アセンブリ情報 ===");
        var assembly = System.Reflection.Assembly.GetExecutingAssembly();
        Debug.WriteLine($"アセンブリ名: {assembly.FullName}");
        Debug.WriteLine($"場所: {assembly.Location}");
        Debug.WriteLine($"ランタイムバージョン: {assembly.ImageRuntimeVersion}");
    }
}

設定ファイル例

<!-- app.config / web.config - システム診断設定 -->
<configuration>
  <system.diagnostics>
    <!-- トレースリスナーの設定 -->
    <trace autoflush="true" indentsize="4">
      <listeners>
        <!-- コンソール出力 -->
        <add name="consoleListener" 
             type="System.Diagnostics.ConsoleTraceListener" />
        
        <!-- ファイル出力 -->
        <add name="fileListener" 
             type="System.Diagnostics.TextWriterTraceListener" 
             initializeData="debug.log" />
        
        <!-- イベントログ出力 -->
        <add name="eventLogListener" 
             type="System.Diagnostics.EventLogTraceListener" 
             initializeData="Application" />
        
        <!-- カスタムリスナー -->
        <add name="customListener" 
             type="MyApp.CustomTraceListener, MyApp" />
      </listeners>
    </trace>
    
    <!-- デバッグリスナーの設定 -->
    <debug autoflush="true">
      <listeners>
        <add name="debugFile" 
             type="System.Diagnostics.TextWriterTraceListener" 
             initializeData="debug-only.log" />
      </listeners>
    </debug>
    
    <!-- ソース別トレース設定 -->
    <sources>
      <source name="MyApp.UserService" switchValue="Verbose">
        <listeners>
          <add name="userServiceLog" 
               type="System.Diagnostics.TextWriterTraceListener" 
               initializeData="userservice.log" />
        </listeners>
      </source>
      
      <source name="MyApp.DataAccess" switchValue="Warning">
        <listeners>
          <add name="dataAccessLog" 
               type="System.Diagnostics.TextWriterTraceListener" 
               initializeData="dataaccess.log" />
        </listeners>
      </source>
    </sources>
    
    <!-- スイッチ設定 -->
    <switches>
      <add name="GeneralSwitch" value="4" />
      <add name="DatabaseSwitch" value="2" />
    </switches>
  </system.diagnostics>
</configuration>

パフォーマンス最適化

using System;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;

public class DebugPerformanceOptimization
{
    public static void OptimizedDebuggingExamples()
    {
        // 1. 条件付きコンパイル属性の活用
        DebugOnlyExpensiveOperation();
        
        // 2. 遅延評価による最適化
        DemonstrateLazyEvaluation();
        
        // 3. バッチ出力による最適化
        DemonstrateBatchDebugging();
        
        // 4. 構造化デバッグ情報
        DemonstrateStructuredDebugging();
        
        // 5. メモリ効率的なデバッグ
        DemonstrateMemoryEfficientDebugging();
    }
    
    [Conditional("DEBUG")]
    public static void DebugOnlyExpensiveOperation()
    {
        Debug.WriteLine("=== 条件付きコンパイル最適化 ===");
        
        // この処理はDEBUGビルドでのみ実行される
        var stopwatch = Stopwatch.StartNew();
        
        // 重い処理のシミュレーション
        PerformExpensiveCalculation();
        
        stopwatch.Stop();
        Debug.WriteLine($"重い処理完了: {stopwatch.ElapsedMilliseconds}ms");
        
        // リリースビルドでは上記のコードは完全に除去される
    }
    
    public static void DemonstrateLazyEvaluation()
    {
        Debug.WriteLine("=== 遅延評価最適化 ===");
        
        // 非効率な例(常に文字列生成)
        var data = GenerateExpensiveString();
        Debug.WriteLineIf(IsDebugEnabled(), $"データ: {data}");
        
        // 効率的な例(必要時のみ生成)
        if (IsDebugEnabled())
        {
            var lazyData = GenerateExpensiveString();
            Debug.WriteLine($"遅延データ: {lazyData}");
        }
        
        // ラムダ式を使った遅延評価
        DebugWriteIf(IsDebugEnabled(), () => $"ラムダデータ: {GenerateExpensiveString()}");
    }
    
    public static void DemonstrateBatchDebugging()
    {
        Debug.WriteLine("=== バッチ出力最適化 ===");
        
        var batchOutput = new StringBuilder();
        
        // 個別出力(非効率)
        for (int i = 0; i < 5; i++)
        {
            Debug.WriteLine($"個別出力 {i}");
        }
        
        // バッチ出力(効率的)
        for (int i = 0; i < 5; i++)
        {
            batchOutput.AppendLine($"バッチ項目 {i}");
        }
        Debug.WriteLine("=== バッチ結果 ===");
        Debug.WriteLine(batchOutput.ToString());
    }
    
    public static void DemonstrateStructuredDebugging()
    {
        Debug.WriteLine("=== 構造化デバッグ ===");
        
        var user = new { Id = 123, Name = "田中太郎", Email = "[email protected]" };
        var timestamp = DateTime.Now;
        
        // 構造化されたデバッグ情報
        Debug.WriteLine($"{{\"timestamp\":\"{timestamp:o}\", \"event\":\"user_action\", \"user_id\":{user.Id}, \"user_name\":\"{user.Name}\"}}");
        
        // タブ区切り形式
        Debug.WriteLine($"{timestamp:yyyy-MM-dd HH:mm:ss.fff}\\t{user.Id}\\t{user.Name}\\tログイン");
        
        // カスタム構造化出力
        WriteStructuredDebug("USER_LOGIN", new { 
            UserId = user.Id, 
            UserName = user.Name, 
            Timestamp = timestamp,
            Success = true 
        });
    }
    
    public static void DemonstrateMemoryEfficientDebugging()
    {
        Debug.WriteLine("=== メモリ効率最適化 ===");
        
        // 効率的な文字列フォーマット
        var userId = 12345;
        var userName = "田中太郎";
        
        // string.Concat より効率的
        Debug.WriteLine($"ユーザー: {userId} - {userName}");
        
        // 大きなオブジェクトの場合は要約のみ
        var largeArray = new int[10000];
        Debug.WriteLine($"配列情報: 長さ={largeArray.Length}, ハッシュ={largeArray.GetHashCode()}");
        
        // StringBuilderの使い回し
        var sb = new StringBuilder(256);
        for (int i = 0; i < 3; i++)
        {
            sb.Clear();
            sb.Append("処理 ").Append(i).Append(" - ").Append(DateTime.Now.Millisecond);
            Debug.WriteLine(sb.ToString());
        }
    }
    
    // ヘルパーメソッド
    private static bool IsDebugEnabled()
    {
        #if DEBUG
        return true;
        #else
        return false;
        #endif
    }
    
    private static void DebugWriteIf(bool condition, Func<string> messageProvider)
    {
        if (condition)
        {
            Debug.WriteLine(messageProvider());
        }
    }
    
    private static string GenerateExpensiveString()
    {
        // 重い処理のシミュレーション
        var sb = new StringBuilder();
        for (int i = 0; i < 1000; i++)
        {
            sb.Append($"item_{i},");
        }
        return sb.ToString().TrimEnd(',');
    }
    
    private static void PerformExpensiveCalculation()
    {
        // CPU集約的な処理のシミュレーション
        double result = 0;
        for (int i = 0; i < 1000000; i++)
        {
            result += Math.Sqrt(i);
        }
    }
    
    private static void WriteStructuredDebug(string eventName, object data)
    {
        var json = System.Text.Json.JsonSerializer.Serialize(new { 
            Event = eventName,
            Timestamp = DateTime.UtcNow,
            Data = data
        });
        Debug.WriteLine($"STRUCTURED: {json}");
    }
}