有的时候在debug项目时候不能直观的使用调试来查询一些状态,而需要自己写一些辅助代码来检测程序的状态(如开发动态库或者COM组件给第三方程序调用无法使用调试器的环境下等)。
1) 以下是一个可以嵌入在代码中的辅助模块,基于标准C++11编写。
2)只有在Debug模式下才能使用,在非Release下改代码会被编译器过滤。(有些特殊情况需要在Release版本中需要编译可以使用宏开启)
3)使用了面向对象的单态模式(Singleton)来实现,并且使用了std::mutex实现了线程安全
4) 并未考虑高符合量的时候的输出,只适合调试轻量级的调试消息代码。
5)高负荷的情况,可以考虑使用队列缓存+线程异步写入,可能需要构建一个完整的log类。但log类可能会有项目依赖,本测试代码并不依赖具体项目可以嵌入到任何C++项目中来作为一种辅助工具使用
代码如下
UT_testlog.h
/*TestLog module header file
This module is designed to support to analyze the code and output the debug log info for the final ocx library.
*/
#ifndef UT_TESTLOG_H
#define UT_TESTLOG_H
#define TEST_LOG 0//The test flag to enabled the test function in Release version.
//define the macro which could be used by the other module of the projects.
#if ((defined(DEBUG) || (TEST_LOG)))
#define DebugCode( code_fragment ) { code_fragment }
#else
#define DebugCode( code_fragment )
#endif
#include <mutex>
#include <iostream>
#include <string>
class UT_TestLog
{
public:
static UT_TestLog* GetInstance();
static void Destory();
void printlogA(const char* str);
void printlogW(const wchar_t* str);
void printlogUTF8(const char* str);
void printlnlogA(const char* str);
void printlnlogW(const wchar_t* str);
void printlnlogUTF8(const char* str);
private:
//Save the stream to file.
void streamOut(const char* str);
void streamOutLn(const char* str);
void checkAppendStatus();
void clearTextContext();
UT_TestLog();
//Static variable.
static UT_TestLog* m_pInstance;
static std::mutex mut;
bool m_bIsAppend;
};
#endif
UT_testlog.cpp
/*TestLog module source file
This module is designed to support to analyze the code and output the debug log info for the final ocx library.
*/
//This module is validate only in Debug mode.
#include "ut_testlog.h"
#if ((defined(DEBUG) || (TEST_LOG)))
#include <fstream>
#include <sstream>
static const char logFileName[] = "test.log";
static const char appendTag[] = "[APPEND]";
UT_TestLog* UT_TestLog::m_pInstance = NULL;
std::mutex UT_TestLog::mut;
UT_TestLog::UT_TestLog() : m_bIsAppend(false)
{
}
UT_TestLog* UT_TestLog::GetInstance()
{
if(NULL == m_pInstance)
{
m_pInstance = new UT_TestLog();
m_pInstance->checkAppendStatus();
m_pInstance->clearTextContext();
}
return m_pInstance;
}
void UT_TestLog::Destory()
{
if(m_pInstance)
{
delete m_pInstance;
m_pInstance = NULL;
}
}
void UT_TestLog::printlogA(const char* str)
{
//Thread safe.
std::lock_guard<std::mutex> guard(mut);
streamOut(str);
}
void UT_TestLog::printlnlogA(const char* str)
{
//Thread safe.
std::lock_guard<std::mutex> guard(mut);
streamOutLn(str);
}
void UT_TestLog::printlogW(const wchar_t* wstr)
{
//Thread safe.
std::lock_guard<std::mutex> guard(mut);
size_t nlength = wcslen(wstr);
char *cstr = new char[nlength];
size_t converted = 0;
wcstombs_s(&converted, cstr, nlength, wstr, _TRUNCATE);
streamOut(cstr);
delete[] cstr;
}
void UT_TestLog::printlnlogW(const wchar_t* wstr)
{
//Thread safe.
std::lock_guard<std::mutex> guard(mut);
size_t nlength = wcslen(wstr);
char *cstr = new char[nlength];
size_t converted = 0;
wcstombs_s(&converted, cstr, nlength, wstr, _TRUNCATE);
streamOutLn(cstr);
delete[] cstr;
}
//Todo: This function is copied from the printlogA, we need to handle the conversation from UTF8 to ANSI string.
void UT_TestLog::printlogUTF8(const char* str)
{
//Thread safe.
std::lock_guard<std::mutex> guard(mut);
//We need to do an conversation from UTF8 to ANSI
streamOut(str);
}
void UT_TestLog::printlnlogUTF8(const char* str)
{
//Thread safe.
std::lock_guard<std::mutex> guard(mut);
//We need to do an conversation from UTF8 to ANSI
streamOutLn(str);
}
//Private member function.
void UT_TestLog::streamOut(const char* str)
{
std::ofstream out;
out.open(logFileName, std::ios::app);
out << str;
}
void UT_TestLog::streamOutLn(const char* str)
{
std::ofstream out;
out.open(logFileName, std::ios::app);
out << str << std::endl;
}
void UT_TestLog::checkAppendStatus()
{
std::ifstream in;
char buffer[256];
in.open(logFileName, std::ios::in | std::ios::binary);
if (!in.is_open())
{
std::cout << "Error opening file";
return;
}
if (!in.eof())
in.getline(buffer, 100);
if (strcmp(buffer, appendTag) == 0)
m_bIsAppend = true;
else
m_bIsAppend = false;
}
void UT_TestLog::clearTextContext()
{
if (m_bIsAppend) //Append Mode we don't need to clear the string.
return;
std::ofstream out;
out.open(logFileName, std::ios::out | std::ios::binary | std::ios::trunc);
out << ""; //Init the test log with null string.
}
#endif
使用方法
在程序初始化的时候(例如main函数 创建一次实例)
在程序退出的时候 (销毁对象)
以后在任意地方可以调用