198 lines
7.1 KiB
Markdown
198 lines
7.1 KiB
Markdown
# 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)**
|
|
```cpp
|
|
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)**
|
|
```cpp
|
|
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 (출력 인터페이스)**
|
|
```cpp
|
|
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 코드에서**
|
|
```cpp
|
|
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에서 초기화**
|
|
```cpp
|
|
class MainWindow {
|
|
MainWindow() {
|
|
// LogManager 초기화 및 출력 설정
|
|
auto& logManager = LogManager::GetInstance();
|
|
logManager.InitializeDefaultOutputs(); // Console + Debug 출력 자동 추가
|
|
|
|
// 선택적으로 파일 로깅 추가
|
|
logManager.AttachLogOutput(LogOutputFactory::CreateFileOutput(L"app.log"));
|
|
}
|
|
};
|
|
```
|
|
|
|
### **Unit Test에서**
|
|
```cpp
|
|
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**: 플러그인 기반 확장성
|
|
|
|
을 모두 만족하는 최적의 로깅 솔루션을 제공합니다. |