ZLogger は、C# の文字列補間 ($"") によるメモリ確保(アロケーション)を回避し、非常に高速にログを出力できるライブラリです。大量のログを扱うシステムや、パフォーマンスが要求されるIoT/ゲームサーバーなどで威力を発揮します。
ここでは、指定されたバージョン 1.4.1 を前提に、コンソールとファイル(ローテーション付き)への出力を実装します。
目次
実装サンプル:IoTセンサーデータの収集
題材として、大量のセンサーデータを受け取り続ける「センサー収集サービス (SensorApp)」を作成します。
1. パッケージのインストール
dotnet add package ZLogger --version 1.4.1
2. Program.cs (ZLoggerの設定)
ZLogger の特徴である ZString.PrepareUtf8 を使ったプレフィックス(ログの先頭につく日時やレベル)の高速化設定を行い、コンソールとファイルに出力先を設定します。
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using ZLogger;
using Cysharp.Text; // ZStringを使用するために必要
namespace SensorApp
{
class Program
{
static async Task Main(string[] args) =>
await CreateHostBuilder(args).Build().RunAsync();
// ログの共通オプション設定
static readonly Action<ZLoggerOptions> LogOption = options =>
{
// ログの先頭に付くプレフィックスのフォーマット定義
// "[LogLevel][yyyy-MM-dd HH:mm:ss] " の形式を事前コンパイルして高速化
var prefixFormat = ZString.PrepareUtf8<LogLevel, DateTime>("[{0}][{1}] ");
options.PrefixFormatter = (writer, info) =>
prefixFormat.FormatTo(ref writer, info.LogLevel, info.Timestamp.DateTime.ToLocalTime());
// 例外発生時のスタックトレース出力も有効化
options.EnableStructuredLogging = true;
};
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging((context, logging) =>
{
// 標準のプロバイダをクリア
logging.ClearProviders();
// 最低ログレベルをTraceに設定
logging.SetMinimumLevel(LogLevel.Trace);
// 1. コンソール出力 (高速版)
logging.AddZLoggerConsole(LogOption);
// 2. 単一ファイル出力
logging.AddZLoggerFile("logs/sensor.log", LogOption);
// 3. ローテーション付きファイル出力
// 日付ごとにファイルを変え、1ファイルあたり2MB(2048KB)を超えたら分割
logging.AddZLoggerRollingFile(
fileNameSelector: (dt, seq) => $"logs/sensor-{dt.ToLocalTime():yyyy-MM-dd}_{seq:000}.log",
timestampPattern: x => x.ToLocalTime().Date,
rollSizeKB: 2048,
options: LogOption);
})
.ConfigureServices((context, services) =>
{
services.AddHostedService<SensorWorker>();
});
}
}
3. SensorWorker.cs (ZLogger独自メソッドによる出力)
ZLogger の性能を最大限に引き出すには、標準の LogInformation ではなく、拡張メソッドである ZLogInformation などを使い、ジェネリクス版の書き方をするのがポイントです。
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ZLogger; // これがないとZLog系メソッドが使えません
namespace SensorApp
{
public class SensorWorker : BackgroundService
{
private readonly ILogger<SensorWorker> _logger;
public SensorWorker(ILogger<SensorWorker> logger)
{
_logger = logger;
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
// ログ出力用のダミーデータ
var sensorId = "Sensor-001";
var temperature = 24.5;
var humidity = 60;
// --- ZLogger の書き方 ---
// 1. Trace: 詳細ログ
_logger.ZLogTrace("詳細トレース: データ受信待機中...");
// 2. Debug: デバッグ情報
// ZLogDebug<T1, T2>(format, arg1, arg2) のように書くことで
// Boxing(メモリ確保)を回避してゼロアロケーションで出力できます。
_logger.ZLogDebug("デバッグ: 接続チェック OK (Target: {0})", "Gateway-A");
// 3. Information: 通常ログ
_logger.ZLogInformation("受信: SensorId={0}, Temp={1}C, Hum={2}%", sensorId, temperature, humidity);
// 4. Warning: 警告
_logger.ZLogWarning("警告: 湿度が閾値を超えています (Current: {0}%)", humidity);
// 5. Error: エラー
// 例外オブジェクトも最初の引数に渡せます
try
{
throw new InvalidOperationException("通信タイムアウト");
}
catch (Exception ex)
{
_logger.ZLogError(ex, "エラー: データの送信に失敗しました (Retry: {0})", 1);
}
// 6. Critical: 致命的エラー
_logger.ZLogCritical("致命的: システムを緊急停止します");
return Task.CompletedTask;
}
}
}
実行結果(ログファイルの出力例)
logs/sensor-2026-01-11_000.log に以下のような形式で出力されます。
[Trace][2026-01-11 10:00:00] 詳細トレース: データ受信待機中...
[Debug][2026-01-11 10:00:00] デバッグ: 接続チェック OK (Target: Gateway-A)
[Information][2026-01-11 10:00:00] 受信: SensorId=Sensor-001, Temp=24.5C, Hum=60%
...
解説とポイント
- ZLog メソッドの利用*:
_logger.LogInformation($"Val={val}")と書くと、文字列生成のためにメモリが確保されてしまいます。_logger.ZLogInformation("Val={0}", val)と書くことで、ZLogger が内部でバッファに直接書き込みを行うため、GC(ガベージコレクション)の発生を抑え、圧倒的な速度を実現します。 - PrefixFormatter の高速化:
ZString.PrepareUtf8を使うことで、ログのフォーマット文字列を事前に解析・保持しておけます。毎回フォーマット解析をするコストが省けるため、ログ出力頻度が高い場合に非常に有効なテクニックです。 - 注意点 (v1 vs v2): 今回は指定のあった v1.4.1 で実装しましたが、現在は v2 がリリースされており、APIや名前空間、設定方法が大きく変更されています(
AddZLoggerConsoleの書き方など)。新規プロジェクトでバージョン指定がない場合は v2 の利用を検討してください。
