c++

c++ 공부

이야기prog 2025. 2. 12. 21:18
#include "pch.h"
#include "Logger.h"

LogPrintf::LogPrintf() {
	printf("* Log create : printf log mode\n");
}

void LogPrintf::log(const WCHAR* logStr) {
	printf("%ws", logStr);
}

//------------------------------------------------------------------------------------------//
LogFile::LogFile(xml_t* config) {
	xmlNode_t* root = config->FirstChildElement("App")->FirstChildElement("Log");
	xmlNode_t* elem = root->FirstChildElement("Path");

	array<WCHAR, _MAX_PATH> logFilePath;
	StrConvA2W((char*)elem->GetText(), logFilePath.data(), logFilePath.max_size());
	printf("* Log create : [%ws]file log mode\n", logFilePath.data());
	this->initialize(logFilePath.data());

}

LogFile::~LogFile() {
	fs_.close();
	fs_.clear();

	std::size_t found = fileName_.find(L".log");
	if (found == wstr_t::npos)
		return;

	//뒤에 로그파일이 붙으면 종료시, 종료시각을 파일이름 뒤에 붙여줍니다.
	wstr_t closeFileName = fileName_.substr(0, found);
	closeFileName += CLOCK.nowTime(L"_%Y%m%d-%H%M%S.log");
	_wrename(fileName_.c_str(), closeFileName.c_str()); // 파일 이름 rename
}

void LogFile::initialize(const WCHAR* logFileName) {
	fileName_ = logFileName;
	fs_.open(logFileName, std::ios::out | std::ios::trunc); // 쓰기모드 + 파일 존재시 삭제

	if (fs_.bad()) {
		printf("! logfile error, file open fail\n");
		assert(false);
	}
}

void LogFile::log(const WCHAR* logStr) {
	printf("%ws", logStr);

	fs_ << logStr;
	fs_.flush(); //실시간 입력 버퍼에 저장 x
}

//------------------------------------------------------------------------------------------//

LogWriter::LogWriter() {
	base_ = nullptr;
}

LogWriter::~LogWriter() {
	prefix_.clear();

	SAFE_DELETE(base_);
}

void LogWriter::setLogger(LogBase* base, const const WCHAR* logPrefix) {
	prefix_.clear();
	prefix_ = logPrefix;

	if (base_) {
		LogBase* old = base_;
		base_ = nullptr;
		old->unInitialize();

		SAFE_DELETE(old);
	}

	base_ = base;
	base_->initialize();
}

LogBase* LogWriter::logger() {
	return base_;
}

void LogWriter::log(const WCHAR* fmt, ...) {
	//va_list args; //가변인자 리스트
	//va_start(args, fmt); // 가변인자 args에 fmt 다음 포인터부분을 읽으라고 지시

	//this->log(fmt, args);

	//va_end(args); // 뒷정리?
	va_list args;
	va_start(args, fmt);
	this->log(fmt, args);

	va_end(args);
}

void LogWriter::log(const WCHAR* fmt, va_list args) {
	wstr_t logMessage = CLOCK.nowTimeWithMilliSec();
	size_t threadId = GET_CURRENT_THREAD_ID;

	logMessage += L"\t";

	// 쓰레드 정보 넣기
	Thread* thread = ThreadManager::getInstance().at(threadId);
	if (thread) {
		logMessage += thread->name();
	}
	else {
		logMessage += prefix_;
	}
	array<WCHAR, SIZE_8 * 2> threadIdStr;
	snwprintf(threadIdStr, L"0x%X", threadId);

	logMessage += L":";
	logMessage += threadIdStr.data();
	logMessage += L"\t";

	array<WCHAR, SIZE_1024> logStr;

	vswprintf_s(logStr.data(), logStr.size(), fmt, args);
	logMessage += logStr.data();
	logMessage += L"\n";
	base_->log((const WCHAR*)logMessage.c_str());
}
//-----------------------------------------------------------------------------//
SystemLog::SystemLog() {
	xml_t config;
	if (!loadConfig(&config)) {
		printf("!!! have not config file\n");
		exit(0);
		return;
	}
	this->initialize(&config);
}

SystemLog::~SystemLog() {

}

void SystemLog::initialize(xml_t* config) {
	xmlNode_t* root = config->FirstChildElement("App")->FirstChildElement("Log");
	if (!root) {
		printf("@ not exist log setting");
		LogBase* base = new LogPrintf();
		logWrite_.setLogger(base, L"testServer");
		return;
	}
	xmlNode_t* elem = root->FirstChildElement("Path");

	array<WCHAR, SIZE_256> tmp;
	elem = root->FirstChildElement("Prefix");
	StrConvA2W((char*)elem->GetText(), tmp.data(), tmp.max_size());
	wstr_t prefix = tmp.data();

	LogBase* base;
	elem = root->FirstChildElement("Type");
	const char* type = (char*)elem->GetText();
	if (!strcmp(type, "WithFile")) { // strcmp 같으면 0 반환 
		base = new LogFile(config);
	}
	else {
		base = new LogPrintf();
	}

	logWrite_.setLogger(base, prefix.c_str());
	
}

void SystemLog::log(const WCHAR* fmt, ...) {
	va_list args;
	va_start(args, fmt);
	logWrite_.log(fmt, args);
	va_end(args);
}

게임서버를 만들면서 오늘 공부한 부분에 대해서 간단히 정리하겠다.

이 코드에서 SYstemLog에 log함수 부분에 ...으로 가변인자가 설정되어 있는데, 가변인자 사용법은

va_list로 가변인자의 리스트를 만들고, va_start로 args의 포인터값을 fmt 다음으로 옮겨서 사용한다.

va_end()는 단순히 끝내는 느낌으로 호환성에따라 쓰고 안써고 상관없다고 한다.

va_arg(args, TYPE)처럼 args가 가리키는 값을 반환하고 TYPE의 크기만큼 포인터를 증가시킨다.

va_copy(copy, args)처럼 copy에 args리스트를 복사하는 함수도 있다.

 

 

'c++' 카테고리의 다른 글

c++ 공부  (0) 2025.02.27
c++공부  (0) 2025.02.24
c++ 어셈블리어 간단하게 공부  (0) 2025.02.22
c++ 공부  (0) 2025.01.30
c++ 공부  (0) 2025.01.29