📄 logger.cpp
字号:
/************************************************************************
模快名: moxu 公共类库
功能: 日志打印
完成日期: 2007-10-20
作者: 许 培 Xu Pei(Email/MSN: peimoxu@163.com)
本代码可以自由使用,但因使用本代码造成的后果,本人不承担任何责任
************************************************************************/
#include "StdAfx.h"
#include "Logger.h"
#include <time.h>
#include "Config.h"
#include "ScopeGuard.h"
#include "PathFile.h"
#define WM_PRINT_MSG WM_USER+1
#define WM_CLOSE_LOG WM_USER+2
#define WM_SET_CAPTION WM_USER+3
namespace moxu
{
namespace detail
{
//////////////////////////////////////////////////////////////////////////
//FileLog
bool FileLog::Create()
{
time_t t = time(0);
tm* pTm = localtime(&t);
m_fileName = TString(_T("c:\\")) + m_caption +
moxu::Str::Format(_T("%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d"),
pTm->tm_year+1900, pTm->tm_mon+1, pTm->tm_mday,
pTm->tm_hour, pTm->tm_min, pTm->tm_sec)
+ _T(".log");
m_file.imbue(std::locale("chs"));
m_file.open(moxu::Str::TtoA(m_fileName.c_str()).c_str(),
std::ios_base::out | std::ios_base::app);
m_bCreated = true;
return true;
}
void FileLog::Close()
{
if(m_bCreated)
{
m_file.close();
m_bCreated = false;
}
}
void FileLog::Print(const TString& msg)
{
if(m_bCreated)
m_file<<msg<<std::endl;
}
void FileLog::SetCaption(const TString& str)
{
m_caption = str;
if(m_bCreated)
{
Close();
Create();
}
}
//////////////////////////////////////////////////////////////////////////
//WndLog
bool WndLog::Create()
{
WNDCLASSEX winclass = {0};
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_NOCLOSE | CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WindowProc;
winclass.hInstance = 0;
winclass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
winclass.lpszClassName = _T("MYLOGGERWND");
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClassEx(&winclass);
m_hWnd = CreateWindowEx(
WS_EX_TOPMOST /*| WS_EX_TOOLWINDOW*/,
_T("MYLOGGERWND"),
m_caption.c_str(),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, 600, 300,
NULL,
NULL,
NULL,
NULL);
SetWindowLong(m_hWnd, GWL_USERDATA, (long)this);
RECT rct;
GetClientRect(m_hWnd, &rct);
m_hList = CreateWindowEx(
WS_EX_CLIENTEDGE,
_T("ListBox"),
_T("MyListBox"),
WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | LBS_NOINTEGRALHEIGHT,
rct.left, rct.top, rct.right, rct.bottom,
m_hWnd,
NULL,
(HINSTANCE)GetWindowLong(m_hWnd, GWL_HINSTANCE),
NULL);
HFONT font = CreateFont(
16, 0, 0, 10,
0, false, false, false,
ANSI_CHARSET,OUT_CHARACTER_PRECIS,
CLIP_CHARACTER_PRECIS,ANTIALIASED_QUALITY,
FF_DECORATIVE,
_T("Courier New"));
SendMessage(m_hList, WM_SETFONT,(WPARAM)font,(LPARAM)1);
m_bCreated = true;
return true;
}
void WndLog::Close()
{
if(m_bCreated)
{
SendMessage(m_hWnd, WM_CLOSE, 0, 0);
m_bCreated = false;
}
}
void WndLog::Print(const TString& msg)
{
if(m_bCreated)
{
SendMessage(m_hList, LB_INSERTSTRING, 0, (LPARAM)msg.c_str());
//Max size is 200, delete old item
SendMessage(m_hList, LB_DELETESTRING, 200, 0);
/*//显示水平滚动条
HDC hdc=::GetDC(m_hList);
SIZE size;
GetTextExtentPoint32(hdc, _T(""), lstrlen(_T("")),&size);
ReleaseDC(m_hList,hdc);
SendMessage(m_hList,LB_SETHORIZONTALEXTENT,(WPARAM)size.cx,0);
*/
}
}
void WndLog::SetCaption(const TString& str)
{
m_caption = str;
if(m_bCreated)
SetWindowText(m_hWnd, m_caption.c_str());
}
LRESULT CALLBACK WndLog::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
WndLog* pThis = (WndLog*)GetWindowLong(hWnd, GWL_USERDATA);
switch(uMsg)
{
case WM_SIZE :
if(SIZE_RESTORED == wParam || SIZE_MAXIMIZED == wParam)
{
if(pThis != NULL)
MoveWindow(pThis->m_hList, 0, 0, LOWORD(lParam), HIWORD(lParam), false);
}
break;
case WM_SETFOCUS:
if( pThis != NULL )
SetFocus((HWND)pThis->m_hList);
break;
/*case WM_CLOSE:
if(MessageBox(hWnd, _T("您确实要关闭日志窗口吗?"), _T("日志窗口"),
MB_ICONINFORMATION | MB_YESNO) != IDYES)
return 1;
break;*/
default:
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}//namespace detail
//////////////////////////////////////////////////////////////////////////
//Logger
Logger::Logger(void) :
m_bInfo(false),
m_bDebug(false),
m_bError(false),
m_bFileLog(false),
m_bWndLog(false),
m_pFileLog(NULL),
m_pWndLog(NULL)
{
}
Logger::~Logger(void)
{
if(m_bFileLog || m_bWndLog)
Close();
}
bool Logger::Create()
{
m_semaphore.Create(0, 1);
m_thread.Start(moxu::Bind(this, Logger::RunThread));
m_semaphore.Wait(); //wait first CheckConfig() in RunThread()
m_semaphore.Close();
return true;
}
void Logger::SetCaption(const TString& str)
{
moxu::ScopedLock locker(m_cs2);
m_caption = str;
if(m_bFileLog || m_bWndLog)
PostThreadMessage(m_thread.GetId(), WM_SET_CAPTION, 0, 0);
}
void Logger::Close()
{
PostThreadMessage(m_thread.GetId(), WM_CLOSE_LOG, 0, 0);
m_thread.Join();
}
void Logger::RunThread()
{
MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
CheckConfig();
m_semaphore.Release(1);
UINT timerId = SetTimer(NULL, 0, 30*1000, NULL);
int nTimeCounter = 0;
BOOL ret;
while((ret = GetMessage(&msg, NULL, 0, 0)) != 0)
{
//if(ret == -1){ error }
if(msg.message == WM_TIMER && msg.wParam == timerId)
{
CheckConfig();
if(m_bFileLog)
{
nTimeCounter++;
if(nTimeCounter == 10)
{
UINT64 size = moxu::PathFile::GetFileSize(
((detail::FileLog*)m_pFileLog)->GetFileName().c_str());
if(size > 1024*1024*5) //当文件过大时更换文件名
{
m_pFileLog->Close();
m_pFileLog->Create();
}
nTimeCounter = 0;
}
}
}
else if(msg.message == WM_PRINT_MSG)
{
Print();
}
else if(msg.message == WM_SET_CAPTION)
{
moxu::ScopedLock locker(m_cs2);
if(m_bWndLog)
m_pWndLog->SetCaption(m_caption);
if(m_bFileLog)
m_pFileLog->SetCaption(m_caption);
}
else if(msg.message == WM_CLOSE_LOG)
{
if(m_bWndLog)
{
m_pWndLog->Close();
delete m_pWndLog;
m_pWndLog = NULL;
m_bWndLog = false;
}
if(m_bFileLog)
{
m_pFileLog->Close();
delete m_pFileLog;
m_pFileLog = NULL;
m_bFileLog = false;
}
m_bInfo = false;
m_bDebug = false;
m_bError = false;
moxu::ScopedLock locker(m_cs);
m_strList.clear();
break;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
KillTimer(NULL, timerId);
}
void Logger::Info(LPCTSTR str, ...)
{
if(m_bInfo)
{
va_list args;
va_start(args, str);
AddLog(str, args);
va_end(args);
}
}
void Logger::Debug(LPCTSTR str, ...)
{
if(m_bDebug)
{
va_list args;
va_start(args, str);
AddLog(str, args);
va_end(args);
}
}
void Logger::Error(LPCTSTR str, ...)
{
if(m_bError)
{
va_list args;
va_start(args, str);
AddLog(str, args);
va_end(args);
}
}
void Logger::AddLog(LPCTSTR str, va_list args)
{
int len = 9 + (_vsctprintf(str, args) + 1); //message format: "hh:mm:ss message"
LPTSTR pStr = new TCHAR[len];
if(pStr == NULL)
throw _T("Alloc memory error");
moxu::ScopeGuard sg = moxu::MakeArrayGuard(pStr);
_tstrtime(pStr);
pStr[8] = ' ';
_vstprintf(pStr+9, str, args);
moxu::ScopedLock locker(m_cs);
m_strList.push_back(pStr);
PostThreadMessage(m_thread.GetId(), WM_PRINT_MSG, 0, 0);
}
void Logger::Print()
{
moxu::ScopedLock locker(m_cs);
for(int i=0; i<m_strList.size(); i++)
{
if(m_bWndLog)
m_pWndLog->Print(m_strList[i]);
if(m_bFileLog)
m_pFileLog->Print(m_strList[i]);
}
m_strList.clear();
}
void Logger::CheckConfig()
{
bool bWndLog, bFileLog;
bWndLog = moxu::Config::GetIniInt(_T("..\\Logger.ini"), _T("Test"), _T("WndLog"), 0);
if(m_bWndLog != bWndLog)
{
m_bWndLog = bWndLog;
if(m_bWndLog)
{
m_pWndLog = new detail::WndLog;
m_pWndLog->SetCaption(m_caption);
if(!m_pWndLog->Create())
{
m_bWndLog = false;
}
}
else
{
m_pWndLog->Close();
delete m_pWndLog;
m_pWndLog = NULL;
}
}
bFileLog = moxu::Config::GetIniInt(_T("..\\Logger.ini"), _T("Test"), _T("FileLog"), 0);
if(m_bFileLog != bFileLog)
{
m_bFileLog = bFileLog;
if(m_bFileLog)
{
m_pFileLog = new detail::FileLog;
m_pFileLog->SetCaption(m_caption);
if(!m_pFileLog->Create())
{
m_bFileLog = false;
}
}
else
{
m_pFileLog->Close();
delete m_pFileLog;
m_pFileLog = NULL;
}
}
if(m_bWndLog || m_bFileLog)
{
m_bInfo = moxu::Config::GetIniInt(_T("..\\Logger.ini"), _T("Test"), _T("Info"), 0);
m_bDebug = moxu::Config::GetIniInt(_T("..\\Logger.ini"), _T("Test"), _T("Debug"), 0);
m_bError = moxu::Config::GetIniInt(_T("..\\Logger.ini"), _T("Test"), _T("Error"), 0);
}
else
{
m_bInfo = false;
m_bDebug = false;
m_bError = false;
moxu::ScopedLock locker(m_cs);
m_strList.clear();
}
}
}//namespace moxu
/*
软件运行时,可修改配置文件,
#include "stdafx.h"
#include <Logger.h>
#include <conio.h>
using namespace moxu;
int main()
{
Logger logger;
logger.Create();
logger.SetCaption(_T("Test Log"));
int c = 1000;
while(c--)
{
logger.Error(_T("log %d"), c+1);
Sleep(500);
}
getch();
return 0;
}
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -