Logger
ビルドレベルでのミュート、ローテーション式ファイルバックエンド、差し替え可能な出力を備えた、カテゴリ化されフィルタリング可能なロギング。
ゲームコードとフレームワークのためのカテゴリ化ロギング · 最初に起動するサービス · no-op 差し替え:
NullLogger
概要
Logger は UnityEngine.Debug.Log を、単一のフィルタリング可能な診断システムにラップします。ビルドレベルでのミュート(Release ビルドは Debug レベルのメッセージを自動的に破棄)、カテゴリごとのオン/オフスイッチ、そして差し替え可能な出力バックエンド — デフォルトは Unity Console、ほかにローテーション式のログファイルや自作のクラッシュレポートシンク — を提供します。散らばった Debug.Log 呼び出しの代わりに、ゲームコードとすべてのフレームワークサービスの診断は Logger.Info(category, message) を通り、一貫したフォーマットと、すべてを制御できる 1 つの中心的な場所が手に入ります。
簡単な使用例
セーブのデバッグ中だけ、それ以外の Console ノイズを抑える例です:
using CommonGameSystem.Core;
using UnityEngine;
using Logger = CommonGameSystem.Core.Logger; // Unity has its own Logger type
[DefaultExecutionOrder(100)] // Run after the framework has started
public class DebugConfig : MonoBehaviour
{
private void Awake()
{
// Silence everything except the Save category
Logger.MinimumLevel = LogLevel.Off;
Logger.SetCategoryFilter(Logger.Categories.Save, LogLevel.Debug);
}
}
// Elsewhere — only Save messages appear in the Console
Logger.Info(Logger.Categories.Net, "heartbeat ok"); // Silent
Logger.Info(Logger.Categories.Save, "slot 0 corrupted"); // Shown
static な Logger ヘルパーは、何も解決せずにどこでも使えます — 起動時にロギングバックエンドをキャッシュしてくれます。明示的な依存関係を好む場合(たとえばテストでフェイクを注入するため)は、Service Locator から ILogger を解決して Awake でキャッシュしてください。
API の全体像
出力メソッド(すべて static、スレッドセーフ)
Logger.Debug(string category, string message)— Debug レベル。Release ビルドでは呼び出し箇所全体がコンパイラによって除去されますLogger.Debug(string message)—Categories.Defaultでの DebugLogger.Info(string category, string message)— Info レベルLogger.Info(string message)—Categories.Defaultでの InfoLogger.Warning(string category, string message)— Warning レベルLogger.Warning(string message)—Categories.Defaultでの WarningLogger.Error(string category, string message)— Error レベルLogger.Error(string message)—Categories.Defaultでの ErrorLogger.Critical(string category, string message)— Critical レベルLogger.Critical(string message)—Categories.Defaultでの CriticalLogger.Exception(string category, Exception ex, string message = null)— 例外をスタックトレースと任意のコンテキストメッセージ付きで記録します。exが null ならArgumentNullExceptionをスローします
どの出力メソッドでも、category が null の場合は Categories.Default にフォールバックします。
フィルター制御(メインスレッド専用)
Logger.MinimumLevel { get; set; }— グローバルなレベルの下限。デフォルトはエディタと Development ビルドでDebug、Release ビルドでWarning。LogLevel.Offに設定するとすべてをミュートします — static ヘルパーも含めて即座に効きます。Logger.SetCategoryFilter(string category, LogLevel level)— 1 つのカテゴリの下限を上書きします。category が null ならArgumentNullExceptionをスローします。Logger.ClearCategoryFilter(string category)— カテゴリの上書きを削除し、グローバルな下限に戻します。category が null ならArgumentNullExceptionをスローします。
LogLevel の値
| 値 | 意味 |
|---|---|
Debug | フレーム単位のトレースや冗長な詳細。Release ビルドからは完全に除去されます。 |
Info | 状態遷移やライフサイクルイベント。常にコンパイルされます。 |
Warning | 回復済みの障害、疑わしい入力、非推奨のパス。常にコンパイルされます。 |
Error | 操作は失敗したがゲームは続行。常にコンパイルされます。 |
Critical | プロセスの整合性が損なわれている — 次の失敗は致命的になる可能性が高い。常にコンパイルされます。 |
Off | センチネル — 下限として設定すると、すべてのレベルをフィルタで除外します。 |
標準カテゴリ(文字列定数)
Logger.Categories.Default、.Bootstrap、.ServiceLocator、.Save、.Audio、.UI、.Input、.AI、.Net、.Perf(パフォーマンス: プール、時間、タイマー)、.Configuration、.Scene、.Localization、.Achievements。
カテゴリキーは大文字と小文字を区別します — 常に定数を使い、文字列リテラルは決して使わないでください。
ILogger インターフェース(カスタムバックエンドはこれを実装)
void Log(LogLevel level, string category, string message)— メッセージを出力void LogException(string category, Exception ex, string message)— 例外をスタックトレース付きで出力LogLevel MinimumLevel { get; set; }— インスタンスごとのレベル下限LogLevel GetEffectiveLevel(string category)— カテゴリの実効的な下限を照会。category が null ならArgumentNullExceptionをスロー
組み込みバックエンド
-
UnityConsoleLogger— デフォルト。Bootstrap が登録し、フォーマット済みの行を Unity Console に書き出します。 -
FileLogger— リリース後のサポートに向けた、オプトインのローテーション式ファイルロガー。Unity 自身のPlayer.logは区別のない単一ストリームで、Windows では次回起動時に上書きされます — プレイヤーが送ってくれる頃には、証拠はしばしば消えています。FileLoggerは各行にカテゴリとレベルを残し、ファイルをローテーションするので履歴が生き残ります:using CommonGameSystem.Core; using UnityEngine; [DefaultExecutionOrder(100)] public class FileLoggerInstaller : MonoBehaviour { private void Awake() { var fileLog = new FileLogger(); // {persistentDataPath}/logs/cgs.log fileLog.CaptureUnityLogStream(true); // also record uncaught exceptions ServiceLocator.Replace<ILogger>(fileLog); } }FileLogger(long maxBytes = 4 MB, int maxFiles = 3)—{persistentDataPath}/logs/cgs.logに記録し、ファイルがmaxBytesを超えるとローテーションして、書き込み中のものを含めmaxFiles個のファイルを保持します。メインスレッドで構築してください(Application.persistentDataPathを一度読み取ります)。FileLogger(string path, long maxBytes, int maxFiles)— 明示的なパスに記録します。ディレクトリがなければ作成されます。パスが null または空白ならArgumentExceptionをスローします。FilePath— 現在書き込み中のファイルの絶対パス。CaptureUnityLogStream(bool enabled)— Unity 自身のログストリームをファイルにミラーリングします: スタックトレース付きの未捕捉例外に加えて、ILoggerを経由しなかったあらゆるDebug.Logも記録します。UnityConsoleLoggerも同時にアクティブな間は、これを有効化しないでください — あちらのロガーはDebug.Log経由で書き込むため、フレームワークのすべての行が二重に記録されてしまいます。- スレッドセーフ(すべての書き込みはロックで直列化)で、決してスローしません: I/O の失敗は握りつぶされ、書き込みが 8 回連続で失敗すると、失敗が確実な書き込みを毎回リトライする代わりにインスタンス自身が無効化されます。
LogException経由で記録された例外はMinimumLevelをバイパスします — クラッシュを説明する唯一のレコードをフィルタで消すことは、この設定の意図では決してないからです。 IDisposableを実装しています — シャットダウン時に破棄して、フラッシュと購読解除を行ってください。
-
NullLogger— すべてのロギング呼び出しを静かな no-op にします:// Mute everything at runtime — takes effect immediately, static helpers included: Logger.MinimumLevel = LogLevel.Off; // Or replace the backend with a silent no-op (picked up by new resolves): ServiceLocator.Replace<ILogger>(new NullLogger());ヘッドレスや自動化ビルドからロギングのオーバーヘッドを取り除く、Console スパムなしでゲームコードをテストする、ロギングノイズなしでベンチマークする、といった用途に使います。ロギングを消音しても、他のすべてのサービスは通常どおり動作し続けます — フレームワークのいかなる部分もログ出力には依存していません。
独自バックエンドの作成
ILogger を実装するクラスなら何でもバックエンドになれます。たとえば、エラーをクラッシュレポート SDK に転送する場合:
using System;
using CommonGameSystem.Core;
public class CrashReportLogger : ILogger
{
public LogLevel MinimumLevel { get; set; } = LogLevel.Warning;
public void Log(LogLevel level, string category, string message)
{
if (level < MinimumLevel) return;
// Forward to your crash-reporting or analytics SDK here.
Console.WriteLine($"[{level}] [{category}] {message}");
}
public void LogException(string category, Exception ex, string message)
{
Console.WriteLine($"[Exception] [{category}] {message}\n{ex}");
}
public LogLevel GetEffectiveLevel(string category) => MinimumLevel;
}
ServiceLocator.Replace<ILogger>(new CrashReportLogger()) で登録します。この呼び出しの後に Service Locator から ILogger を解決するコードは、あなたのバックエンドを使います。注意点が 1 つ: static な Logger ヘルパーは初回実行時にバックエンドをキャッシュし、それはフレームワーク起動中に起こります — Play セッションの後半で行った差し替えは、static ヘルパーをリターゲットしません。キャッシュがリセットされる次の Play 開始時に、あなたのバックエンドを拾います。
挙動とエッジケース
-
Release ビルドは Debug 呼び出しを完全に除去します。
Logger.Debug($"msg = {Expensive()}")は、Release ビルドでは呼び出し箇所全体がコンパイラによって除去されるため、Expensive()は決して実行されません。タダで手に入る最適化です。 -
Unity の型との名前衝突。 ファイルに
using CommonGameSystem.Core;とusing UnityEngine;の両方があると、LoggerとILoggerはUnityEngine.LoggerおよびUnityEngine.ILoggerと衝突します。ファイルの先頭にエイリアスを追加してください:using Logger = CommonGameSystem.Core.Logger; using ILogger = CommonGameSystem.Core.ILogger; -
ワーカースレッドには起動時のウォームアップが必要です。 Bootstrap は起動中にメインスレッドで Logger を一度呼び出し、それによって以降のワーカースレッドからの呼び出し(セーブ I/O、ネットワーク I/O)が安全になります。ウォームアップ前にワーカースレッドがログを出すと、メッセージは素の
Debug.Logにフォールバックします。 -
カテゴリキーは大文字と小文字を区別します。
"Net"と"net"は別のフィルターです。常にLogger.Categories.*定数を使い、文字列リテラルは使わないでください。 -
フィルター API はメインスレッド専用です。
SetCategoryFilter/ClearCategoryFilterはメインスレッドから呼び出してください。出力メソッド(Info、Warning、Errorなど)はどこからでもスレッドセーフです。 -
GetEffectiveLevelは非 null のカテゴリを要求します。 出力パス(nullをCategories.Defaultとして扱う)とは異なり、照会 API は null カテゴリに対してArgumentNullExceptionをスローします。これにより設定バグが早期に表面化します。 -
セッション途中のバックエンド差し替えは static ヘルパーをリターゲットしません。 上の「独自バックエンドの作成」の注意点を参照してください。実行時に即座にミュートするには
Logger.MinimumLevel = LogLevel.Offを使ってください。
関連ページ
- Bootstrap — 起動順序と Logger のウォームアップ
- Service Locator —
ILoggerの解決と差し替え - Save/Load —
Categories.Saveを通じてログを出すサービス - マニュアル: トラブルシューティング — 問題発生時のフレームワークログ出力の読み方