Error以上のログ出力するときにVisualStudioを中断/ブレークする忘備録

## 対象読者

ローカルでの開発中、Errorレベル以上のログ出力するときってのは大体バグってるのからIDEでブレークポイントに引っかかったときのような感じで中断してデバッグしたい。

でもErrorログ出力するところに全部ブレークポイント付けてくのは面倒でぇ...って人向けのTips, 忘備録。

都合によりSerilogで検証しましたが、Serilogの独自機能とか使ってるわけじゃないので適宜置き換えれば他のLoggerでも同等の機能を実現できると思います。

## IDEの中断手法

IDEでブレークポイントをポチポチ設定する以外にも、`Debugger.Break` メソッドを呼び出すことで中断できます。

https://learn.microsoft.com/ja-jp/dotnet/api/system.diagnostics.debugger.break?view=net-8.0#system-diagnostics-debugger-break

## Errorレベル以上のログ出したときに中断させる

Loggerを拡張して任意のレベル以上のログを出力するときに中断させてみましょう。

```c#
using System.Diagnostics;
using Serilog;
using Serilog.Events;

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Verbose()
    .WriteTo.Console()
    .CreateLogger();

var stringValue = "中断したときに通常のブレークポイントと同じように値の中身が見れることを確認する用のローカル変数";
var intValue = 123;
var now = DateTime.Now;

var logger = MyLoggerFactory.CreateLogger<Program>();

logger.Verbose("{str} {int} {now}", stringValue, intValue, now);

logger.Verbose("Verbose!");
logger.Debug("Debug!");
logger.Information("Information!");
logger.Warning("Warning!このレベルはまだ中断されないよー");
logger.Error("Error!ブレークポイント張ったときのようにここで中断されるよー");
logger.Fatal("Fatal!ブレークポイント張ったときのようにここで中断されるよー");

class MyLoggerFactory
{
    public static ILogger CreateLogger<TSource>()
    {
        var baseLogger = Log.ForContext<TSource>();

        var myLogger = new MyLogger(baseLogger);

        return myLogger;
    }
}

class MyLogger(ILogger baseLogger) : ILogger
{
    /// <summary>
    /// これ以上のレベルのLogEventが発生したらDebugger.Break()を呼び出す。
    /// </summary>
    public LogEventLevel BreakIfGreaterThan { get; set; } = LogEventLevel.Error;

    // この属性を付けると、このメソッド内でデバッガーがステップインしない。
    // logger.Errorとか呼び出したところでブレークポイント貼られてたみたいな挙動になる。
    [DebuggerStepThrough]
    public void Write(LogEvent logEvent)
    {
        baseLogger.Write(logEvent);

        if (!Debugger.IsAttached)
        {
            return;
        }

        if (logEvent.Level >= BreakIfGreaterThan)
        {
            // DebuggerStepThroughがないとここでブレークする。ステップアウトが必要で不便。
            Debugger.Break();
        }
    }
}

```

## 実行結果例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93212/b28361dd-62a6-efd9-f65b-6dd42cd522d2.png)

わーい。

## サンプルコード真似てみたらDebuggerStepThrough属性つけてるのにDebugger.Break()の行で中断されちゃうんですけどー

VisualStudioのデバッグの全般設定で、**マイコードのみを有効にする** をオンにする必要があります。(オフのままでも適宜ステップオーバーすれば動きはします)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93212/dfdab105-fa0f-9994-f298-cccd06613535.png)

https://learn.microsoft.com/ja-jp/visualstudio/debugger/just-my-code?view=vs-2022#BKMK_Enable_or_disable_Just_My_Code

>[マイ コードのみを有効にする] は、すべての言語のすべての Visual Studio プロジェクトに適用されるグローバル設定です。

とのことなので注意しましょう。個別のプロジェクト設定で上書きする方法をご存じの方いらっしゃいましたら教えて下さいー。

---

## 独り言

- DIContainerでLoggerを解決するとき、特定の名前空間での解決のときだけ中断を有効にするのとか良さそう
- 「Errorログ出力時に中断させなくても、VS標準機能で例外投げたときに中断してくれるじゃん！Loggerに変なことさせないでそっち中心に組み立てたら！？」って話はごもっとも
  - https://learn.microsoft.com/ja-jp/visualstudio/debugger/managing-exceptions-with-the-debugger?view=vs-2022&source=recommendations
  - 基本、こっちを主軸に環境整えるのがいいと思う
  - が、プロジェクトのポリシーや既存実装との兼ね合い次第で例外全般が導入しづらいこともありましてぇ。という自分への言い訳

## 検証プロジェクト

https://github.com/kokeiro001/SandboxProjects/tree/main/SerilogSandbox