/*
* Copyright (C) 2012 Yee Young Han (http://blog.naver.com/websearch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "FileLog.h"
#include "TimeUtility.h"
#include "FileUtility.h"
#include
#ifndef WIN32
#include
#endif
extern bool LogFileCompare( const std::string & strFirst, const std::string & strSecond );
CFileLog::CFileLog() : m_sttFd(NULL), m_iLevel(LOG_ERROR), m_iMaxLogSize(DEFAULT_LOG_FILE_SIZE), m_iLogSize(0)
, m_iIndex(1), m_iMaxFolderSize(DEFAULT_LOG_FOLDER_SIZE), m_iFolderSize(0)
{
memset( m_szDate, 0, sizeof(m_szDate) );
}
CFileLog::~CFileLog()
{
Close();
}
/**
* @ingroup SipPlatform
* @brief ·Î±× ÆÄÀÏÀ» ÀúÀåÇÒ µð·ºÅ丮¸¦ ¼³Á¤ÇÑ´Ù.
* @param pszDirName ·Î±× ÆÄÀÏÀ» ÀúÀåÇÒ µð·ºÅ丮
* @return ¼º°øÇϸé true ¸¦ ¸®ÅÏÇÏ°í ±×·¸Áö ¾ÊÀ¸¸é false ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool CFileLog::Open( const char * pszDirName )
{
if( pszDirName == NULL ) return false;
int iLen = (int)strlen( pszDirName );
bool bRes = false;
if( iLen < 3 ) return false;
m_clsMutex.acquire();
if( m_strDirName.empty() )
{
#ifdef WIN32
if( pszDirName[iLen-1] == '\\' )
#else
if( pszDirName[iLen-1] == '/' )
#endif
{
m_strDirName.append( pszDirName, iLen - 1 );
}
else
{
m_strDirName = pszDirName;
}
if( CDirectory::Create( m_strDirName.c_str() ) )
{
m_iFolderSize = CDirectory::GetSize( m_strDirName.c_str() );
bRes = true;
}
}
m_clsMutex.release();
return bRes;
}
/**
* @ingroup SipPlatform
* @brief ·Î±× ÆÄÀÏ ÀúÀåÀ» ÁßÁöÇÑ´Ù.
* @returns true ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool CFileLog::Close( )
{
m_clsMutex.acquire();
if( m_strDirName.empty() == false )
{
if( m_sttFd != NULL )
{
fclose( m_sttFd );
m_sttFd = NULL;
}
m_strDirName.clear();
}
m_clsMutex.release();
return true;
}
/**
* @ingroup SipPlatform
* @brief ·Î±× ÆÄÀÏ¿¡ ·Î±×¸¦ ÀúÀåÇÑ´Ù.
* @param iLevel ·Î±× ÆÄÀÏ ·¹º§
* @param fmt ·Î±× ÆÄÀÏ¿¡ ÀúÀåÇÒ Æ÷¸Ë ¹®ÀÚ¿
* @param ... fmt Æ÷¸Ë¿¡ ÀÔ·ÂÇÒ ÀÎÀÚµé
* @return ¼º°øÇϸé true ¸¦ ¸®ÅÏÇÏ°í ±×·¸Áö ¾ÊÀ¸¸é false ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool CFileLog::Print( EnumLogLevel iLevel, const char * fmt, ... )
{
if( ( m_iLevel & iLevel ) == 0 ) return false;
va_list ap;
char szBuf[LOG_MAX_SIZE];
char szDate[9], szHeader[30];
struct tm sttTm;
switch( iLevel )
{
case LOG_ERROR:
snprintf( szHeader, sizeof(szHeader), "[ERROR] " );
break;
case LOG_INFO:
snprintf( szHeader, sizeof(szHeader), "[INFO] " );
break;
case LOG_DEBUG:
snprintf( szHeader, sizeof(szHeader), "[DEBUG] " );
break;
case LOG_NETWORK:
snprintf( szHeader, sizeof(szHeader), "[NETWORK] " );
break;
case LOG_SYSTEM:
snprintf( szHeader, sizeof(szHeader), "[SYSTEM] " );
break;
case LOG_SQL:
snprintf( szHeader, sizeof(szHeader), "[SQL] " );
break;
default:
memset( szHeader, 0, sizeof(szHeader) );
break;
}
// ÇöÀçÀÇ ½Ã°£À» ±¸ÇÑ´Ù.
struct timeval sttTime;
gettimeofday( &sttTime, NULL );
#ifdef WIN32
_localtime32_s( &sttTm, &sttTime.tv_sec );
#else
localtime_r( &sttTime.tv_sec, &sttTm );
#endif
snprintf( szDate, sizeof(szDate), "%04d%02d%02d", sttTm.tm_year + 1900, sttTm.tm_mon + 1, sttTm.tm_mday );
if( m_clsMutex.acquire() == false ) return false;
if( m_strDirName.empty() == false && strcmp( m_szDate, szDate ) )
{
// ÇöÀçÀÇ ³¯Â¥¿Í Ŭ·¡½º¿¡ ÀúÀåµÈ ³¯Â¥°¡ ´Ù¸¥ °æ¿ì¿¡´Â ·Î±× ÆÄÀÏÀ» »õ·Î Á¦ÀÛÇÏ¿©¼ Open ÇÑ´Ù.
char szFileName[FULLPATH_FILENAME_MAX_SIZE];
m_iIndex = 1;
OPEN_FILE:
m_iLogSize = 0;
snprintf( szFileName, sizeof(szFileName), "%s%c%04d%02d%02d_%d.txt", m_strDirName.c_str(), DIR_SEP, sttTm.tm_year + 1900, sttTm.tm_mon + 1, sttTm.tm_mday, m_iIndex );
// ÀÌ¹Ì Open µÈ ÆÄÀÏÀÌ ÀÖ´Â °æ¿ì¿¡´Â À̸¦ ´Ý´Â´Ù.
if( m_sttFd )
{
fclose( m_sttFd );
m_sttFd = NULL;
}
DeleteOldFile();
if( m_iMaxLogSize > 0 )
{
int64_t iFileSize = GetFileSize( szFileName );
if( iFileSize >= m_iMaxLogSize )
{
++m_iIndex;
goto OPEN_FILE;
}
m_iLogSize = (int)iFileSize;
}
m_sttFd = fopen( szFileName, "ab" );
if( m_sttFd == NULL )
{
printf( "log file(%s) open error\n", szFileName );
}
snprintf( m_szDate, sizeof(m_szDate), "%s", szDate );
}
else if( m_iMaxLogSize > 0 && m_iLogSize >= m_iMaxLogSize )
{
++m_iIndex;
goto OPEN_FILE;
}
m_clsMutex.release();
va_start( ap, fmt );
vsnprintf( szBuf, sizeof(szBuf)-1, fmt, ap );
va_end( ap );
if( m_clsMutex.acquire() == false ) return false;
if( m_sttFd )
{
int iWrite;
#ifdef WIN32
iWrite = fprintf( m_sttFd, "[%02d:%02d:%02d.%06u] %s[%u] %s\r\n"
, sttTm.tm_hour, sttTm.tm_min, sttTm.tm_sec, sttTime.tv_usec, szHeader, GetCurrentThreadId(), szBuf );
#else
iWrite = fprintf( m_sttFd, "[%02d:%02d:%02d.%06u] %s[%lu] %s\n"
, sttTm.tm_hour, sttTm.tm_min, sttTm.tm_sec, (unsigned int)sttTime.tv_usec, szHeader, (unsigned long)pthread_self(), szBuf );
#endif
fflush( m_sttFd );
m_iLogSize += iWrite;
m_iFolderSize += iWrite;
}
else
{
#ifdef WIN32
printf( "[%02d:%02d:%02d] %s%s\r\n", sttTm.tm_hour, sttTm.tm_min, sttTm.tm_sec, szHeader, szBuf );
#else
printf( "[%02d:%02d:%02d] %s%s\n", sttTm.tm_hour, sttTm.tm_min, sttTm.tm_sec, szHeader, szBuf );
#endif
}
m_clsMutex.release();
return true;
}
/**
* @ingroup SipPlatform
* @brief ·Î±× ·¹º§À» °¡Á®¿Â´Ù.
* @return ·Î±× ·¹º§À» ¸®ÅÏÇÑ´Ù.
*/
int CFileLog::GetLevel( )
{
return m_iLevel;
}
/**
* @ingroup SipPlatform
* @brief ·Î±× ÆÄÀÏ¿¡ ÀúÀåÇÒ ·Î±× ·¹º§À» ¼³Á¤ÇÑ´Ù. ¿©·¯ ·Î±×¸¦ ÀúÀåÇÒ °æ¿ì, '|' ¿¬»êÀÚ¸¦ ÀÌ¿ëÇÏ¿©¼ ¿©·¯ ·Î±× ·¹º§À» ¼³Á¤ÇÒ ¼ö ÀÖ´Ù.
* @param iLevel [in] µð¹ö±× ·Î±×¸¦ ÀúÀåÇÒ °æ¿ì, LOG_DEBUG ¸¦ ¼³Á¤ÇÑ´Ù.
* Á¤º¸ ·Î±×¸¦ ÀúÀåÇÒ °æ¿ì, LOG_INFO ¸¦ ¼³Á¤ÇÑ´Ù.
* ¿¡·¯ ·Î±×¸¦ ÀúÀåÇÒ °æ¿ì, LOG_ERROR ¸¦ ¼³Á¤ÇÑ´Ù.
*/
void CFileLog::SetLevel( int iLevel )
{
m_iLevel = LOG_ERROR | LOG_SYSTEM;
m_iLevel |= iLevel;
}
/**
* @ingroup SipPlatform
* @brief ÀÔ·ÂÇÑ ·Î±× ·¹º§ÀÌ ÇöÀç Ãâ·ÂÇÒ ¼ö ÀÖ´Â ·Î±× ·¹º§ÀÎÁö ºÐ¼®ÇÏ¿© ÁØ´Ù.
* @param iLevel [in] ·Î±× ·¹º§
* @return ÇöÀç Ãâ·ÂÇÒ ¼ö ÀÖ´Â ·Î±× ·¹º§ÀÎ °æ¿ì¿¡´Â true ¸¦ ¸®ÅÏÇÏ°í ±×·¸Áö ¾ÊÀ¸¸é false ¸¦ ¸®ÅÏÇÑ´Ù.
*/
bool CFileLog::IsPrintLogLevel( EnumLogLevel iLevel )
{
if( ( m_iLevel & iLevel ) == 0 ) return false;
return true;
}
/**
* @ingroup SipPlatform
* @brief ·Î±×¸¦ ÀúÀåÇÒ ÃÖ´ë ÆÄÀÏ Å©±â¸¦ ¼³Á¤ÇÑ´Ù.
* @param iSize ·Î±×¸¦ ÀúÀåÇÒ ÃÖ´ë ÆÄÀÏ Å©±â
*/
void CFileLog::SetMaxLogSize( int iSize )
{
if( iSize < MIN_LOG_FILE_SIZE )
{
iSize = MIN_LOG_FILE_SIZE;
}
else if( iSize > MAX_LOG_FILE_SIZE )
{
iSize = MAX_LOG_FILE_SIZE;
}
m_iMaxLogSize = iSize;
}
/**
* @ingroup SipPlatform
* @brief ·Î±× Æú´õ ÃÖ´ë Å©±â¸¦ ¼³Á¤ÇÑ´Ù.
* @param iSize ·Î±× Æú´õ ÃÖ´ë Å©±â
*/
void CFileLog::SetMaxFolderSize( int64_t iSize )
{
// ÃÖ¼Ò 30ÀÏ ·Î±× ÆÄÀÏ ÀúÀå °ø°£À» È®º¸ÇÑ´Ù.
if( m_iMaxLogSize == 0 )
{
if( iSize < ( MIN_LOG_FILE_SIZE * 30 ) )
{
iSize = MIN_LOG_FILE_SIZE * 30;
}
}
else
{
if( iSize < m_iMaxLogSize * 30 )
{
iSize = m_iMaxLogSize * 30;
}
}
m_iMaxFolderSize = iSize;
}
/**
* @ingroup SipPlatform
* @brief ·Î±× Æú´õÀÇ Å©±â°¡ ¼³Á¤µÈ Å©±âº¸´Ù Å« °æ¿ì, ¿À·¡µÈ ·Î±× ÆÄÀÏÀ» »èÁ¦ÇÑ´Ù.
*/
void CFileLog::DeleteOldFile( )
{
if( m_iMaxFolderSize == 0 ) return;
if( m_strDirName.empty() ) return;
if( m_iFolderSize >= m_iMaxFolderSize )
{
int64_t iWantSize = m_iMaxFolderSize * 8 / 10;
FILE_LIST clsFileList;
FILE_LIST::iterator itList;
int64_t iFileSize;
CDirectory::FileList( m_strDirName.c_str(), clsFileList );
clsFileList.sort( LogFileCompare );
for( itList = clsFileList.begin(); itList != clsFileList.end(); ++itList )
{
std::string strFileName = m_strDirName;
CDirectory::AppendName( strFileName, itList->c_str() );
iFileSize = GetFileSize( strFileName.c_str() );
#ifdef WIN32
DeleteFile( strFileName.c_str() );
#else
unlink( strFileName.c_str() );
#endif
m_iFolderSize -= iFileSize;
if( m_iFolderSize < iWantSize ) break;
}
}
}