#include "StdAfx.h" #include "LoggerEntity.h" #include #include #include #include #include SINGLETON_IMPLEMENT(CLoggerEntity) ILogger& ILogger::getInstance(void) { return CLoggerEntity::GetInstance(); } CLoggerEntity::CLoggerEntity(void) : m_bStopLog(TRUE), m_bIsLogger(FALSE), m_nFilterClass(LOG_CLASS_GENERAL), m_nFilterLevel(0x07), m_pThread(nullptr), m_logBufferSize(0), m_pListCtrlCount(100) { m_arClass[0] = "PDU"; m_arClass[1] = "DEV"; m_arClass[2] = "业务"; m_arClass[3] = "基本"; m_arLevel[0] = ""; m_arLevel[1] = "警告"; m_arLevel[2] = "错误"; m_arLevel[3] = "信息"; m_arLevel[4] = "详细"; } CLoggerEntity::~CLoggerEntity(void) { //close(); } /**************************************************************** **【函数名称】 init **【函数功能】 日志初始化 **【参数】 pList:日志显示的List控件 nDevType:使用日志的系统 lpFilePath:日志记录路径 **【返回值】 *****************************************************************/ void CLoggerEntity::init(CListCtrl* pList, LOG_DEV nDevType, LPCTSTR lpFilePath /*= NULL */ ) { // 列表控件的初始化 if((m_pListCtrl = pList) != NULL) __frameControl(); else __initConsoleWindow(); // 保存设备类型 m_nDevType = nDevType; switch(m_nDevType) { case LOG_DEV_CTI: m_strLoggerName = _T("log_cti"); break; case LOG_DEV_IVR: m_strLoggerName = _T("log_ivr"); break; case LOG_DEV_ACD: m_strLoggerName = _T("log_acd"); break; case LOG_DEV_VS: m_strLoggerName = _T("log_vs"); break; case LOG_DEV_FS: m_strLoggerName = _T("log_fs"); break; case LOG_DEV_AC: m_strLoggerName = _T("log_ac"); break; case LOG_DEV_SC: m_strLoggerName = _T("log_sc"); break; case LOG_DEV_GUARD: m_strLoggerName = _T("log_guard"); break; case LOG_DEV_SERVER: m_strLoggerName = _T("log_http"); break; default: m_strLoggerName = _T("log_unknow"); break; } if (lpFilePath == NULL) { // 默认路径 m_strFileDircet = _T("d:\\middleware_log"); } else { // 指定路径 m_strFileDircet = lpFilePath; } m_bStopLog = FALSE; // 初始化记录日志线程 if (m_pThread == nullptr) m_pThread = std::make_shared(std::bind(&CLoggerEntity::logThread, this)); } /**************************************************************** **【函数名称】 close **【函数功能】 日志关闭 **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::close(void) { m_bIsLogger = FALSE; m_bStopLog.store(true); m_cond.notify_one(); // 条件变量通知 if (m_pThread&& m_pThread->joinable()) { m_pThread->join(); } __flush(); } /**************************************************************** **【函数名称】 start **【函数功能】 开始显示日志 **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::start( void ) { m_bIsLogger = TRUE; } /**************************************************************** **【函数名称】 stop **【函数功能】 停止显示日志 **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::stop( void ) { std::unique_lock lock(m_mut); m_bIsLogger = FALSE; lock.unlock(); } /**************************************************************** **【函数名称】 log **【函数功能】 添加一条新日志 **【参数】 nClass:日志类型 nLevel:日志级别 format:日志信息 **【返回值】 *****************************************************************/ void CLoggerEntity::log(LOG_CLASS nClass, LOG_LEVEL nLevel, char* format, ...) { try { if (!m_bIsLogger) return; // 检查过滤标志 if (!m_bStopLog && (m_nFilterClass & nClass) == nClass && (m_nFilterLevel & nLevel) == nLevel && nLevel < 5) { // 解析日志信息参数 char szMsgBuffer[LOG_BUFFER_LENGTH]; memset(szMsgBuffer, 0, sizeof(szMsgBuffer)); va_list ap; va_start(ap, format); vsnprintf(szMsgBuffer, sizeof(szMsgBuffer), format, ap); va_end(ap); __pushLog(nClass, nLevel, szMsgBuffer); } } catch (CException* e) { std::ofstream file("logger_except.txt", std::ios::app); if (file) { file << "CException 异常:"; TCHAR szErr[1024]; if (e->GetErrorMessage(szErr, 1024)) file << szErr << std::endl; file.close(); } e->Delete(); } } /**************************************************************** **【函数名称】 filterShow **【函数功能】 设置日志内容过滤方式 **【参数】 nClass:日志类型 nLevel:日志级别 **【返回值】 *****************************************************************/ void CLoggerEntity::filterShow( LOG_CLASS nClass /*= LOG_CLASS_GENERAL*/, LOG_LEVEL nLevel /*= LOG_LEVEL_NORMAL */ ) { m_nFilterClass = nClass; // 日志类型过滤 m_nFilterLevel = nLevel; // 日志级别过滤 } /**************************************************************** **【函数名称】 __frameControl **【函数功能】 日志界面控制 **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::__frameControl() { CRect mRect; m_pListCtrl->GetClientRect(&mRect); int length = mRect.right - mRect.left - 240; //加载日志图标信息 CImageList imgList; imgList.Create(16, 16, ILC_MASK|ILC_COLOR16, 3, 1); imgList.Add(AfxGetApp()->LoadStandardIcon(IDI_INFORMATION)); imgList.Add(AfxGetApp()->LoadStandardIcon(IDI_WARNING)); imgList.Add(AfxGetApp()->LoadStandardIcon(IDI_ERROR)); imgList.Add(AfxGetApp()->LoadStandardIcon(IDI_INFORMATION)); m_pListCtrl->SetImageList(&imgList, LVSIL_SMALL); imgList.Detach(); //加载日志列表 m_pListCtrl->SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_HEADERDRAGDROP | LVS_EX_INFOTIP | LVS_EX_SUBITEMIMAGES); m_pListCtrl->InsertColumn(0, (LPCTSTR)"时间", LVCFMT_LEFT, 140, -1); m_pListCtrl->InsertColumn(1, (LPCTSTR)"类型", LVCFMT_LEFT, 50, -1); m_pListCtrl->InsertColumn(2, (LPCTSTR)"分类", LVCFMT_LEFT, 50, -1); m_pListCtrl->InsertColumn(3, (LPCTSTR)"信息", LVCFMT_LEFT, length, -1); m_pListCtrl->SetItemCount(m_pListCtrlCount); // 设置总行数 } /**************************************************************** **【函数名称】 启动控制台窗口 **【函数功能】 __initConsoleWindow **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::__initConsoleWindow( void ) { if(!AllocConsole()) return; int nCrt = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT); if(nCrt == -1) return; FILE* fp = _fdopen(nCrt, "w"); if(fp == NULL) return; *stdout = *fp; setvbuf(stdout, NULL, _IONBF, 0); } /**************************************************************** **【函数名称】 创建日志文件 **【函数功能】 __openLoggerFile **【参数】 lpFile **【返回值】 *****************************************************************/ FILE* CLoggerEntity::__openLoggerFile( void ) { static int nCount = 1; FILE* pFile = NULL; // 获取当前日期 CTime time = CTime::GetCurrentTime(); // 创建日志总目录 if (_access(m_strFileDircet, 0) == -1) { boost::filesystem::create_directories(m_strFileDircet.GetBuffer(0)); m_strFileDircet.ReleaseBuffer(); } // 创建日期目录 CString strPath = _T(""); strPath.Format(_T("%s\\%d-%d-%d"), m_strFileDircet, time.GetYear(), time.GetMonth(), time.GetDay()); // 防止日期文件夹存在时,日志文件索引不会从1开始 static CString lastPath = strPath; // 初始化目录日期 if (lastPath != strPath) { nCount = 1; lastPath = strPath; } if(_access(strPath, 0) == -1) { nCount = 1; CreateDirectoryA(strPath, NULL); } // 如果文件存在且大于指定大小,生成新的文件名 CString strFileName = _T(""); struct stat st; do { memset(&st, 0, sizeof(st)); strFileName.Format(_T("%s\\%s_%d.txt"), strPath, m_strLoggerName, nCount); if(stat(strFileName, &st) == 0) { if(st.st_size > FILE_MAX_SIZE) nCount++; } } while(st.st_size > FILE_MAX_SIZE); // 打开文件 fopen_s(&pFile, strFileName, "a+"); return pFile; } /**************************************************************** **【函数名称】 __pushLog **【函数功能】 将日志压入链表 **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::__pushLog( LOG_CLASS nClass, LOG_LEVEL nLevel, LPCTSTR lpMessage ) { // 获取当前时间 CTime t1 = CTime::GetCurrentTime(); CString strTime = t1.Format("%Y-%m-%d %H:%M:%S"); if (m_logBufferSize.load() <= LOG_BUFFER_SIZE && !m_bStopLog.load()){ PLOG_ITEM pItem = new(std::nothrow)LOG_ITEM(nClass, nLevel, strTime, lpMessage); if (pItem != NULL){ std::unique_locklock(m_mut); m_ItemList.emplace_back(pItem); m_logBufferSize.store(m_ItemList.size()); m_cond.notify_one(); // 条件变量通知 } } } /**************************************************************** **【函数名称】 __logShow **【函数功能】 显示日志 **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::__saveLog( PLOG_ITEM pItem, FILE* pFile ) { LOG_CLASS Class = pItem->Class; LOG_LEVEL Level = pItem->Level; CString LogContent; LogContent.Format(_T("%s %s %s %s\r\n"), pItem->Date, m_arLevel[Level], m_arClass[Class], pItem->Content); // 写日志文件 fwrite(LogContent.GetBuffer(0), LogContent.GetLength(), 1, pFile); if(!m_bIsLogger || m_bStopLog.load()) return; if (Level > LOG_LEVEL_NORMAL) return; // UI展现 if(m_pListCtrl == NULL) { cout << LogContent; } else { // 日志显示行数控制(500) if (m_pListCtrl->GetItemCount() >= m_pListCtrlCount) { m_pListCtrl->DeleteAllItems(); } // 定义系统日志显示条数的上限为499条 m_pListCtrl->InsertItem(0, pItem->Date, Level); m_pListCtrl->SetItemText(0, 1, m_arLevel[Level]); m_pListCtrl->SetItemText(0, 2, m_arClass[Class]); m_pListCtrl->SetItemText(0, 3, pItem->Content); } } /**************************************************************** **【函数名称】 记录日志线程函数 **【函数功能】 __logThreadFunc **【参数】 pParam:线程参数 **【返回值】 *****************************************************************/ void CLoggerEntity::logThread() { PLOG_ITEM pItem = NULL; while (!m_bStopLog.load()) { std::unique_lock lock(m_mut); for (; m_ItemList.empty() && !m_bStopLog.load();) { m_cond.wait(lock); } if (m_bStopLog.load()) break; lock.unlock(); FILE *pFile = __openLoggerFile(); if (pFile) { for (; m_logBufferSize > 0 && !m_bStopLog.load();) { std::unique_lock lock1(m_mut); if (!m_ItemList.empty()) { pItem = m_ItemList.front(); m_ItemList.pop_front(); m_logBufferSize.store(m_ItemList.size()); lock1.unlock(); if (pItem) { __saveLog(pItem, pFile); delete pItem; pItem = NULL; } } else { m_logBufferSize.store(0); break; } } // 关闭文件 fclose(pFile); pFile = NULL; } } std::cout << "线程结束" << std::endl; } /**************************************************************** **【函数名称】 __flush **【函数功能】 保存残留的LOGITEM **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::__flush(void) { if (m_ItemList.empty()) return; FILE *pFile = __openLoggerFile(); if (pFile == NULL) return; for (auto pItem : m_ItemList) { if (pItem != NULL) { __saveLog(pItem, pFile); delete pItem; pItem = NULL; } } m_ItemList.clear(); fclose(pFile); pFile = NULL; }