您的位置:首页 > 编程语言 > C语言/C++

C++打印日志功能设计

2016-04-14 19:20 357 查看
我之前用Qt框架下,设计了一个“打印日志”的功能(点击打开链接),利用了Qt框架的一些机制,并调用了一些的Qt框架函数。现在,我需要编写一个纯C++的“日志打印”功能。(事实上,还是调用了一些windows系统函数)

一、日志打印函数

我设计的是一个全局函数,而不是一个全局变量来实现log文件管理和输出。全局变量会导致“不可重入”,在多线程环境下,会概率性打印出错。

void CCommon::PrintLog(string str)
{
SYSTEMTIME sys;
::GetLocalTime(&sys);

std::ofstream ofs;
ofs.open("driver.log", std::ios_base::in | std::ios_base::app);
ofs << "[" << sys.wHour << ":" << sys.wMinute << ":" << sys.wSecond << "." << sys.wMilliseconds << "]\t" << str << std::endl;
ofs.close();
}


1, 事实上,我用的是类的static函数,增加了封装性,防止名称冲突。也可以用namespace来封装。

2,如果在多线程下,还可以在该函数中加“互斥锁”。

二、日志打印宏

在之前的Qt实现中,log文件不但包含时间,也包含文件名和行号。其实在纯C++中,也可实现该功能。具体来说,就是利用C++的编译宏“__FUNCTION__”、“__LINE__”、“__FILE__”和“__TIME__”(它显示的是编译时时间)等。如果要打印这些信息,它们就不能放到“PrintLog”这个全局函数中,而是要放到调用的地方,那么,解决的办法就是用“宏”。

#define PRINT_LOG(ss) \
do { \
std::ostringstream oss; \
oss << "Function: " << __FUNCTION__ << "\t\tMsg: " << ss; \
CCommon::PrintLog(oss.str()); \
} while(0);


1,对于分行的宏,最好用do-while包裹,比如调用的地方用的for循环,而没有加花括符。

2,在此选用的是C++的“字符流”,它能够识别字符串和其他类型变量,扩展性很好。

三、应用举例

double db = 5;
std::ostringstream oss;
oss << "Function: " << __FUNCTION__ << "\t\tMsg: " << db;
CCommon::PrintLog(oss.str());
for (int i = 0; i < 20; ++i)
PRINT_LOG("test" << 10);
打印宏的括号内支持表达式,使用方法与C++标准流相同。

打印结果如下:



四、文件管理

对于日志文件,一般有两种处理方式,一种就是每次启动软件,清空之前的文件;另一种就是累增。前一种的缺点是,长跑测试中,软件崩溃,后来者不小心重启了软件,导致历史日志丢失;后一种的缺陷是,长跑测试,日志文件累增过大,导致磁盘空间不足。

针对上面两种情况的优缺点,我设计了一种循环记录的方法,类似“行车记录仪”。

long fileSize = 0;
HANDLE handle = CreateFile(L"driver.log", FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (handle != INVALID_HANDLE_VALUE)
{
fileSize = GetFileSize(handle, NULL);
cout << fileSize << endl;
CloseHandle(handle);
}
if (fileSize < 200 * 1024 * 1024)    // filesize的单位是byte,设定门限是200M
{
PRINT_LOG("\n\n------------------------------reboot----------------------------------");
}
else
DeleteFile(L"driver.log");


将该段代码加载程序启动的位置即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: