#include #include #include #include #include "logfile.h" #include "fileutil.h" ///////////////////////////////////////////////////////////////////////////// CLogfile::CLogfile(void) : m_pf(NULL), m_bAttached(false), m_bClose(false), m_vb(VB_Off), m_nFileSize(0), m_nMaxFileSize(0), m_nMaxBackupFiles(0) { m_lsync = PTHREAD_MUTEX_INITIALIZER; } CLogfile::CLogfile(FILE *pf, bool bClose, int verb) : m_pf(pf), m_bAttached(false), m_bClose(false), m_vb(VB_Off), m_nFileSize(0), m_nMaxFileSize(0), m_nMaxBackupFiles(0) { m_lsync = PTHREAD_MUTEX_INITIALIZER; if(!Attach(pf, bClose, verb)) { StdErr("CLogfile::Attach failed!\n"); throw EINVAL; } } CLogfile::CLogfile(const char *pszFilename, bool bAppend, int verb, size_t nMaxFileSize, unsigned int nMaxBackupFiles) : m_pf(NULL), m_bAttached(false), m_bClose(false), m_vb(VB_Off), m_nFileSize(0), m_nMaxFileSize(0), m_nMaxBackupFiles(0) { m_lsync = PTHREAD_MUTEX_INITIALIZER; if(!Open(pszFilename, bAppend, verb, nMaxFileSize, nMaxBackupFiles)) { StdErr("CLogfile::Open failed!\n"); throw errno; } } CLogfile::~CLogfile(void) { Close(); ::pthread_mutex_destroy(&m_lsync); } void CLogfile::SetVerbosity(int verb) { if(verb < VB_Off) verb = VB_Off; else if(verb >= VB_Dbg) verb = VB_Dbg; m_vb = (Verbosity)verb; } ///////////////////////////////////////////////////////////////////////////// bool CLogfile::Open(const char *pszFilename, bool bAppend, int verb, size_t nMaxFileSize, unsigned int nMaxBackupFiles) { if(!pszFilename || !*pszFilename) return false; if(nMaxBackupFiles < 1) nMaxBackupFiles = 1; Close(); if((m_pf = fopen(pszFilename, bAppend ? "ab" : "wb"))) { char szBuf[PATH_MAX]; m_strFilePath = ::realpath(pszFilename, szBuf); m_nFileSize = GetFileSize(); m_bAttached = false; m_bClose = true; m_nMaxFileSize = nMaxFileSize; m_nMaxBackupFiles = nMaxBackupFiles; SetVerbosity(verb); ProcessFileSizeLimit(m_pf); } return m_pf != NULL; } void CLogfile::Close(void) { CsLock(); if(m_pf) { if(!m_bAttached || m_bClose) fclose(m_pf); m_pf = NULL; } m_bClose = false; m_bAttached = false; m_nFileSize = 0; m_nMaxFileSize = 0; m_nMaxBackupFiles = 0; m_vb = VB_Off; m_strFilePath.clear(); CsUnlock(); } void CLogfile::Flush(void) { if(m_pf) fflush(m_pf); } ///////////////////////////////////////////////////////////////////////////// bool CLogfile::Attach(FILE *pf, bool bClose, int verb) { if(!pf) { errno = EINVAL; return false; } Close(); m_pf = pf; m_bAttached = true; m_bClose = bClose; SetVerbosity(verb); return true; } void CLogfile::Detach(void) { CsLock(); if(m_bAttached) { m_pf = NULL; m_bClose = false; m_bAttached = false; } CsUnlock(); } ///////////////////////////////////////////////////////////////////////////// void CLogfile::Log(FILE *pf, const char *pszFormat, va_list args) { int nLen; CsLock(); if((nLen = vfprintf(pf, pszFormat, args)) > 0) { fflush(pf); m_nFileSize += nLen; ProcessFileSizeLimit(pf); } CsUnlock(); } void CLogfile::Log(const char *pszFormat, ...) { if(m_pf && pszFormat && *pszFormat) { va_list args; va_start(args, pszFormat); Log(m_pf, pszFormat, args); va_end(args); } } ///////////////////////////////////////////////////////////////////////////// void CLogfile::Debug(const char *pszFormat, ...) { if(m_vb >= VB_Dbg) { const char *pszFmt; std::string sFormat; if((pszFmt = CreateFormatString(VB_Dbg, pszFormat, sFormat))) { va_list args; va_start(args, pszFormat); Log(m_pf, pszFmt, args); va_end(args); } } } void CLogfile::Info(const char *pszFormat, ...) { if(m_vb >= VB_Inf) { const char *pszFmt; std::string sFormat; if((pszFmt = CreateFormatString(VB_Inf, pszFormat, sFormat))) { va_list args; va_start(args, pszFormat); Log(m_pf, pszFmt, args); va_end(args); } } } void CLogfile::Warning(const char *pszFormat, ...) { if(m_vb >= VB_War) { const char *pszFmt; std::string sFormat; if((pszFmt = CreateFormatString(VB_War, pszFormat, sFormat))) { va_list args; va_start(args, pszFormat); Log(m_pf, pszFmt, args); va_end(args); } } } void CLogfile::Error(const char *pszFormat, ...) { if(m_vb >= VB_Err) { const char *pszFmt; std::string sFormat; if((pszFmt = CreateFormatString(VB_Err, pszFormat, sFormat))) { va_list args; va_start(args, pszFormat); Log(m_pf, pszFmt, args); va_end(args); } } } size_t CLogfile::GetFileSize(void) { CsLock(); size_t s = m_pf ? ::GetFileSize(m_pf) : 0; CsUnlock(); return s; } bool CLogfile::ProcessFileSizeLimit(FILE *pf) { if(m_nMaxFileSize && !m_bAttached && pf && (pf == m_pf)) { if(m_nFileSize >= m_nMaxFileSize) { char szBuf1[PATH_MAX], szBuf2[PATH_MAX]; std::string strFilePath = m_strFilePath; Verbosity vb = m_vb; size_t nMaxFileSize = m_nMaxFileSize; int nMaxBackupFiles = m_nMaxBackupFiles; fclose(m_pf); m_pf = NULL; m_bClose = false; m_bAttached = false; m_nFileSize = 0; m_nMaxFileSize = 0; m_nMaxBackupFiles = 0; m_vb = VB_Off; m_strFilePath.clear(); snprintf(szBuf1, sizeof(szBuf1), "%s.%03u", strFilePath.c_str(), nMaxBackupFiles); remove(szBuf1); for(int i = nMaxBackupFiles; i > 1; --i) { snprintf(szBuf2, sizeof(szBuf2), "%s.%03u", strFilePath.c_str(), i); snprintf(szBuf1, sizeof(szBuf1), "%s.%03u", strFilePath.c_str(), i - 1); rename(szBuf1, szBuf2); } rename(strFilePath.c_str(), szBuf1); return Open(strFilePath.c_str(), false, vb, nMaxFileSize, nMaxBackupFiles); } } return false; } ///////////////////////////////////////////////////////////////////////////// void CLogfile::StdOut(const char *pszFormat, ...) { if(pszFormat && *pszFormat) { va_list args; va_start(args, pszFormat); vfprintf(stdout, pszFormat, args); va_end(args); fflush(stdout); } } void CLogfile::StdErr(const char *pszFormat, ...) { if(pszFormat && *pszFormat) { va_list args; va_start(args, pszFormat); vfprintf(stderr, pszFormat, args); va_end(args); fflush(stderr); } } ///////////////////////////////////////////////////////////////////////////// const char* CLogfile::CreateFormatString(Verbosity verb, const char *pszFormat, std::string &ret) const { time_t ts = time(NULL); char szBuf[128], szTime[64]; struct tm *pm = localtime(&ts); strftime(szTime, sizeof(szTime), "%d.%m.%Y %H:%M:%S", pm); switch(verb) { case VB_Dbg: sprintf(szBuf, "%s - DEBUG: ", szTime); break; case VB_Inf: sprintf(szBuf, "%s - INFO: ", szTime); break; case VB_War: sprintf(szBuf, "%s - WARNING: ", szTime); break; case VB_Err: sprintf(szBuf, "%s - ERROR: ", szTime); break; default: return NULL; } ret = szBuf; ret += pszFormat; return ret.c_str(); } ///////////////////////////////////////////////////////////////////////////// void CLogfile::CsLock(void) { ::pthread_mutex_lock(&m_lsync); } void CLogfile::CsUnlock(void) { ::pthread_mutex_unlock(&m_lsync); }