#include "StdAfx.h" #include "LoggerEntity.h" #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(LOG_LEVEL_NORMAL), m_pThread(NULL) { 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] = "信息"; } CLoggerEntity::~CLoggerEntity(void) { } /**************************************************************** **【函数名称】 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; default: m_strLoggerName = _T("log_unknow"); break; } if (lpFilePath == NULL) { // 默认路径 m_strFileDircet = _T("d:\\middleware_log"); } else { // 指定路径 m_strFileDircet = lpFilePath; } m_bStopLog = FALSE; // 初始化记录日志线程 m_pThread = AfxBeginThread(__logThread, this); } /**************************************************************** **【函数名称】 close **【函数功能】 日志关闭 **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::close( void ) { m_bStopLog = TRUE; m_bIsLogger = FALSE; WaitForSingleObject(m_pThread->m_hThread, INFINITE); __flush(); } /**************************************************************** **【函数名称】 start **【函数功能】 开始显示日志 **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::start( void ) { m_bIsLogger = TRUE; } /**************************************************************** **【函数名称】 stop **【函数功能】 停止显示日志 **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::stop( void ) { m_bIsLogger = FALSE; } /**************************************************************** **【函数名称】 log **【函数功能】 添加一条新日志 **【参数】 nClass:日志类型 nLevel:日志级别 format:日志信息 **【返回值】 *****************************************************************/ void CLoggerEntity::log( LOG_CLASS nClass, LOG_LEVEL nLevel, char* format, ... ) { // 解析日志信息参数 char szMsgBuffer[LOG_BUFFER_LENGTH]; memset(szMsgBuffer, 0, sizeof(szMsgBuffer)); va_list ap; va_start(ap, format); vsprintf_s(szMsgBuffer, format, ap); __pushLog(nClass, nLevel, szMsgBuffer); } /**************************************************************** **【函数名称】 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->SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); 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); } /**************************************************************** **【函数名称】 启动控制台窗口 **【函数功能】 __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) CreateDirectoryA(m_strFileDircet, NULL); // 创建日期目录 CString strPath = _T(""); strPath.Format(_T("%s\\%d-%d-%d"), m_strFileDircet, time.GetYear(), time.GetMonth(), time.GetDay()); 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 ) { // 检查过滤标志 if ((m_nFilterClass & nClass) == nClass && (m_nFilterLevel & nLevel) == nLevel) { // 获取当前时间 CTime t1 = CTime::GetCurrentTime(); CString strTime = t1.Format("%Y-%m-%d %H:%M:%S"); PLOG_ITEM pItem = new LOG_ITEM(nClass, nLevel, strTime, lpMessage); ASSERT(pItem != NULL); // 日志信息记入缓冲队列 m_LockSection.Lock(); // 保证缓冲区字节大小不超过10M if(m_ItemList.GetCount() < LOG_BUFFER_SIZE) m_ItemList.AddTail(pItem); m_LockSection.Unlock(); } } /**************************************************************** **【函数名称】 __pushLog **【函数功能】 从链表中弹出日志 **【参数】 **【返回值】 *****************************************************************/ CLoggerEntity::PLOG_ITEM CLoggerEntity::__popLog( void ) { CSingleLock Locker(&m_LockSection, TRUE); if(!m_ItemList.IsEmpty()) return m_ItemList.RemoveHead(); else return NULL; } /**************************************************************** **【函数名称】 __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, LogContent.GetLength(), 1, pFile); if(!m_bIsLogger) return; // UI展现 if(m_pListCtrl == NULL) { cout << LogContent; } else { // 定义系统日志显示条数的上限为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); // 日志显示行数控制(500) if(m_pListCtrl->GetItemCount() == 500) { m_pListCtrl->DeleteItem(499); } } } /**************************************************************** **【函数名称】 记录日志线程函数 **【函数功能】 __logThreadFunc **【参数】 pParam:线程参数 **【返回值】 *****************************************************************/ UINT CLoggerEntity::__logThread( LPVOID pParam ) { CLoggerEntity* pSelf = (CLoggerEntity*)pParam; FILE *pFile = NULL; PLOG_ITEM pItem = NULL; while(!pSelf->m_bStopLog) { // 获取文件指针 pFile = pSelf->__openLoggerFile(); if(pFile != NULL) { while((pItem = pSelf->__popLog()) != NULL) { pSelf->__saveLog(pItem, pFile); delete pItem; } // 关闭文件 fclose(pFile); } // 暂停一秒钟 Sleep(1000); } return 0; } /**************************************************************** **【函数名称】 __flush **【函数功能】 保存残留的LOGITEM **【参数】 **【返回值】 *****************************************************************/ void CLoggerEntity::__flush( void ) { if(m_ItemList.IsEmpty()) return; FILE *pFile = __openLoggerFile(); if(pFile == NULL) return; while(!m_ItemList.IsEmpty()) { PLOG_ITEM pItem = m_ItemList.RemoveHead(); ASSERT(pItem != NULL); __saveLog(pItem, pFile); delete pItem; } fclose(pFile); }