很长一段时间后,我又开始做一些 C++ 开发。现在我正在为我的伐木课而苦苦挣扎。它已经工作得很好,但我想介绍一些日志级别。老实说,我不太确定如何以正确的方式继续。
我的记录器使用五个简单的宏:
#define PLUGINLOG_INIT(path, fileName) logInstance.initialise(path, fileName);
#define LOG_ERROR (logInstance << logInstance.prefix(error))
#define LOG_WARN (logInstance << logInstance.prefix(warn))
#define LOG_INFO (logInstance << logInstance.prefix(info))
#define LOG_DEBUG (logInstance << logInstance.prefix(debug))
第一个打开文件流,其他四个将日志条目写入文件。这是一个相当简单的方法。前缀方法将日期时间戳和日志级别写入文本:
<块引用>2021-05.26 12:07:23 WARN 文件未找到!
对于日志级别,我创建了一个 enum
并将当前日志级别存储在我的类中。但是,我的问题是,如果日志级别设置得较低,我如何避免日志记录?
示例: 类中的 LogLevel = 警告
当我记录信息条目时,我会将以下行放入我的源代码中:
LOG_INFO << "My info log entry" << std::endl;
由于 LogLevel
设置为警告,因此不应记录此信息条目。我可以尝试将 if 语句放入 LOG_INFO
宏中,但我宁愿避免使用复杂的宏。有没有更好的方法来实现我的需求?
非常感谢, 马可
我的记录器的完整头文件:
#ifndef PLUGINLOGGER_H_
#define PLUGINLOGGER_H_
// Standard
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>
// Forward declarations
class PluginLogger;
extern PluginLogger logInstance;
// Enumerations
enum LogLevel {
error = 0,
warn = 1,
info = 2,
debug = 3
};
// Macros
#define PLUGINLOG_INIT(path, fileName) logInstance.initialise(path, fileName);
#define LOG_ERROR (logInstance << logInstance.prefix(error))
#define LOG_WARN (logInstance << logInstance.prefix(warn))
#define LOG_INFO (logInstance << logInstance.prefix(info))
#define LOG_DEBUG (logInstance << logInstance.prefix(debug))
class PluginLogger {
public:
PluginLogger();
void initialise(std::string_view path, std::string_view fileName);
void close();
template<typename T> PluginLogger& operator<<(T t);
// to enable std::endl
PluginLogger& operator<<(std::ostream& (*fun) (std::ostream&));
std::string prefix(const LogLevel logLevel);
private:
std::string m_fileName;
std::ofstream m_stream;
LogLevel m_logLevel;
};
template<typename T> inline PluginLogger& PluginLogger::operator<<(T t) {
if (m_stream.is_open())
m_stream << t;
return* this;
}
inline PluginLogger& PluginLogger::operator<<(std::ostream& (*fun)( std::ostream&)) {
if (m_stream.is_open())
m_stream << std::endl;
return* this;
}
#endif // PLUGINLOGGER_H_
我的记录器的完整源文件:
#include <chrono>
#include "PluginLogger.h"
PluginLogger logInstance;
PluginLogger::PluginLogger() {
m_fileName = "";
m_logLevel = error;
}
void PluginLogger::initialise(std::string_view path, std::string_view fileName) {
if (!path.empty() && !fileName.empty()) {
m_fileName = std::string(path) + std::string(fileName) + "_log.txt";
m_stream.open(m_fileName);
unsigned char bom[] = { 0xEF,0xBB,0xBF };
m_stream.write((char*)bom, sizeof(bom));
}
}
void PluginLogger::close() {
if (m_stream.is_open())
m_stream.close();
}
std::string PluginLogger::prefix(const LogLevel logLevel) {
// add a date time string
std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::string dateTimeStr(25, '\0');
std::strftime(&dateTimeStr[0], dateTimeStr.size(), "%Y-%m-%d %H:%M:%S", std::localtime(&now));
// add log level
std::string logLevelText;
switch (logLevel) {
case error:
logLevelText = " ERROR ";
break;
case warn:
logLevelText = " WARN ";
break;
case info:
logLevelText = " INFO ";
break;
case debug:
logLevelText = " DEBUG ";
break;
}
return dateTimeStr + logLevelText;
}