Files
video-v1/vav2/Logging_Architecture_Design.md
2025-09-26 01:32:24 +09:00

7.1 KiB

Vav2Player - Testable Hybrid Logging Architecture Design

🎯 목표

  • 확장 가능한 로깅: 다양한 출력 대상 지원 (Console, Debug, Network, File)
  • MVVM 호환: Model-ViewModel-View 패턴과 완벽 통합
  • 테스트 가능: Unit Test에서 로깅 동작 검증 가능
  • 개발자 친화적: 간단한 API로 어디서든 쉽게 사용

🏗️ 아키텍처 구조

전체 구조도

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   View Layer    │    │  ViewModel      │    │   Model Layer   │
│ (LogMessagePage)│◄───┤(LogPageViewModel)│◄───┤   (LogManager)  │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                                                       │
                                                       ▼
┌─────────────────────────────────────────────────────────────────┐
│                    ILogOutput Interface                         │
├─────────────────┬─────────────────┬─────────────────┬───────────┤
│ ConsoleLogOutput│ DebugLogOutput  │ FileLogOutput   │NetworkLog │
│ (stdout)        │ (VS Output)     │ (.log file)     │(future)   │
└─────────────────┴─────────────────┴─────────────────┴───────────┘

컴포넌트 간 관계

[VideoPlayerControl]
        │
        ▼
[LogManagerProvider::GetInstance()] ─┐
        │                            │ (Production)
        ▼                            ▼
[Real LogManager] ◄──── or ───► [Mock LogManager] (Testing)
        │
        ▼
[ILogOutput Implementations]

🔧 핵심 컴포넌트

1. Model Layer

ILogManager (Interface)

class ILogManager {
public:
    virtual void LogInfo(const std::wstring& message, const std::wstring& source) = 0;
    virtual void LogVideoLoad(const std::wstring& filename, bool success) = 0;
    virtual void AttachLogOutput(std::unique_ptr<ILogOutput> output) = 0;
    // ... 기타 로깅 메서드
};

LogManager (실제 구현체)

  • Singleton 패턴
  • ILogManager 인터페이스 구현
  • 다중 ILogOutput 관리
  • Thread-safe 로그 데이터 저장

MockLogManager (테스트용)

  • ILogManager 인터페이스 구현
  • 로그 호출 기록 및 검증 기능
  • Unit Test에서 로깅 동작 검증

2. Infrastructure Layer

LogManagerProvider (Global Access)

class LogManagerProvider {
public:
    static ILogManager& GetInstance();           // Production: LogManager, Test: MockLogManager
    static void SetInstance(std::shared_ptr<ILogManager> mock);  // Test에서 Mock 주입
    static void ResetToDefault();                // Test 후 정리
};

ILogOutput (출력 인터페이스)

class ILogOutput {
public:
    virtual void OutputLog(const LogMessage& message) = 0;
    virtual void SetLogLevel(LogLevel level) = 0;
    virtual std::wstring GetName() const = 0;
};

구현체들

  • ConsoleLogOutput: stdout 콘솔 출력
  • DebugLogOutput: Visual Studio 출력 창 (OutputDebugString)
  • FileLogOutput: 파일 로깅
  • NetworkLogOutput: 네트워크 로깅 (향후 확장)

3. Presentation Layer

LogMessagePageViewModel (향후 구현)

  • LogManager와 View 사이의 바인딩
  • Observable Collection 관리
  • UI 상태 관리 (필터, 자동 스크롤 등)

LogMessagePage (View)

  • 순수 XAML 선언형 UI
  • ViewModel에 데이터 바인딩

📋 사용 방법

Production 코드에서

class VideoPlayerControl {
    void LoadVideo(const std::wstring& filePath) {
        // 어디서든 간단하게 로깅
        LogManagerProvider::GetInstance().LogInfo(L"Loading video: " + filePath, L"VideoPlayer");

        // 비디오 로딩 로직...
        bool success = LoadVideoFile(filePath);

        LogManagerProvider::GetInstance().LogVideoLoad(filePath, success);
    }
};

MainWindow에서 초기화

class MainWindow {
    MainWindow() {
        // LogManager 초기화 및 출력 설정
        auto& logManager = LogManager::GetInstance();
        logManager.InitializeDefaultOutputs();  // Console + Debug 출력 자동 추가

        // 선택적으로 파일 로깅 추가
        logManager.AttachLogOutput(LogOutputFactory::CreateFileOutput(L"app.log"));
    }
};

Unit Test에서

TEST_METHOD(VideoPlayerControl_LoadVideo_ShouldLogCorrectly) {
    // Arrange - Mock LogManager 주입
    auto mockLogManager = std::make_shared<MockLogManager>();
    LogManagerProvider::SetInstance(mockLogManager);

    VideoPlayerControl player;

    // Act
    player.LoadVideo(L"test.mp4");

    // Assert - 로깅 호출 검증
    Assert::AreEqual(2, mockLogManager->GetLogCallCount());
    Assert::IsTrue(mockLogManager->WasMethodCalled(L"LogInfo"));
    Assert::IsTrue(mockLogManager->WasMethodCalled(L"LogVideoLoad"));
    Assert::IsTrue(mockLogManager->WasMessageLogged(L"Loading video"));

    // Cleanup
    LogManagerProvider::ResetToDefault();
}

장점

개발 편의성

  • 전역 접근: LogManagerProvider::GetInstance()로 어디서든 사용
  • 간단한 API: 복잡한 의존성 전달 불필요
  • 타입 안전: 컴파일 타임에 로깅 메서드 검증

확장성

  • 플러그인 아키텍처: 새로운 ILogOutput 구현체 추가 용이
  • 다중 출력: Console + Debug + File + Network 동시 출력 가능
  • 개별 설정: 출력별로 로그 레벨 독립 설정

테스트 가능성

  • Mock 지원: MockLogManager로 로깅 동작 완벽 검증
  • 격리된 테스트: 테스트 간 로그 상태 격리
  • 검증 API: 로그 호출 횟수, 메시지 내용, 파라미터 검증

MVVM 호환성

  • Model: LogManager가 데이터와 비즈니스 로직 관리
  • ViewModel: UI 바인딩과 프레젠테이션 로직 분리
  • View: 순수 선언형 UI

🔄 확장 계획

  1. LogMessagePageViewModel 구현: ViewModel 패턴 완성
  2. Network Logging: 원격 로그 수집 서버 연동
  3. Log Filtering: 동적 로그 필터링 UI
  4. Performance Logging: 성능 메트릭 전용 로깅
  5. Structured Logging: JSON 기반 구조화 로깅

🎯 결론

이 하이브리드 아키텍처는:

  • Production: 간편한 Singleton 접근
  • Testing: 완벽한 Mock 지원
  • Architecture: MVVM 패턴 준수
  • Extensibility: 플러그인 기반 확장성

을 모두 만족하는 최적의 로깅 솔루션을 제공합니다.