#ifndef __LOGMANAGER__H_
#define __LOGMANAGER__H_
#include <cstdio>
#include <queue>
#include <string>
#include "singleton.h"
#include "util.h"
#include "CMutex.h"
#include "CThread.h"
using namespace std;
enum LogType{ LOG_TYPE_SCREEN = 0, LOG_TYPE_FILE, LOG_TYPE_MAX};
enum LogLevel{
LOG_LEVEL_ERR = 0,
LOG_LEVEL_DBG,
LOG_LEVEL_INFO,
LOG_LEVEL_FUNCTION,
LOG_LEVEL_MAX
};
#define MAX_PER_LOGFILE_SIZE 500*1024*1024 //单个日志文件的大小为500M
#define MAX_PER_LINE_LOG 2048 //一行日志最大缓存
struct tagLogItem
{
int iLevel;
string strLog;
};
class CLogmanger : public CSingleton<CLogmanger>, CThread
{
SINGLE_CLASS_INITIAL(CLogmanger);
public:
int Init(int iType, int iLevel, const char* szDir);
~CLogmanger();
void AddLogItem(int iLevel, const char *format, ...);
int StopLog();
int SetLogType(int iType);
protected:
virtual void* work();
private:
int Check();
FILE* GetFile();
private:
int m_iType;
int m_iLevel;
unsigned long m_lCount;
bool m_bInit;
string m_strDir;
FILE* m_pFile;
queue<tagLogItem> m_qLogItems;
};
#define sLog CLogmanger::Instance()
#define LOG_ERR(fmt, ...) sLog->AddLogItem(LOG_LEVEL_ERR, "[ERROR](%s:%s:%d)[Thread:%ld] " fmt, __FILE__, __FUNCTION__, __LINE__, get_thread_id_self(), ##__VA_ARGS__)
#define LOG_DBG(fmt, ...) sLog->AddLogItem(LOG_LEVEL_DBG, "[DEBUG](%s:%s:%d)[Thread:%ld] " fmt, __FILE__, __FUNCTION__, __LINE__, get_thread_id_self(), ##__VA_ARGS__)
#define LOG_INFO(fmt, ...) sLog->AddLogItem(LOG_LEVEL_INFO, "[INFO][Thread:%ld] " fmt, get_thread_id_self(), ##__VA_ARGS__)
#define LOG_FUNCTION(fmt, ...) sLog->AddLogItem(LOG_LEVEL_DBG, "[FUNCTION](%s)[Thread:%ld] " fmt, __FUNCTION__, get_thread_id_self(), ##__VA_ARGS__)
#define ASSERT(expr) do{if (!(expr)){LOG_ERR("assert \"%s\" failed", #expr);}}while(0)
#define ASSERT_RET(expr) do{if (!(expr)){LOG_ERR("assert \"%s\" failed", #expr); return ; }}while(0)
#define ASSERT_RET_VALUE(expr, retval) do{if (!(expr)){LOG_ERR("assert \"%s\" failed", #expr); return retval; }}while(0)
#define ASSERT_ERR_MSG(expr, fmt, ...) \
do \
{ \
if (!(expr)) \
{ \
LOG_ERR("assert \"%s\", msg:" fmt, #expr, ##__VA_ARGS__); \
} \
} while (0);
#define ASSERT_ERR_MSG_RET(expr, retval, fmt, ...) \
do \
{ \
if (!(expr)) \
{ \
LOG_ERR("assert \"%s\", msg:" fmt, #expr, ##__VA_ARGS__); \
return retval; \
} \
} while (0);
#endif
#include "stdafx.h"
#include "CLogmanager.h"
#define RESET 0
#define BRIGHT 1
#define DIM 2
#define UNDERLINE 4
#define BLINK 5
#define REVERSE 7
#define HIDDEN 8
#define BLACK 0
#define RED 1
#define GREEN 2
#define YELLOW 3
#define BLUE 4
#define MAGENTA 5
#define CYAN 6
#define WHITE 7
#if defined(WIN32) || defined(_WIN32)
#elif __linux__
#define COLOR_PRINT_BEGIN \033
#define COLOR_PRINT_END \033[0m
#endif
CLogmanger::CLogmanger()
{
m_iLevel = LOG_LEVEL_ERR;
m_iType = LOG_TYPE_SCREEN;
m_lCount = 0;
m_pFile = NULL;
m_strDir = "";
m_bInit = false;
}
CLogmanger::~CLogmanger()
{
if (NULL != m_pFile)
{
fclose(m_pFile);
m_pFile = NULL;
}
}
FILE* CLogmanger::GetFile()
{
if (m_iType == LOG_TYPE_FILE)
{
if (NULL != m_pFile && m_pFile != stdout)
{
fclose(m_pFile);
m_pFile = NULL;
}
struct system_time_t stNow = get_now_time();
char szFileName[1000];
safe_snprintf(szFileName, 1000, _TRUNCATE, "%02d-%02d-%02d-%02d-%02d-%02d.log", stNow.tm_year, stNow.tm_mon, stNow.tm_mday,
stNow.tm_hour, stNow.tm_min, stNow.tm_sec);
string strTmp = m_strDir;
if (!str_end_with(strTmp, "\\") && !str_end_with(strTmp, "/"))
{
strTmp += "/";
}
strTmp += szFileName;
m_pFile = safe_open_file(strTmp.c_str(), "a+");
if (nullptr == m_pFile)
{
m_pFile = stdout;
}
}
else
{
if (NULL != m_pFile && m_pFile != stdout)
{
fclose(m_pFile);
}
m_pFile = stdout;
}
return m_pFile;
}
int CLogmanger::Check()
{
//文件过大创建新文件
if (m_iType == LOG_TYPE_FILE && m_lCount >= MAX_PER_LOGFILE_SIZE)
{
GetFile();
if (m_pFile != nullptr)
{
m_lCount = 0;
}
}
return 0;
}
int CLogmanger::SetLogType(int iType)
{
if (!m_bInit || iType < LOG_TYPE_SCREEN || iType >= LOG_TYPE_MAX)
{
return -1;
}
if (iType == m_iType)
{
return 0;
}
m_iType = iType;
GetFile();
return 0;
}
void CLogmanger::AddLogItem(int iLevel, const char *format, ...)
{
if (iLevel > m_iLevel || iLevel > LOG_LEVEL_MAX || !m_bInit)
{
return;
}
char szBuf[MAX_PER_LINE_LOG];
memset(szBuf, 0, sizeof(szBuf));
int nPos = 0;
struct system_time_t stNow = get_now_time();
nPos = safe_snprintf(szBuf, MAX_PER_LINE_LOG - 1, _TRUNCATE, "[%02d/%02d/%02d %02d:%02d:%02d.%06d] ", stNow.tm_year, stNow.tm_mon, stNow.tm_mday, stNow.tm_hour, stNow.tm_min, stNow.tm_sec, stNow.tm_milliseconds);
va_list ap;
va_start(ap, format);
#if defined(WIN32) || defined(_WIN32)
nPos += vsnprintf_s(szBuf + nPos, MAX_PER_LINE_LOG - nPos - 1, _TRUNCATE, format, ap);
#elif __linux__
nPos += vsnprintf(szBuf + nPos, MAX_PER_LINE_LOG - nPos - 1, format, ap);
#endif
va_end(ap);
if (nPos > MAX_PER_LINE_LOG - 1)
{
nPos = MAX_PER_LINE_LOG - 1;
}
if (nPos > 0)
{
szBuf[nPos] = '\0';
}
tagLogItem stLog;
stLog.iLevel = iLevel;
stLog.strLog = szBuf;
m_cMutex.Lock();
m_qLogItems.push(stLog);
m_cMutex.UnLock();
}
int CLogmanger::Init(int iType, int iLevel, const char* szDir)
{
if (m_bInit)
{
return 1;
}
m_iType = iType;
m_iLevel = iLevel;
if (nullptr != szDir && strlen(szDir) > 0)
{
m_strDir = szDir;
}
else
{
m_strDir = get_app_path();
}
if (iType == LOG_TYPE_FILE)
{
if (make_dirs(szDir))
{
return 1;
}
}
GetFile();
if (NULL == m_pFile)
{
return 1;
}
else
{
Start();
}
m_bInit = true;
return 0;
}
int CLogmanger::StopLog()
{
m_bInit = false;
return Stop();
}
void* CLogmanger::work()
{
while (!m_bStop)
{
bool bBusy = false;
m_cMutex.Lock();
if (!m_qLogItems.empty())
{
tagLogItem stLog = m_qLogItems.front();
#if defined(WIN32) || defined(_WIN32)
if (m_iType == LOG_TYPE_SCREEN && stLog.iLevel == LOG_LEVEL_ERR)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);
}
#endif
fprintf(m_pFile, "%s\n", stLog.strLog.c_str());
#if defined(WIN32) || defined(_WIN32)
if (m_iType == LOG_TYPE_SCREEN && stLog.iLevel == LOG_LEVEL_ERR)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY);
}
#endif
m_qLogItems.pop();
bBusy = true;
m_lCount += (unsigned long)stLog.strLog.size();
}
m_cMutex.UnLock();
Check();
fflush(m_pFile);
if (!bBusy)
{
Wait();
}
}
return nullptr;
}