プログラムを開発、テスト、運用する際にログが欲しくなります。特に運用時はログのでき次第で障害や改修への対応の難易度が大きく変わります。この記事ではC#の定番ログライブラリの一つであるSerilogについて説明します。Serilogは設定の柔軟性、ログの構造化、そして出力先の多様性といった特徴を備えたログライブラリでありC#のプログラムの助けになってくれます。
serilog/serilog: Simple .NET logging with fully-structured events
Serilogは一度設定を決定した後、グローバルで呼び出した時に常にその設定を適用するという動き方をします。これにより設定や呼び出しを繰り返す手間を省けます。次のコードが最初の設定例です。
using Serilog; using Serilog.Events; namespace MyApp.LogSample { public class Program { public static void Main() { Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() // Information 以上に重要なログのみを記録します // Microsoftからのログは、Warningレベル以上のもののみ出力します。 .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) // Systemからのログも、Warningレベル以上のもののみ出力します。 .MinimumLevel.Override("System", LogEventLevel.Warning) // ログの詳細情報を提供するために、ログコンテキストから情報を取得します。 .Enrich.FromLogContext() // ログの出力先を指定します。ここではファイルに出力するとし、 // ファイル名のテンプレート // ログの形式 // ログファイルの間隔 // 保持するファイル数 // を指定しています。 .WriteTo.File( "Logs/log-.txt", outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 90 ) .CreateLogger();// 上記の設定を元にLoggerインスタンスを作成します。 try { Log.Information("アプリケーションを開始します。"); // プログラム本体 } catch (Exception ex) { // アプリケーション終了のエラーログを出力します。エラーメッセージと例外の詳細がログに記録されます。 Log.Fatal(ex, "アプリケーションが終了しました。"); } finally { // すべての処理が終了したら、ログを閉じて残っている分を出力します。 Log.CloseAndFlush(); } } } }
一度こんな感じで設定するとプログラム本体の中で次の様にさっくり呼び出せます。
using Serilog; namespace MyApp.LogSample { public class MyClass { public void DoSomething() { Log.Information("何かを実行します"); } } }
先述の設定例では直にプログラム中のメソッドチェーンで設定していますが、設定ファイルを使うこともできます。これは次の拡張によって実現できます。
環境によってログに残す内容や出力先を変えたい場合はこちらの方が楽です。これは次の様にできます。
logsettings.json { "Serilog": { "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "System": "Warning" } }, "WriteTo": [ { "Name": "File", "Args": { "path": "Logs/log-.txt", "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level}] {Message}{NewLine}{Exception}", "rollingInterval": "Day", "retainedFileCountLimit": 90 } } ], "Enrich": [ "FromLogContext" ] } }
using Microsoft.Extensions.Configuration; using Serilog; namespace MyApp.LogSample { public class Program { public static void Main() { var configuration = new ConfigurationBuilder() .AddJsonFile("logsettings.json") .Build(); Log.Logger = new LoggerConfiguration() .ReadFrom.Configuration(configuration) // logsettings.jsonから設定を読み込みます。 .CreateLogger(); try { Log.Information("アプリケーションを開始します。"); // プログラム本体 } catch (Exception ex) { // アプリケーション終了のエラーログを出力します。エラーメッセージと例外の詳細がログに記録されます。 Log.Fatal(ex, "アプリケーションが終了しました。"); } finally { // すべての処理が終了したら、ログを閉じて残っている分を出力します。 Log.CloseAndFlush(); } } } }
Serilogは長く選ばれ続けるだけあって多くのことができます。特に先ほどの設定ファイルのライブラリなどの様に元々のSerilogを拡張するライブラリは数多くあり、機能を自前で増やすこともやりやすいです。またSerilogを元にした解析ツールなどもあり、運用の助けになってくれそうです。