セージ の メモ書き

メモこそ命の恩人だ

C# - Microsoft.Extensions.Logging

Microsoft.Extensions.Logging

www.nuget.org

docs.microsoft.com

  • ロギング用のライブラリ。
  • ILogger インタフェースにロガーを注入して利用する。
  • 以下に出力できる。
    • デバッグウィンドウ
    • コンソール
    • OSのイベントログ
  • Microsoft 以外のライブラリも使用できる。
    • NLog、Log4Net など
    • DI により、使用ライブラリを容易に切り替えられる。
  • Nuget より "Microsoft.Extensions.Logging" をインストール。
    • 作成者:Microsoft
    • ダウンロード数:1.23B (2022/6時点)
    • ライセンス:MIT

WPFアプリでデバッグウィンドウに出力してみる。

using ILoggerFactory loggerFactory = LoggerFactory.Create(loggingBuilder =>
{
    // ログレベルの最小値を設定
    loggingBuilder.SetMinimumLevel(LogLevel.Trace);
    // デバッグウィンドウに記録
    // Nuget より "Microsoft.Extensions.Logging.Debug" をインストールする。
    loggingBuilder.AddDebug();
});
ILogger logger = loggerFactory.CreateLogger<MainWindow>();

logger.LogTrace("お試し1");
logger.LogDebug("お試し2");
logger.LogInformation("お試し3");
logger.LogWarning("お試し4");
logger.LogError("お試し5");
logger.LogCritical("お試し6");

// デバッグウィンドウに以下が記録されたことを確認。
// WpfApp1.MainWindow: Trace: お試し1
// WpfApp1.MainWindow: Debug: お試し2
// WpfApp1.MainWindow: Information: お試し3
// WpfApp1.MainWindow: Warning: お試し4
// WpfApp1.MainWindow: Error: お試し5
// WpfApp1.MainWindow: Critical: お試し6

コンソールアプリでも試す。Nuget より以下をインストールしておく。
Microsoft.Extensions.Logging.Debug
Microsoft.Extensions.Logging.Console
Microsoft.Extensions.Logging.EventLog

using ILoggerFactory loggerFactory = LoggerFactory.Create(loggingBuilder =>
{
    // 複数指定することもできる。
    loggingBuilder.AddDebug();
    loggingBuilder.AddConsole();
    loggingBuilder.AddEventLog();
});
ILogger logger = loggerFactory.CreateLogger<Program>();

logger.LogInformation("お試し (^^♪");
// ログが以下に記録されたことを確認。
// ・デバッグウィンドウ
// ・コンソールアプリ
// ・OSイベントログ

ロガーの利用方法

  • 前述の方法で都度生成するのは手間である。
  • 汎用ホストの利用がオススメ。

static オブジェクトの利用

public static class LogManager
{
    private static ILoggerFactory loggerFactory = new LoggerFactory();
    private static readonly object lockObject = new();

    public static void SetLoggerFactory(ILoggerFactory factory) => loggerFactory = factory;

    static public ILogger<T> GetLogger<T>()
    {
        lock (lockObject)
        {
            return loggerFactory.CreateLogger<T>();
        }
    }
}

public class Class1
{
    public Class1()
    {
        // ロガーを取得
        var logger = LogManager.GetLogger<Class1>();
        logger.LogInformation("お試し (^^♪");
    }
}
// ILoggerFactory を設定
LogManager.SetLoggerFactory(LoggerFactory.Create(loggingBuilder =>
{
    loggingBuilder.AddDebug();
}));

var sample = new Class1();
// お試し (^^♪
// ログが記録されたことを確認。

汎用ホストの利用

  • DI によりロガーを取得する。
  • Nuget より "Microsoft.Extensions.Hosting" をインストール。
    • 作成者:Microsoft
    • ダウンロード数:197M (2022/6時点)
    • ライセンス:MIT
public class Class1
{
    public Class1(ILogger<Class1> logger)
    {
        logger.LogInformation("お試し (^^♪");
    }
}
IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureLogging(loggingBuilder => 
    {
        loggingBuilder.ClearProviders();
        loggingBuilder.AddDebug();
    })
    .ConfigureServices(services =>
    {
        services.AddTransient<Class1>();
    })
    .Build();

var sample = host.Services.GetService<Class1>();
// お試し (^^♪
// ログが記録されたことを確認。

汎用ホストの利用(WPF

  • ViewModel の DI は難しい。
    • ViewModel のコンストラクタに引数があると、XAML のデザイナーでエラーになる。
    • View のコードビハインドで DataContext にセットする場合、new する必要がある。
    • なので、DI させる方法がわからない。。。
  • ViewModel ではユニットテストしないと割り切って、DI コンテナを参照する。
    • アンチパターンかも。。。
    • DIコンテナにロガー、DBアクセスなどのオブジェクトをセットする。
    • それを ViewModel で Model 用のオブジェクトに適用していくのが良いかも。
// エントリーポイント
public partial class App : Application
{
    private static readonly IHost host = Host.CreateDefaultBuilder()
            .ConfigureLogging(loggingBuilder =>
            {
                loggingBuilder.ClearProviders();
                loggingBuilder.AddDebug();
            })
            .Build();

    public static IServiceProvider ServiceProvider => host.Services;

    public static ILogger<T> GetLogger<T>() => host.Services.GetRequiredService<ILogger<T>>();

    private async void Application_Startup(object sender, StartupEventArgs e)
    {
        StartupUri = new Uri(@"/MainWindow.xaml", UriKind.Relative);

        await host.RunAsync();
    }
}
// Model
public class MainService
{
    private readonly ILogger<MainService> logger;

    public MainService(ILogger<MainService> logger) => this.logger = logger;

    public void Run() => logger.LogInformation("お試し (^^♪");
}
// ViewModel
public class MainViewModel
{
    private readonly ILogger<MainViewModel> logger;
    private readonly MainService mainService;

    public MainViewModel()
    {
        // DI コンテナを間接的に参照し、ロガーを取得
        logger = App.GetLogger<MainViewModel>();
        logger.LogInformation("お試し (^^♪");

        // Model には ViewModel からセット
        mainService = new MainService(App.GetLogger<MainService>());
        mainService.Run();
    }
}



以上