/*************************************************************************** Logger.h ----------------------------------------- begin : 2011/10/26 copyright : (C) 2005 SolutionBox Inc. author : Service 1 Team email : svc1@solbox.com version : 3.2.0.805 CopyRight(C) 2005 SolutionBox Inc. All Rights reserved. Redistribution and use in source and binary forms, with or with out modification, are not permitted in outside of SolutionBox Inc. ***************************************************************************/ #ifndef __LOGGER_H__ #define __LOGGER_H__ #include #include #include ///@brief 로그 레벨 정의 #define LEMR 0 /* system is or will be unusable if situation is not resolved */ #define LALT 1 /* immediate action required */ #define LCRT 2 /* critical situations */ #define LERR 3 /* error conditions */ #define LWAR 4 /* recoverable errors */ #define LNOT 5 /* unusual situation that merits investigation */ #define LINF 6 /* information messages */ #define LDBG 7 /* verbose data for debugging */ #define LDEV 8 /* verbose data for developer */ #define LDEV1 9 /* start or end the function of application level */ #define LDEV2 10 /* start or end the function of application level */ #define MAX_LOG_LEVEL LDEV2 ///@brief Log 정보를 파일로 저장하기 위한 Class. ///1. 가변 format 으로 전달된 로그 관련 정보를 Log Level 에 따라 로그 파일에 아래의 4가지 형식으로 저장한다. /// /// 1.1 Prefix로 [hh:mm:ss]와 [ClassName::FunctionName]이 추가된 로그 /// LOG( level, format, ... ) 매크로 사용. /// 예) [17:43:40] [DBG] log level debug [LoggerTestTestLogger] /// /// 1.2 Prefix로 [hh:mm:ss]이 추가된 로그 /// _LOG( level, format, ... ) 매크로 사용 /// 예) [17:43:40] [EMR] log level emergency /// /// 1.3 Prefix가 없는 로그 /// _LOG_( level, format, ... ) 매크로 사용 /// 예) log level emergency /// /// 1.4 Hex 로그. /// LOG_HEX( level, data, size ) 매크로 사용 /// 예) 00010203 04050607 08090A0B 0C0D0E0F /// ///2. Logger 객체 초기화시 전달된 Log Level 정보보다 전달받은 Log Level 정보가 큰 경우 해당 로그는 파일로 저장되지 않는다. /// ///3. 로그 파일은 매 일단위로 저장파일이 변경된다. /// ///4. 로그 저장을 위한 program 경로가 존재하지 않는 경우 자동 생성 처리된다. /// ///5. 로그 저장방식은 매 저장로그마다 open-close 로 처리된다. /// ///6. 파일로 기록시 Log Level 에 대한 정보도 함께 기록된다. /// ///7. 싱글톤으로 작성되었고, CLogger::Init(...)시에 쓰레드 안정성을 제공한다. /// ///8. 동적으로 로그 레벨을 변경할 수 있는 인터페이스를 제공한다. /// class CLogger { // Attributes private: ///@brief 싱글톤 객체 인트턴스. static CLogger* m_pInstance; ///@brief 싱글톤 객체 초기화 여부. static bool m_bIsInitialized; ///@brief 싱글톤 객체 초기화시 스레드 안정성을 위한 뮤텍스. static pthread_mutex_t m_mutex; ///@brief 프로그램 이름. 로그 파일 경로를 만들 때 사용. std::string m_szProgramName; ///@brief 공통 로그 디렉토리 이름. 로그 파일 경로를 만들 때 사용. std::string m_szLogDir; ///@brief 로그 레벨. int m_nLogLevel; ///@brief 로그 레벨에 대응되는 문자열 정보를 저장. std::vector m_vectorLogLevelString; protected: public: ///@brief 로그 형식을 지정. typedef enum { PREFIX_NONE = 0, /// 클래스 설명의 1.3에 해당 PREFIX_DATE, /// 클래스 설명의 1.2에 해당 PREFIX_FUNCTION, /// 클래스 설명의 1.1에 해당 } LOG_PREFIX; // Operations private: ///@brief 생성자. /// 프로그램 이름, 공통 로그 디렉토리, 로그 레벨을 저장하고 /// 로그 레벨에 대응되는 문자열 정보를 만든다. ///@param programName [in] 프로그램 이름 ///@param logDir [in] 공통 로그 디렉토리 경로 ///@param logLevel [in] 로그 레벨 CLogger( std::string programName, std::string logDir, int logLevel ); ///@brief 소멸자. /// 로그 레벨에 대응되는 문자열 정보를 저장하고 있는 /// 벡터 m_vectorLogLevelString을 clear 시킴. virtual ~CLogger(); ///@brief 로그 레벨에 대응되는 문자열을 만든다. ///@param none. ///@return none. void MakeLogLevelString(); ///@brief 로그 파일이 위치할 실제 로그 디렉토리를 생성한다. /// 생성할 디렉토리 경로는 'logDir/programName'이 된다. ///@param programName [in] 프로그램 이름 ///@param logDir [in] 공통 로그 디렉토리 경로 ///@return 디렉토리가 이미 존재하거나 생성 성공하면 true, /// 해당 경로가 존재하지만 디렉토리가 아니거나, 디렉토리 생성 실패하면 false 반환. static bool MakeLogDir( std::string programName, std::string logDir ); ///@brief 해당 경로가 디렉토리 인지 아닌지 판단. ///@param path [in] 디렉토리 인지 아닌지 판단할 경로. ///@return 해당 경로가 디렉토이면 true, /// 경로가 존재하지 않거나 디렉토리가 아니면 false 반환. static bool IsDirectory( std::string path ); ///@brief 로그 레벨이 올바른지 판별. ///@param logLevel [in] ///@return 올바른 로그 레벨이면 true, 그렇지 않으면 false 반환. static bool IsValidLogLevel( int logLevel ); ///@brief 시간 정보를 입력 받아 로그 파일 이름을 만든다. /// 로그 파일 이름 형식 : 프로그램명_YYYYMMDD.log ///param timeNow [in] 현재 시간 정보. ///return 로그 파일 이름. std::string GetLogFilename( struct tm &timeNow ); ///@brief 로그를 남기는는 클래스가 정의된 파일의 이름에서 클래스명을 추출한다. /// 쓰레드 안정성을 보장한다. ///@param className [out] 파일 이름에서 추출된 클래스명 ///@param filename [in] 파일 이름. ///@return 클래스명 추출이 성공하면 클래스명 문자열의 포인터, 추출 실패하면 NULL. const char* GetClassName( char* className, const char* filename ); ///@brief 인자 logPrefix에 따라 적절한 형식으로 로그 파일에 로그를 저장한다. /// 인자 logLevel이 설정된 로그 레벨보다 높으면 로그를 출력하지 않는다. ///@param logLevel [in] 로그 레벨 ///@param logPrefix [in] 로그 프리픽스 종류. ///@functionName [in] ClassName::FunctionNmae() 형식의 문자열. ///@lineNum [in] 라인 번호. ///@log [in] 출력하고자 하는 로그 내용. bool Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log ); protected: public: ///@brief 싱글톤 객체 m_pInstance를 생성하고 인자 정보로 로그 디렉토리를 만든다. ///@param programName [in] 프로그램 이름 ///@param logDir [in] 공통 로그 디렉토리 경로 ///@param logLevel [in] 로그 레벨 ///@return 로그 디렉토리를 만들고 싱글톤 객체를 생성했으면 true, /// 로그 디렉토리를 만들지 못 했거나 인자 값이 올바르지 않으면 false 반환. static bool Init( std::string programName, std::string logDir, int logLevel ); ///@brief 싱글톤 객체 m_pInstance를 delete 한다. ///@param none. ///@return none. static void Exit(); ///@brief 싱글톤 객체 m_pInstance를 반환한다. ///@param none. ///@return CLogger 객체의 인스턴스. static CLogger* GetInstance(); ///@brief Prefix로 [hh:mm:ss]이 추가된 형식으로 로그 저장. ///@param logLevel [in] 로그 레벨 ///@param fmt [in] 로그 내용 포맷. ///@param __VAR_ARGS__ [in] 가변 인자. ///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환 bool Write( int logLevel, const char * fmt, ...) __attribute__((format(printf, 3, 4))); ///@brief Prefix가 없는 로그 저장. ///@param logLevel [in] 로그 레벨 ///@param fmt [in] 로그 내용 포맷. ///@param __VAR_ARGS__ [in] 가변 인자. ///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환 bool WriteNoPrefix( int logLevel, const char * fmt, ...) __attribute__((format(printf, 3, 4))); // CHG 2012-08-16 huibong // 가변인자를 사용하는 Write 함수 다중 정의로 인해... // Complier 에서 인수 갯수 및 Type 이 동일할 경우 다른 함수를 가르키는 현상이 발견됨. // 이를 해결하기 위해 Write 함수에 대한 다중 정의를 제거토록 함수명을 명확하게 변경처리함. ///@brief Prefix로 [hh:mm:ss]와 [ClassName::FunctionName:line]이 추가된 형식으로 로그 저장. ///@param logLevel [in] 로그 레벨 ///@param filename [in] 파일 이름 ///@param funcname [in] 함수 이름 ///@param lineNum [in] 라인 번호 ///@param fmt [in] 로그 내용 포맷. ///@param __VAR_ARGS__ [in] 가변 인자. ///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환 bool WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...) __attribute__((format(printf, 6, 7))); ///@brief 로그를 hex 형식으로 저장. ///@param logLevel [in] 로그 레벨 ///@param data [in] hex 형식으로 출력할 데이터. ///@pram size [in] data의 크기. ///@return 로그 파일에 로그를 저장했으면 true, 그렇지 않으면 false 반환 bool WriteHex( int logLevel, const unsigned char* data, const int size ); ///@brief 로그을 설정한다. 인자 logLevel이 적절한 값이면 새로운 값으로 변경하고 /// 적절한 값이 아니면 로그 레벨을 변경하지 않는다. ///@param logLevel [in] 설정할 로그 레벨 ///@return none. bool SetLogLevel( int logLevel ); inline int GetLogLevel() { return m_nLogLevel; }; inline std::string GetLogDir() { return m_szLogDir + "/" + m_szProgramName; }; }; #define LOG( level, format, ... ) \ if( CLogger::GetInstance() != NULL ) \ { \ CLogger::GetInstance()->WriteWithFunc( level, __FILE__, __FUNCTION__, __LINE__, format, ##__VA_ARGS__ ); \ } #define _LOG( level, format, ... ) \ if( CLogger::GetInstance() != NULL ) \ { \ CLogger::GetInstance()->Write( level, format, ##__VA_ARGS__ ); \ } #define _LOG_( level, format, ... ) \ if( CLogger::GetInstance() != NULL ) \ { \ CLogger::GetInstance()->WriteNoPrefix( level, format, ##__VA_ARGS__ ); \ } #define _LOG_HEX_( level, data, size ) \ if( CLogger::GetInstance() != NULL ) \ { \ CLogger::GetInstance()->WriteHex( level, (const unsigned char*)data, size ); \ } #define FUNC_BEGIN() LOG( LDEV1, "begin" ) #define FUNC_END() LOG( LDEV1, "end" ) #define FRM_BEGIN() LOG( LDEV2, "begin" ) #define FRM_END() LOG( LDEV2, "end" ) #endif // __LOGGER_H__