로거
빌드 수준 음소거, 로테이션 파일 백엔드, 교체 가능한 출력을 갖춘 카테고리 기반 필터링 로깅.
게임 코드와 프레임워크를 위한 분류형 로깅 · 가장 먼저 시작되는 서비스 · no-op 대체물:
NullLogger
무엇을 하는가
로거는 UnityEngine.Debug.Log를 하나의 필터링 가능한 진단 시스템으로 감쌉니다. 빌드 수준 음소거(Release 빌드는 Debug 레벨 메시지를 자동으로 버립니다), 카테고리별 on/off 스위치, 그리고 교체 가능한 출력 백엔드 — 기본은 Unity 콘솔이고, 로테이션 로그 파일이나 여러분 자신의 크래시 리포팅 싱크도 가능합니다 — 를 제공합니다. 흩어진 Debug.Log 호출 대신, 게임 코드와 모든 프레임워크 서비스가 일관된 포맷과 단 하나의 중앙 제어 지점을 갖고 Logger.Info(category, message)를 통해 진단을 내보냅니다.
빠른 예제
저장 기능만 디버깅하는 동안 콘솔 소음을 억제하기:
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 헬퍼는 아무것도 resolve하지 않고 어디서나 사용할 수 있습니다 — 시작 시 로깅 백엔드를 알아서 캐시해 줍니다. 명시적 의존성을 선호한다면(예: 테스트에서 가짜를 주입하기 위해) 서비스 로케이터에서 ILogger를 resolve해 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을 던집니다
어떤 출력 메서드든 카테고리가 null이면 Categories.Default로 처리됩니다.
필터 제어 (메인 스레드 전용)
Logger.MinimumLevel { get; set; }— 전역 레벨 하한. 에디터와 Development 빌드에서는Debug, Release 빌드에서는Warning이 기본값입니다.LogLevel.Off로 설정하면 전부 음소거되며 — static 헬퍼를 포함해 즉시 적용됩니다.Logger.SetCategoryFilter(string category, LogLevel level)— 한 카테고리의 하한을 재정의합니다; 카테고리가 null이면ArgumentNullException을 던집니다.Logger.ClearCategoryFilter(string 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)— 카테고리의 실제 하한을 조회합니다; 카테고리가 null이면ArgumentNullException을 던집니다
내장 백엔드
-
UnityConsoleLogger— 기본값. 부트스트랩이 등록하며, 포맷된 줄을 Unity 콘솔에 씁니다. -
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을 구현합니다 — 종료 시 dispose해 플러시하고 구독을 해제하십시오.
-
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());헤드리스 빌드나 자동화 빌드에서 로깅 오버헤드를 제거하거나, 콘솔 스팸 없이 게임 코드를 테스트하거나, 로깅 소음 없이 벤치마크할 때 사용하십시오. 로깅을 음소거해도 다른 모든 서비스는 정상 동작합니다 — 프레임워크의 어떤 것도 로그 출력에 의존하지 않습니다.
직접 백엔드 작성하기
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())로 등록합니다. 이 호출 이후 서비스 로케이터에서 ILogger를 resolve하는 코드는 여러분의 백엔드를 사용합니다. 한 가지 주의점: 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를 사용하십시오.
관련 페이지
- 부트스트랩 — 시작 순서와 로거 예열
- 서비스 로케이터 —
ILoggerresolve와 교체 - 저장/불러오기 —
Categories.Save로 로그를 남기는 서비스 - 매뉴얼: 문제 해결 — 문제가 생겼을 때 프레임워크 로그 출력 읽기