在软件开发过程中,日志系统是一个重要的组成部分。它可以帮助开发者追踪程序的运行状态,记录错误信息,以及进行性能分析等。本文将介绍如何设计和实现一个灵活的日志系统,包括日志级别的设置、日志颜色的调整以及如何获取程序的创建时间等。
日志条目可以包含多种类型的信息,如日期、数字和字符串等。首先,将介绍可以包含在每个日志条目中的信息类型。
总是希望知道是哪个函数调用了每个日志条目。为此,可以在WriteLogFile()函数中添加一个参数,并通过宏自动添加以下预处理器指令的第一个参数:__FUNCTION__
。
通常,希望日志条目包含一些一般信息,如当前日期和时间、应用程序启动的日期和时间(可选),以及应用程序创建的日期和时间(可选)。
并非每个应用程序都需要这个功能,但有些应用程序确实需要。如果应用程序有一个主事件循环,通常会从一些初始化开始,然后启动这个循环,直到应用程序被终止。可能想要计算这个循环发生了多少次。
以下函数可以用来设置文本和背景颜色。这个函数应该根据设置的标准被一个包装器调用,以便于在运行时查看日志。例如,区分信息日志条目和错误/警告,以及为不同类型的紧急情况设置不同的颜色。
inline void setcolor(int textcol, int backcol) {
if ((textcol % 16) == (backcol % 16)) textcol++;
textcol %= 16; backcol %= 16;
unsigned short wAttributes = ((unsigned)backcol << 4) | (unsigned)textcol;
HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hStdOut, wAttributes);
}
通过以下代码,定义了不同的日志级别,允许后续根据选定的“日志级别”显示日志条目。
typedef enum {
minimal = 1, // 必须显示的消息
normal = 2, // 通常会显示的消息
verbose = 3 // 不一定需要显示的消息
} LoggingLevel;
然后,可以使用宏来选择所需的日志级别作为WriteLogFile()的参数。
#define LOG_VERBOSE utils::LoggingLevel::verbose
#define LOG_NORMAL utils::LoggingLevel::normal
#define LOG_MINIMAL utils::LoggingLevel::minimal
将获取程序的创建日期,但首先,定义一个“友好”的格式来显示它:
#define FRIENDLY_DATEFORMAT L"%d-%m-%Y, %H:%M:%S"
这意味着:日-月-年 时:分:秒。例如:04-04-2019 10:00:00。使用以下代码获取程序的创建日期:
CTime GetFileDateTime(LPCWSTR FileName) {
FILETIME ftCreate, ftAccess, ftWrite;
HANDLE hFile;
CTime result = NULL;
CTime FileTime;
hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return result;
}
// 获取文件的时间。
if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite)) return result;
FileTime = ftWrite;
CloseHandle(hFile);
result = (CTime)FileTime;
return result;
}
// GetSelfDateTime- 返回运行程序的创建日期和时间
CTime GetSelfDateTime(void) {
WCHAR szExeFileName[MAX_PATH];
GetModuleFileName(NULL, szExeFileName, MAX_PATH);
return GetFileDateTime(szExeFileName);
}
可能还想要显示处理器类型,很可能是32位(x86)或64位(x64)。使用以下函数来实现:
bool Isx64OS() {
SYSTEM_INFO systemInfo;
GetNativeSystemInfo(&systemInfo);
return (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64);
}
现在是时候看看整个函数以及如何调用它了。使用WriteLogFile(),如下代码片段所示。注意:使用日志记录时,_LOG预处理器指令被设置,否则不会,这种代码的组织方式确保了当_LOG没有被打开时,不会包含所有日志消息在二进制可执行文件中,因为有时不希望这些消息被发布,而只是内部使用。
int myIntVar = 999;
wchar_t *myStringVar = L"Test";
#if _LOG
WriteLogFile(__FUNCTION__, LOG_COLOR_WHITE, LOG_VERBOSE,
L"myStringVar = %s myIntVar = %d", myStringVar, myIntVar);
#endif