log.h

#pragma once

#include <cstdarg>
#include <string_view>

#include "noncopyable.h"
#include "log4cplus/consoleappender.h"
#include "log4cplus/fileappender.h"
#include "log4cplus/initializer.h"
#include "log4cplus/logger.h"
#include "log4cplus/ndc.h"
#include "singleton.h"

namespace Core {
    class Log : public Core::noncopyable {
    public:
        Log() = default;

        ~Log() {
            log4cplus::Logger::shutdown();
        };

        static void Load(std::string_view prefix, std::string_view script_name, std::string_view file_pattern,
                         short int file_log_level,
                         short int console_log_level,
                         std::string_view pattern = "%D{%Y-%m-%d %H:%M:%S} [%x:%p] %m%n");

        static void Write(log4cplus::LogLevel log_Level, const char *format, ...);

        static void LuaInfo(const char *msg) {
            log4cplus::NDCContextCreator tmp_ndc(m_script_name.data());
            m_logger.forcedLog(log4cplus::INFO_LOG_LEVEL, msg);
        }

        static void LuaError(const char *msg) {
            log4cplus::NDCContextCreator tmp_ndc(m_script_name.data());
            m_logger.forcedLog(log4cplus::ERROR_LOG_LEVEL, msg);
        }

    private:
        static void AddDailyMode(std::string_view file_pattern, std::string_view pattern,
                                 short int level);

        static void AddConsoleMode(std::string_view pattern, short int level);

    private:
        static std::string_view m_prefix;
        static std::string_view m_script_name;
        static log4cplus::Logger m_logger;
    };

#define LOGGER Core::Singleton<Core::Log>::Instance()
#define LOG_DEBUG(...) LOGGER.Write(log4cplus::DEBUG_LOG_LEVEL, __VA_ARGS__)
#define LOG_INFO(...) LOGGER.Write(log4cplus::INFO_LOG_LEVEL, __VA_ARGS__)
#define LOG_WARN(...) LOGGER.Write(log4cplus::WARN_LOG_LEVEL, __VA_ARGS__)
#define LOG_ERROR(...) LOGGER.Write(log4cplus::ERROR_LOG_LEVEL, __VA_ARGS__)
#define LOG_FATAL(...) LOGGER.Write(log4cplus::FATAL_LOG_LEVEL, __VA_ARGS__)
}  // namespace Core

log.cpp

#include "log.h"
#include "utils.h"

namespace Core {

    log4cplus::Logger Core::Log::m_logger;
    std::string_view Core::Log::m_script_name;
    std::string_view Core::Log::m_prefix;

    void Log::Load(std::string_view prefix, std::string_view script_name, std::string_view file_pattern,
                   short int file_log_level,
                   short int console_log_level, std::string_view pattern) {
        log4cplus::initialize();
        m_logger = log4cplus::Logger::getInstance(prefix.data());
        m_prefix = prefix;
        m_script_name = script_name;

        if (!file_pattern.empty())
            AddDailyMode(file_pattern, pattern, file_log_level);
        AddConsoleMode(pattern, console_log_level);
    }

    void Log::Write(log4cplus::LogLevel log_Level, const char *format, ...) {
        if (m_logger.isEnabledFor(log_Level)) {
            va_list ap;
            va_start(ap, format);
            std::string log = StringUtil::Formatv(format, ap);
            va_end(ap);
            log4cplus::NDCContextCreator tmp_ndc(m_prefix.data());
            m_logger.forcedLog(log_Level, log);
        }
    }

    void Log::AddDailyMode(std::string_view file_pattern, std::string_view pattern, short level) {
        log4cplus::SharedAppenderPtr time(new log4cplus::TimeBasedRollingFileAppender(
                "", file_pattern.data(), 999, false, true, true, false));
        time->setLayout(std::make_unique<log4cplus::PatternLayout>(pattern.data()));
        time->setName(LOG4CPLUS_TEXT("TimeFile"));
        time->setThreshold(level * 10000);
        m_logger.addAppender(time);
    }

    void Log::AddConsoleMode(std::string_view pattern, short level) {
        log4cplus::SharedAppenderPtr console(new log4cplus::ConsoleAppender());
        console->setLayout(std::make_unique<log4cplus::PatternLayout>(pattern.data()));
        console->setName(LOG4CPLUS_TEXT("Console"));
        console->setThreshold(level * 10000);
        m_logger.addAppender(console);
    }

}  // namespace Core