Files
Sun1602/Server/Common/SunLog.h
T
2022-10-26 12:25:11 +08:00

348 lines
12 KiB
C++

#pragma once
#define OUTPUT_NONE 0
#define OUTPUT_FILE 1
#define OUTPUT_MONITOR 2
#define OUTPUT_BOTH 3
#define MAX_TIME_SIZE 100
#define __WAVERIX_SUNLOG_REVISION__
//
// <기본 설명>
// CSunLog Revision
// 이것은 기존 버전과의 호환되면서 새로운 요청상황을 수용하기 위한 로직과 그에 따라 새로 설계된 버전이다.
// 모든 로그의 기본 인터페이스는 CSunLog::LOGGINGwithARG 이며,
// 기타 다른 세부적인 처리들을 대신해주는 인터페이스들이 제공된다.
//
// <기존 호환을 위한 로그 레벨과 로그 옵션의 재정의>
// LEVEL의 경우, 자기 이하를 모두 포함한다.
// FULL인 경우, { CRITICAL, MIDDLE, FULL }
// MIDDLE인 경우, { CRITICAL, MIDDLE }
// CRITICAL인 경우, { CRITICAL }
// OPTION의 경우,
// FILE은 파일에만 기록한다.
// CONSOLE은 콘솔에만 기록한다.
// BOTH인 경우, 새롭게 주어진 인자값에 의거, 해당 위치에만 기록한다.
// -> BOTH로 설정되어 있다고 할지라도, 로깅시점에 특정 매체만 선택해서 기록이 가능하다
// CATEGORY의 경우, (신규)
// 해당 플랙값이 설정되어 있는 경우에만 허용한다.
//
// <기존 호환을 위한 인터페이스들>
// <매크로> SUNLOG : TCHAR기반의 약간 변형된 루틴을 통해서 처리된다.
// <매크로> SUNLOGCONN, 기타... : SUNLOG와 마찬가지이며, 이후 하나로 통합하는 방향으로 유도될 것이다.
// <메소드> InsertMessage : SUNLOGxxx와 같은 매크로를 사용하지 않은 경우들이 있으며, 이를 위한 제공 인터페이스
// <포멧제어> '\n'의 처리, 하나의 로깅당 다음줄로 넘기는 루틴이 포함되어 있다. 사용하는데 있어 다음 줄로 넘기는
// 루틴의 여부는 있어도 없어도 알아서 해준다.
//
// <신규 옵션의 활용 방안>
// ITEM, TRADE 등등의 관련된 범주를 포함해 로깅할 수 있도록 되어 있다.
// 이들의 블록처리도 가능하며, 쓰여진 파일 (SolarLog를 사용하므로 *.wzl)을 엑셀로 불러 구분할 수 있다.
//
// <신규 카테고리 추가>
// 다음 검색 단어 "<LOG CATEGORY INTERFACE>"를 SunLog.h, SunLog.cpp에서 찾아 볼 것.
// 추가해야 할 것이 무엇인지 나오며, 필요한 경우 추가할 수 있다.
// 단, 카테고리에 대한 처리 허용 여부는
// BIT fields에 기준(CSunLog::cCATE_MASK)하며, 고정된 값으로 작동되고 그 개수는 현 시스템에서는 32개가 한계일 것이다.
//
// <이후 작업할 일>
// 카테고리의 동적 설정 또는 ...
// GuildServer쪽은 작업되지 않았다.
// Blah~ Blah~ VC++ Compiler는 아래의 구문에서 실패가 되었다. 사용하지 않는다.
#define SUNLOG_ENUM_TO_STRING(name) ((TCHAR*)CSunLog::s##name())
#define ENUM_VALUE_LOGLEVEL(type, name, value) \
static const type c##name = (eLOGLEVEL)(value);
// static const DWORD sc##name = (DWORD)(__int64)_T(#name)
//static const TCHAR*
#define ENUM_VALUE_LOGOPTION(type, name, value) \
static const type c##name = (eLOGOPTION)(value);
// static const DWORD sc##name = (DWORD)(__int64)_T(#name)
#define ENUM_VALUE_CATEGORY(type, name, value) \
static const type c##name = (eLOGCATEGORY)(value); \
inline static TCHAR* sc##name() { return _T(#name); }
// static const DWORD sc##name = (DWORD)(__int64)_T(#name)
// <LOG CATEGORY INTERFACE>
#define SUNLOG_LOGGER_PER_OPTION(where, option) \
inline BOOL LOG( const eLOGLEVEL logLEVEL, const eLOGCATEGORY category, const TCHAR* pszMsg, va_list args )\
{ \
CSunLog* pSunLog = CONTAINING_RECORD(this, CSunLog, where); \
BOOL bRET = LOGGINGwithARG( pSunLog, option, logLEVEL, category, pszMsg, args ); \
va_end(args); \
return bRET; \
}
// <LOG CATEGORY INTERFACE>
#define SUNLOG_LOGGER_PER_LEVEL(where, option, level) \
inline BOOL LOG( const eLOGCATEGORY category, const TCHAR* pszMsg, va_list args ) \
{ \
CSunLog* pSunLog = CONTAINING_RECORD(this, CSunLog, where); \
BOOL bRET = LOGGINGwithARG( pSunLog, option, level, category, pszMsg, args ); \
va_end(args); \
return bRET; \
}
// <LOG CATEGORY INTERFACE>
#define SUNLOG_CATEGORY_OPTION_INTERFACE(name, catename) \
inline BOOL name( const eLOGLEVEL logLEVEL, const TCHAR* pszMsg, ... ) \
{ \
va_list args; \
va_start(args, pszMsg); \
return LOG( logLEVEL, catename, pszMsg, args ); \
}
// <LOG CATEGORY INTERFACE>
#define SUNLOG_CATEGORY_LEVEL_INTERFACE(name, catename) \
inline BOOL name( const TCHAR* pszMsg, ... ) \
{ \
va_list args; \
va_start(args, pszMsg); \
return LOG( catename, pszMsg, args ); \
}
class SolarLog;
class CSunLog
{
public:
// <CONSTANTs>
// <Descrition>
// eLOGLEVEL은 SunServer.ini에 등록된 LOG_LEVEL의 수치값과 동일하다.
// <BOUNDARY> 1<= (value) <=3
enum eLOGLEVEL {};
// <Descrition>
// eLOGOPTION은 SunServer.ini에 등록된 LOG_OPTION의 수치값과 동일하다.
// <BOUNDARY> 1<= (value) <=3
enum eLOGOPTION {};
// <Descrition>
// eLOGCATEGORY는 신규 추가된 것으로 남기는 로그의 성격을 분류하기 위함이다.
// 파일로 남는 로그에는 이 범주로 구분할 수 있도록 탭이 구분된다.
// Init을 통해 이 범주들에 대한 마스크를 씌울 수 있을 것이나, 특별한 툴은 제공되지 않느다.
// <BOUNDARY> Bits 1<= (value) <=16
enum eLOGCATEGORY {};
enum eLOGCATEGORYGROUP {};
ENUM_VALUE_LOGOPTION(eLOGOPTION, OUTPUT_NONE, OUTPUT_NONE);
ENUM_VALUE_LOGOPTION(eLOGOPTION, OUTPUT_FILE, OUTPUT_FILE);
ENUM_VALUE_LOGOPTION(eLOGOPTION, OUTPUT_CONSOLE, OUTPUT_MONITOR);
ENUM_VALUE_LOGOPTION(eLOGOPTION, OUTPUT_BOTH, OUTPUT_BOTH);
ENUM_VALUE_LOGOPTION(eLOGOPTION, OUTPUT_MASK, cOUTPUT_NONE|cOUTPUT_FILE|cOUTPUT_CONSOLE);
ENUM_VALUE_LOGLEVEL(eLOGLEVEL, CRITICAL_LOG, eCRITICAL_LOG);
ENUM_VALUE_LOGLEVEL(eLOGLEVEL, MIDDLE_LOG, eMIDDLE_LOG);
ENUM_VALUE_LOGLEVEL(eLOGLEVEL, FULL_LOG, eFULL_LOG);
ENUM_VALUE_LOGLEVEL(eLOGLEVEL, DEV_LOG, eDEV_LOG);
ENUM_VALUE_LOGLEVEL(eLOGLEVEL, LEVEL_MASK, cCRITICAL_LOG|cMIDDLE_LOG|cFULL_LOG|cDEV_LOG);
// <LOG CATEGORY INTERFACE>
ENUM_VALUE_CATEGORY(eLOGCATEGORY, CATE_DEFAULT, 1<<0);
ENUM_VALUE_CATEGORY(eLOGCATEGORY, CATE_CONNECTION, 1<<1);
ENUM_VALUE_CATEGORY(eLOGCATEGORY, CATE_WAREHOUSE, 1<<2);
ENUM_VALUE_CATEGORY(eLOGCATEGORY, CATE_TRADE, 1<<3);
ENUM_VALUE_CATEGORY(eLOGCATEGORY, CATE_ITEM, 1<<4);
ENUM_VALUE_CATEGORY(eLOGCATEGORY, CATE_MISSION, 1<<5);
ENUM_VALUE_CATEGORY(eLOGCATEGORY, CATE_ABUSE, 1<<6);
ENUM_VALUE_CATEGORY(eLOGCATEGORY, CATE_DATARELOAD, 1<<30);
// <LOG CATEGORY INTERFACE>
ENUM_VALUE_CATEGORY(eLOGCATEGORY, CATE_MASK, \
cCATE_DEFAULT | cCATE_CONNECTION | cCATE_WAREHOUSE | cCATE_TRADE | cCATE_ITEM | cCATE_MISSION \
| cCATE_DATARELOAD | cCATE_ABUSE );
CSunLog( VOID );
~CSunLog( VOID );
public:
//WriteMessage
// <METHODs><INTERFACEs>
virtual BOOL Init(
const BYTE byLogOption,
const BYTE byLogLevel,
const TCHAR* pszFilePath,
const TCHAR* pszFileName,
BOOL bUseSolarLog = TRUE
);
inline static BOOL LOGGING(
CSunLog* pSunLog,
const eLOGOPTION logOpt,
const eLOGLEVEL logLEVEL,
const eLOGCATEGORY category,
const TCHAR* pszMsg
)
{ return LOGGINGwithARG( pSunLog, logOpt, logLEVEL, category, pszMsg, (va_list)NULL ); }
static BOOL LOGGINGwithARG(
CSunLog* pSunLog,
const eLOGOPTION logOpt,
const eLOGLEVEL logLEVEL,
const eLOGCATEGORY category,
const TCHAR* pszMsg,
va_list vlist
);
// 이전 버전 호환용
inline bool InsertMessage( TCHAR* pszMsg, BYTE byLogLevel = 3 )
{ return TRUE == LOGGING( this, CSunLog::cOUTPUT_BOTH, (eLOGLEVEL)byLogLevel, CSunLog::cCATE_DEFAULT, pszMsg ); }
// Reload
VOID SetLogLevel( BYTE lv );
// <DESCRIPTION>
// 매 프레임시에 서버 시간 변경 검사를 수행한다.
// 1) 버퍼 타임아웃 체크
// 2) 날짜 변경에 따른 문제, 남아있는 버퍼 비우기 등의 처리를 수행한다.
// 2-1) 이경우, 파일이 변경되는 경우의 문제를 해결하기 위해 파일의 경우는 미리 Flush를 수행하도록 한다.
VOID Update();
// <DESCRIPTION>
// 현재 임시 버퍼에 쓰여진 내용을 강제로 출력시킨다. (콘솔+파일)
VOID Flush( eLOGOPTION eLogOPT = CSunLog::cOUTPUT_BOTH );
typedef BOOL (*WriteMessage)( const CSunLog* pSunLog, const TCHAR* pMsg, va_list arglist );
VOID RegisterHandler( WriteMessage fnFileLogger );
//
//
//
//======================================================================================================
// 다음부터는 CSunLog객체에서 사용하는 별도의 처리로직들이며, 이것을 사용하기 위한 INTERFACE가 아니다.
// <WARNING> 사용하지 말것.
//
protected:
// <CONSTANTs><TYPEs>
static const DWORD c_FileLogDataSize = 1024*3; // 3KB
static const DWORD c_FileLogDataSizeLimit = 1024*2; // 2KB
static const DWORD c_ConsoleLogDataSize = 1024*8; // 8KB
static const DWORD c_ConsoleLogDataSizeLimit = 1024*7; // 7KB
static const DWORD c_ConsoleLogInterval = 500; // 500ms
static const DWORD c_FileLogInterval = 5000; // 5000ms
struct sLOG_HANDLER
{
WriteMessage fn_FILE_LOGGER;
WriteMessage fn_CONSOLE_LOGGER;
};
public:
class CSunLogInfo
{
public:
HANDLE m_hConsole;
//sLOG_HANDLER m_Handler;
WriteMessage m_fnCONSOLE_LOGGER;
struct sLOGGING_INFO
{
eLOGOPTION Option;
eLOGLEVEL Level;
eLOGCATEGORY Mask;
} LOGGING_INFO;
struct sCONSOLE_LOG
{
DWORD Written;
TCHAR* QueuedStream; // Aligned Buffer by c_ConsoleLogDataSize
} CONSOLE_LOG;
CRITICAL_SECTION m_csConsoleLog;
DWORD m_dwConsoleTimeout;
CSunLogInfo();
~CSunLogInfo();
};
// 하나의 프로세스에 하나만 유지해야하는 SUNLOG 정보들
static DWORD g_dwSUNLOG_INIT;
static CSunLogInfo* g_pSUNLOG;
private:
// <METHODs>
// 기능 필터링
#ifdef __SUNLOG_UNUSED_SECT
//
// <RETURN>
// buffer <- CSunLog::m_strFileNameWithTime
// size <- sizeof(CSunLog::m_strFileNameWithTime)
TCHAR* GetCurrentFileNameWithTime( const TCHAR* defFileName );
#endif
//
// LEVEL의 경우, 자기 이하를 모두 포함한다.
// FULL인 경우, CRITICAL+MIDDLE+FULL
// MIDDLE인 경우, CRITICAL+MIDDLE
// CRITICAL인 경우, CRITICAL
// OPTION의 경우,
// FILE은 파일에만 기록한다.
// CONSOLE은 콘솔에만 기록한다.
// BOTH인 경우, 새롭게 주어진 인자값에 의거, 해당 위치에만 기록한다.
// CATEGORY의 경우,
// 해당 플랙값이 설정되어 있는 경우에만 허용한다.
BOOL CheckControl(
const CSunLogInfo::sLOGGING_INFO* pINFO,
const eLOGLEVEL logLEVEL,
const eLOGOPTION logOPT,
const eLOGCATEGORY logCATE )
{
__UNUSED(logOPT);
if( pINFO->Level < logLEVEL )
return FALSE;
if( (pINFO->Mask&logCATE) != logCATE )
return FALSE;
return TRUE;
}
//BOOL CheckHandler( CSunLog::sLOG_HANDLER& logHandler );
BOOL CheckHandler( WriteMessage& pfnColsoleLogHandler, WriteMessage& pfnFileLogHandler );
private:
enum ePREFIX { PREFIX_NONE=0, PREFIX_WRITE_TIME=1, PREFIX_CATEGORY=2, };
// METHODs for Handler
// <RETURN>
// written position : INT (0.ret<MAX)
// -1 : error
static INT MakePrefixFormat( const ePREFIX ePrefix, TCHAR* buffer, const DWORD dwMaxWritableLen, const eLOGCATEGORY cate = cCATE_DEFAULT );
public:
static INT WriteMessage_IO( HANDLE hWriter, const BYTE* stream, const DWORD dwLength );
// Handlers
static BOOL WriteMessage_Console( const CSunLog* pSunLog, const TCHAR* pMsg, va_list vlist );
static BOOL WriteMessage_Console2( const CSunLog* pSunLog, const TCHAR* pMsg, va_list vlist );
static BOOL WriteMessage_Console3( const CSunLog* pSunLog, const TCHAR* pMsg, va_list vlist );
static BOOL WriteMessage_File( const CSunLog* pSunLog, const TCHAR* pMsg, va_list vlist );
protected:
// <FIELDs>
SolarLog* m_pMainLogger;
WriteMessage m_fnFILE_LOGGER;
struct sFILE_LOG
{
DWORD Written;
TCHAR* QueuedStream; // Aligned Buffer by c_FileLogDataSize
} FILE_LOG;
CRITICAL_SECTION m_csFileLog;
DWORD m_dwFileTimeout;
public:
sFILE_LOG& GetFILE_LOG() { return FILE_LOG; }
//DWORD m_dwWrittenFile;
//TCHAR* m_pFileQueuedData; // Aligned Buffer by c_FileLogDataSize
//DWORD m_dwWrittenConsole;
//TCHAR* m_pConsoleQueuedData; // Aligned Buffer by c_ConsoleLogDataSize
//로그 삽입 즉시 출력 플러그.
private:
BOOL m_bFileOutDelay;
public:
VOID SetFileOutDelayOption( BOOL bDelay ){ m_bFileOutDelay = bDelay; }
};
#include <SunLog.Interfaces.h>
//#include <SecureLog.h>