具有日志级别的 C++ 中的简单记录器

时间:2021-05-26 14:14:33

标签: c++ logging

很长一段时间后,我又开始做一些 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;
}

0 个答案:

没有答案
相关问题