/*************************************************************************** Logger.cpp ----------------------------------------- begin : 2011/10/26 copyright : (C) 2005 SolutionBox Inc. author : Service 1 Team email : svc1@solbox.com version : 1.0 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. ***************************************************************************/ #include "Logger.h" #include #include #include #include #include #include #include #include #define MAX_BUFFER_SIZE 2048 // Àӽà ¹öÆÛ ÃÖ´ë Å©±â #define DEFAULT_LOG_LEVEL LINF using namespace std; CLogger* CLogger::m_pInstance = NULL; bool CLogger::m_bIsInitialized = false; pthread_mutex_t CLogger::m_mutex = PTHREAD_MUTEX_INITIALIZER; CLogger::CLogger( string programName, string logDir, int logLevel ) { m_szProgramName = programName; m_szLogDir = logDir; if( IsValidLogLevel( logLevel ) == true ) { m_nLogLevel = logLevel; } else { m_nLogLevel = DEFAULT_LOG_LEVEL; } MakeLogLevelString(); } void CLogger::MakeLogLevelString() { m_vectorLogLevelString.push_back( "EMR" ); m_vectorLogLevelString.push_back( "ALT" ); m_vectorLogLevelString.push_back( "CRT" ); m_vectorLogLevelString.push_back( "ERR" ); m_vectorLogLevelString.push_back( "WAR" ); m_vectorLogLevelString.push_back( "NOT" ); m_vectorLogLevelString.push_back( "INF" ); m_vectorLogLevelString.push_back( "DBG" ); m_vectorLogLevelString.push_back( "DEV" ); m_vectorLogLevelString.push_back( "DEV1" ); m_vectorLogLevelString.push_back( "DEV2" ); } CLogger::~CLogger() { m_vectorLogLevelString.clear(); } bool CLogger::Init( string programName, string logDir, int logLevel ) { if( m_bIsInitialized == true ) { return true; } pthread_mutex_lock( &m_mutex ); // º¯¼ö À¯È¿¼º °Ë»ç. if( programName.empty() == true || logDir.empty() == true ) { pthread_mutex_unlock( &m_mutex ); return false; } if( IsValidLogLevel( logLevel ) == false ) { pthread_mutex_unlock( &m_mutex ); return false; } if( MakeLogDir( programName, logDir ) == false ) { pthread_mutex_unlock( &m_mutex ); return false; } if( CLogger::m_pInstance != NULL ) { delete CLogger::m_pInstance; CLogger::m_pInstance = NULL; } CLogger::m_pInstance = new CLogger( programName, logDir, logLevel ); m_bIsInitialized = true; pthread_mutex_unlock( &m_mutex ); return true; } bool CLogger::IsValidLogLevel( int logLevel ) { return ( ( logLevel < 0 || logLevel > MAX_LOG_LEVEL ) ? false : true ); } bool CLogger::SetLogLevel( int logLevel ) { if( IsValidLogLevel( logLevel ) == false ) { return false; } m_nLogLevel = logLevel; return true; } bool CLogger::MakeLogDir( string programName, string logDir ) { string path = logDir + "/" + programName; struct stat dirStat; // ÇØ´ç À̸§À» °¡Áø ÆÄÀÏ ¶Ç´Â µð·ºÅ丮°¡ Á¸ÀçÇϰí if( lstat( path.c_str(), &dirStat ) == 0 ) { // ÇØ´ç À̸§ÀÌ µð·ºÅ丮ÀÎ °æ¿ì if( S_ISDIR( dirStat.st_mode ) == true ) { return true; } else { cerr << "exist file with the same name as log path(" << path << ")." << endl; return false; } } // µð·ºÅ丮 °¡ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì µð·ºÅ丮 »ý¼º ½Ãµµ string cmd = "mkdir -p " + path; system( cmd.c_str() ); if( IsDirectory( path ) == false ) { cerr << "can't make log directory. path=" << path << "." << endl; return false; } return true; } bool CLogger::IsDirectory( string path ) { struct stat dirStat; if( lstat ( path.c_str(), &dirStat ) != 0 ) { cerr << "Log path not valid. Check path [" << path << "][" << errno << "][" << strerror(errno) << "]" << endl; return false; } // ÇØ´ç Á¤º¸°¡ Directory °¡ ¾Æ´Ñ °æ¿ì if( S_ISDIR( dirStat.st_mode ) == false ) { return false; } return true; } void CLogger::Exit() { if( m_bIsInitialized == false ) { return; } pthread_mutex_lock( &m_mutex ); if( CLogger::m_pInstance != NULL ) { delete CLogger::m_pInstance; CLogger::m_pInstance = NULL; m_bIsInitialized = false; } pthread_mutex_unlock( &m_mutex ); } CLogger* CLogger::GetInstance() { return CLogger::m_pInstance; } string CLogger::GetLogFilename( struct tm &timeNow ) { char timeStr[256]; snprintf( timeStr, (size_t)256, "%04d%02d%02d.log", timeNow.tm_year+1900, timeNow.tm_mon+1, timeNow.tm_mday); // Make File Name string filename = m_szLogDir + "/" + m_szProgramName + "/" + m_szProgramName + "_" + string( timeStr ); return filename; } bool CLogger::Write( int logLevel, const char * fmt, ...) { // °¡º¯ ÀÎÀÚ Ã³¸® va_list args; char buffer[MAX_BUFFER_SIZE]; va_start( args, fmt ); if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 ) { va_end( args ); return false; } va_end(args); return Write( logLevel, PREFIX_DATE, NULL, 0, buffer ); } bool CLogger::WriteNoPrefix( int logLevel, const char * fmt, ...) { // °¡º¯ ÀÎÀÚ Ã³¸® va_list args; char buffer[MAX_BUFFER_SIZE]; va_start( args, fmt ); if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 ) { va_end( args ); return false; } va_end(args); return Write( logLevel, PREFIX_NONE, NULL, 0, buffer ); return false; } // CHG 2012-08-16 huibong // °¡º¯ÀÎÀÚ¸¦ »ç¿ëÇÏ´Â Write ÇÔ¼ö ´ÙÁß Á¤ÀÇ·Î ÀÎÇØ... // Complier ¿¡¼­ Àμö °¹¼ö ¹× Type ÀÌ µ¿ÀÏÇÒ °æ¿ì ´Ù¸¥ ÇÔ¼ö¸¦ °¡¸£Å°´Â Çö»óÀÌ ¹ß°ßµÊ. // À̸¦ ÇØ°áÇϱâ À§ÇØ Write ÇÔ¼ö¿¡ ´ëÇÑ ´ÙÁß Á¤ÀǸ¦ Á¦°ÅÅä·Ï ÇÔ¼ö¸íÀ» ¸íÈ®ÇÏ°Ô º¯°æÃ³¸®ÇÔ. // ÇÔ¼ö¸í : Write -> WriteWithFunc À¸·Î º¯°æ ó¸® bool CLogger::WriteWithFunc( int logLevel, const char* filename, const char* funcname, int lineNum, const char * fmt, ...) { if( filename == NULL || funcname == NULL || lineNum < 0 || fmt == NULL ) { return false; } // °¡º¯ ÀÎÀÚ Ã³¸® va_list args; char buffer[MAX_BUFFER_SIZE]; va_start( args, fmt ); if( vsnprintf( buffer, MAX_BUFFER_SIZE, fmt, args) < 0 ) { va_end( args ); return false; } va_end(args); char className[255]; string funcPrefix = GetClassName( className, filename ); funcPrefix += "::" + string( funcname ) + "()"; return Write( logLevel, PREFIX_FUNCTION, funcPrefix.c_str(), lineNum, buffer ); } const char* CLogger::GetClassName( char* className, const char* filename ) { if( className == NULL ) { cout << "[ERROR] The input argument 'className' is NULL." << endl; return NULL; } if( filename == NULL ) { cout << "[ERROR] The input argument 'filename' is NULL." << endl; strcpy( className, "NULL" ); return className; } int filenameSize = strlen( filename ); memcpy( className, filename, filenameSize ); // find end position char endCharacter = '.'; int endPos = filenameSize - 1; for( ; endPos > 0; --endPos ) { if( className[endPos] == endCharacter ) { break; } } if( endPos == 0 ) { cout << "[ERROR] endPos=0" << endl; strcpy( className, "NULL" ); return className; } className[endPos] = '\0'; // find start position char startCharacter = '/'; int startPos = endPos - 1; for( ; startPos > 0; --startPos ) { if( className[startPos] == startCharacter ) { break; } } if( startPos != 0 ) { startPos += 1; } return (className + startPos ); } bool CLogger::Write( int logLevel, int logPrefix, const char* functionName, int lineNum, const char* log ) { /// À¯È¿ÇÑ ·Î±× ·¹º§ÀÌ ¾Æ´Ï¸é ·Î±ëÇÏÁö ¾ÊÀ½. if( IsValidLogLevel( logLevel ) == false ) { return false; } // Log Level °Ë»ç : ÁöÁ¤µÈ Level ÀÌ»óÀÎ °æ¿ì ·Î±ëÇÏÁö ¾ÊÀ½. if( logLevel > m_nLogLevel ) { return false; } if( log == NULL ) { return false; } // Get Current Data & Time time_t now = time( NULL ); struct tm timeNow; localtime_r( &now, &timeNow ); string filename = GetLogFilename( timeNow ); // Log file open FILE* pFile = NULL; pFile = fopen( filename.c_str(), "a+" ); if( pFile == NULL ) { cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl; return false; } // ½Ã°£ Á¤º¸Ã³¸® char timeStr[256]; snprintf( timeStr, (size_t)256, "[%02d:%02d:%02d]" , timeNow.tm_hour, timeNow.tm_min, timeNow.tm_sec ); // Log Level ¹®ÀÚ¿­ °Ë»ö string szLevel = m_vectorLogLevelString[ logLevel ]; switch( logPrefix ) { case PREFIX_DATE: /// Çü½Ä ¿¹: [15:47:41] [DBG] sample log message. fprintf( pFile, "%s [%-4s] %s\n", timeStr, szLevel.c_str(), log ); break; case PREFIX_FUNCTION: if( functionName == NULL ) { fclose( pFile ); return false; } /// Çü½Ä ¿¹: [15:47:41] [DBG] sample log message. [SomeClass::SomeFunction():12] fprintf( pFile, "%s [%-4s] %s [%s:%d]\n", timeStr, szLevel.c_str(), log, functionName, lineNum ); break; case PREFIX_NONE: /// Çü½Ä ¿¹: sample log message. fprintf( pFile, "%s\n", log ); break; } // Write to log file fflush( pFile ); // Á¾·á ó¸®. fclose( pFile ); return true; } bool CLogger::WriteHex( int logLevel, const unsigned char* data, const int size ) { /// À¯È¿ÇÑ ·Î±× ·¹º§ÀÌ ¾Æ´Ï¸é ·Î±ëÇÏÁö ¾ÊÀ½. if( IsValidLogLevel( logLevel ) == false ) { return false; } // Log Level °Ë»ç : ÁöÁ¤µÈ Level ÀÌ»óÀÎ °æ¿ì ·Î±ëÇÏÁö ¾ÊÀ½. if( logLevel > m_nLogLevel ) { return false; } if( data == NULL ) { return false; } if( size <= 0 ) { return false; } // Get Current Data & Time time_t now = time( NULL ); struct tm timeNow; localtime_r( &now, &timeNow ); string filename = GetLogFilename( timeNow ); // Log file open FILE* pFile = NULL; pFile = fopen( filename.c_str(), "a+" ); if( pFile == NULL ) { cerr << "Log file open fail.[" << filename.c_str() << "][" << errno << "][" << strerror(errno) << "]" << endl; return false; } for( int i = 0; i < size; ++i ) { fprintf( pFile, "%02X", data[i] ); if( i == 0 ) { continue; } if( ( (i+1) % 8 ) == 0 ) { fprintf( pFile, " " ); } if( ( (i+1) % 16 ) == 0 ) { fprintf( pFile, " " ); } if( ( (i+1) % 32 ) == 0 ) { fprintf( pFile, "\n" ); } } fprintf( pFile, "\n" ); fflush( pFile ); // Á¾·á ó¸®. fclose( pFile ); return false; }