C++で簡単なロガーを考えてみた

コードを見ればわかるはず

#include <stdarg.h>
#include <string>
#include <sstream>
#include <fstream>

class LogLevel
{
public:
    enum type
    {
        Info= 1,
        Debug,
        Warn,
        Error,
    };

    static std::string ToString(LogLevel::type logLevel)
    {
        switch (logLevel)
        {
        case LogLevel::Info:  return "INFO ";
        case LogLevel::Debug: return "DEBUG";
        case LogLevel::Warn:  return "WARN ";
        case LogLevel::Error: return "ERROR";
        default:              return "UNKNOWN";
        }
    }
};


class Logger
{
private:
    LogLevel::type  m_tatgetLogLevel;
    std::string     m_logFilePath;

public:

    static Logger* GetInstance()
    {
        static Logger instance;
        return &instance;
    }

    // 出力したいログレベルを設定します
    void SetLogLevel(const LogLevel::type& logLevel)
    {
        this->m_tatgetLogLevel = logLevel;
    }

    // 出力したいログファイルを設定します
    void SetLogFilePath(const char* logFilePath)
    {
        this->m_logFilePath = logFilePath;
    }

    void Write(const LogLevel::type& logLevel, const char* fileName, const char* funcName, const int lineNum, const char* format, ...)
    {
        char message[512] = { 0 };
        va_list args;

        va_start(args, format);
#ifdef _WIN32
        vsprintf_s(message, format, args);
#else
        vsprintf(message, format, args);
#endif
        this->write(logLevel, fileName, funcName, lineNum, message);
        va_end(args);
    }

    void Info(const char* const fileName, const char* const funcName, const int lineNum, const char* message) const
    {
        this->write(LogLevel::Info, fileName, funcName, lineNum, message);
    }

    void Debug(const char* const fileName, const char* const funcName, const int lineNum, const char* message) const
    {
        this->write(LogLevel::Debug, fileName, funcName, lineNum, message);
    }

    void Warn(const char* const fileName, const char* const funcName, const int lineNum, const char* message) const
    {
        this->write(LogLevel::Warn, fileName, funcName, lineNum, message);
    }

    void Error(const char* const fileName, const char* const funcName, const int lineNum, const char* message) const
    {
        this->write(LogLevel::Error, fileName, funcName, lineNum, message);
    }

private:

    // 
    Logger() : m_tatgetLogLevel(LogLevel::Info)
    {
        // ログファイル名を決めましょう
        this->m_logFilePath = "C:\\testlog.log";
    }

    void write(const LogLevel::type& logLevel, const char* fileName, const char* funcName, const int lineNum, const char* message) const
    {
        if (!this->isEnabled(logLevel))
            return;

        // ログを出力する処理
        std::ofstream ofs;
        ofs.open(this->m_logFilePath, std::ios::app);

        ofs << this->getDateTimeNow() << " "
            << "[" << LogLevel::ToString(logLevel) << "]"
            << "[" << fileName << "]"
            << "[" << funcName << "]"
            << "[" << lineNum << "]"
            << message
            << std::endl;

        ofs.close();
    }

    bool isEnabled(const LogLevel::type& logLevel) const
    {
        return this->m_tatgetLogLevel <= logLevel;
    }

    std::string getDateTimeNow() const
    {
        std::ostringstream oss;

        // 時刻を整形する処理

        return oss.str();
    }
};


#define LOG_LEVEL_SET(x)        Logger::GetInstance()->SetLogLevel(x);
#define LOG_FILE_PATH_SET(x)    Logger::GetInstance()->SetLogFilePath(x);

#ifdef _WIN32
#define LOG_INFO(format, ...)   Logger::GetInstance()->Write(LogLevel::Info,  __FILE__, __FUNCTION__, __LINE__, format, __VA_ARGS__);
#define LOG_DEBUG(format, ...)  Logger::GetInstance()->Write(LogLevel::Debug, __FILE__, __FUNCTION__, __LINE__, format, __VA_ARGS__);
#define LOG_WARN(format, ...)   Logger::GetInstance()->Write(LogLevel::Warn,  __FILE__, __FUNCTION__, __LINE__, format, __VA_ARGS__);
#define LOG_ERROR(format, ...)  Logger::GetInstance()->Write(LogLevel::Error, __FILE__, __FUNCTION__, __LINE__, format, __VA_ARGS__);
#else
#define LOG_INFO(format, ...)   Logger::GetInstance()->Write(LogLevel::Info,  __FILE__, __func__, __LINE__, format, __VA_ARGS__);
#define LOG_DEBUG(format, ...)  Logger::GetInstance()->Write(LogLevel::Debug, __FILE__, __func__, __LINE__, format, __VA_ARGS__);
#define LOG_WARN(format, ...)   Logger::GetInstance()->Write(LogLevel::Warn,  __FILE__, __func__, __LINE__, format, __VA_ARGS__);
#define LOG_ERROR(format, ...)  Logger::GetInstance()->Write(LogLevel::Error, __FILE__, __func__, __LINE__, format, __VA_ARGS__);
#endif

int main(int argc, char* argv[])
{
    LOG_INFO("info %d, %d--", 1, 2);
    LOG_DEBUG("debug--");
    LOG_WARN("warn %s--", "あいうえお");
    LOG_ERROR("error %s %d--", "abcde", 1000);

    // yyyy/mm/dd hh:mm:ss.000 [INFO ][XXXX\cpploggersample.cpp][main][157]info 1, 2--
    // yyyy/mm/dd hh:mm:ss.000 [DEBUG][XXXX\cpploggersample.cpp][main][158]debug--
    // yyyy/mm/dd hh:mm:ss.000 [WARN ][XXXX\cpploggersample.cpp][main][159]warn あいうえお--
    // yyyy/mm/dd hh:mm:ss.000 [ERROR][XXXX\cpploggersample.cpp][main][160]error abcde 1000--

    return 0;
}