[C++/單例模式] QT-Logger的分級管理機制

有沒有羨慕過python自帶的logging的易用性?這裏簡單地完成了一個較爲高效的模板化分級logger.
先理一下思路:
1.希望有一個根據字符串索引的單例集合
2.希望有一個可以分級的日誌管理
3.不要寫得太長

先來設計一下分級管理的標籤

/* Logger級別 */
namespace LoggerFlag {
    struct logger_flag                                       {};
    struct critical_logger_flag : public logger_flag         {};
    struct error_logger_flag    : public critical_logger_flag{};
    struct debug_logger_flag    : public error_logger_flag   {};
    struct warning_logger_flag  : public debug_logger_flag   {};
    struct info_logger_flag     : public warning_logger_flag {};
}

這個分級機制允許分級匹配,不過我們可以用type_traits,這樣效率更高。

namespace LoggerFlag {
    template<typename m_flag> struct type_traitor;
    template<typename m_flag>
    struct type_traitor {
        typedef std::true_type enable_info;
        typedef std::true_type enable_warning;
        typedef std::true_type enable_debug;
        typedef std::true_type enable_error;
        typedef std::true_type enable_critical;
    };

    template<>
    struct type_traitor<critical_logger_flag> {
        typedef logger_flag _ww;
        typedef std::false_type enable_info;
        typedef std::false_type enable_warning;
        typedef std::false_type enable_debug;
        typedef std::false_type enable_error;
        typedef std::true_type enable_critical;
    };

	...
}

接下來是Logger的單例

/* Logger單例 */
class Logger
{
    static Logger m_logger_instance;
protected:
    typedef QDebug OutStream;
public:

    static Logger *get_logger(const std::string &logger_name);

    static OutStream criticals();
    static OutStream errors();
    static OutStream debugs();
    static OutStream warnings();
    static OutStream infos();

    OutStream critical();
    OutStream error();
    OutStream debug();
    OutStream warning();
    OutStream info();

public:
protected:
    Logger();
    virtual ~Logger();
private:
    template<typename out_flag=LoggerFlag::logger_flag>
    Logger(out_flag);
};

如果我們直接在如critical()裏返回一個qDebug,或者qNoDebug,用m_logger_instance作爲單例載體,那麼單例模式算是設計完了。
但是如何去設計static Logger *get_logger(const std::string &logger_name);呢?
結合我們之前的分級方法,我們可能要先設計一個真正工作的Logger指針。

/* Logger指針 */
template <typename output_flag>
class LoggerHelper: public LoggerManagable
{
protected:
    typedef QDebug OutStream;
public:
    LoggerHelper();
    ~LoggerHelper();

    OutStream _critical();
    OutStream _error();
    OutStream _debug();
    OutStream _warning();
    OutStream _info();
};

然後拿map<>(或unordered_map)保存每一個std::string對應的單例。
但是這裏LoggerHandler並不能寫在map<>的聲明上,所以我們還要加一個非泛型的基類。

/* Logger指針 */
class LoggerManagable
{
protected:
    typedef QDebug OutStream; // <-把OutStream提升到這裏
public:
    LoggerManagable();
    virtual ~LoggerManagable() = 0;

    virtual OutStream _critical() = 0;
    virtual OutStream _error() = 0;
    virtual OutStream _debug() = 0;
    virtual OutStream _warning() = 0;
    virtual OutStream _info() = 0;
};

然後用一個內存管理器的單例做一個tricky的編程

/* Logger單例管理器 */
class LoggerManager{
    friend class Logger;
    static std::map<std::string, Logger*> m_logger_instances;
    static LoggerManager logger_destructor;
public:
    LoggerManager();
    ~LoggerManager();
};

爲什麼上面是Logger*?,我在Logger裏保存了LoggerManagable的指針,這樣也是合情合理的。Logger裏新添加的內容在下面:

/* Logger單例 */
class Logger
{
    friend class LoggerManager;
private:
    LoggerManagable *handler;
};

來看一下第一組實例代碼,單例的內存管理器是怎麼實現的?回顧以前的某一個blog,我們用那個思想做了一個威力加強版。

LoggerManager::LoggerManager()
{
    m_logger_instances.clear();
}

LoggerManager::~LoggerManager()
{
    for (auto &logger_instance: m_logger_instances) {
        if (logger_instance.second != nullptr) {
#ifdef DEBUG
            qDebug() << "logger" << QString::fromStdString(logger_instance.first) << "is destructed";
#endif
            delete logger_instance.second;
            logger_instance.second = nullptr;
        }
    }
}

用戶是沒有權限delete單例的,因此這裏map中的每一個指針都對應一個單例,放心釋放吧。

接下來是設計真正的handler.以critical爲例:

/* 申請假的stream(Not True Type) */
template<typename request_bool_type>
inline LoggerManagable::OutStream LoggerManagable::request_stream() {
    static QString idle_buffer;
    static QDebug idle_dbg(&idle_buffer);
    idle_buffer.clear();
    return idle_dbg;
}

/* 申請真的stream(偏特化True Type) */
template<>
inline LoggerManagable::OutStream LoggerManagable::request_stream<std::true_type>() {
    return qDebug();
}

/* 根據type_traits裏記錄的值選擇對應的stream */
template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_critical()
{
    return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_critical::type>();
}
Logger::OutStream Logger::criticals()
{
    return Logger::m_logger_instance.handler->_critical();
}

Logger::OutStream Logger::critical()
{
    return this->handler->_critical();
}

這裏criticals是單例的靜態方法。
其他的複製粘貼替換即可。

我們還差什麼?
好像還差分級。
一開始我的設計是這樣的。

/* Logger單例 */
class Logger
{
public:
	template<typename out_flag>
    bool set_mode();
	template<typename out_flag>
    static bool set_modes();

};

但是頭文件和實現的cpp文件分離了,會報未實例化偏函數的warning,忍不了。乾脆還是迴歸平常吧。
好在這裏 logger_flag都是一字節的,也沒有哪個程序會瘋狂更改mode,好像也不會浪費到哪裏去。
修改一下

/* Logger單例 */
class Logger
{
public:

    bool set_mode(LoggerFlag::logger_flag);
    bool set_mode(LoggerFlag::critical_logger_flag);
    bool set_mode(LoggerFlag::error_logger_flag);
    bool set_mode(LoggerFlag::debug_logger_flag);
    bool set_mode(LoggerFlag::warning_logger_flag);
    bool set_mode(LoggerFlag::info_logger_flag);

    static bool set_modes(LoggerFlag::logger_flag);
    static bool set_modes(LoggerFlag::critical_logger_flag);
    static bool set_modes(LoggerFlag::error_logger_flag);
    static bool set_modes(LoggerFlag::debug_logger_flag);
    static bool set_modes(LoggerFlag::warning_logger_flag);
    static bool set_modes(LoggerFlag::info_logger_flag);

};

下面是實現:

bool Logger::set_mode(LoggerFlag::logger_flag)
{
    if (this->handler != nullptr) {
        delete this->handler;
        this->handler = nullptr;
    }
    this->handler = new LoggerHelper<LoggerFlag::logger_flag>;
    return this->handler != nullptr;
}
bool Logger::set_modes(LoggerFlag::logger_flag)
{
    if (m_logger_instance.handler != nullptr) {
        delete m_logger_instance.handler;
        m_logger_instance.handler = nullptr;
    }
    m_logger_instance.handler = new LoggerHelper<LoggerFlag::logger_flag>;
    return m_logger_instance.handler != nullptr;
}

當然最重要的函數之一get_logger也有一些需要注意的地方,上代碼:

Logger *Logger::get_logger(const std::string &logger_name)
{
    static std::mutex alloc_mutex;
    if (!LoggerManager::m_logger_instances.count(logger_name)) {
        alloc_mutex.lock();
        if (!LoggerManager::m_logger_instances.count(logger_name)) {
            LoggerManager::m_logger_instances[logger_name] = new Logger();
        }
        alloc_mutex.unlock();
    }
    return LoggerManager::m_logger_instances[logger_name];
}

這樣一個簡單的logger就完成了,雖然比較簡短,一些坑還是需要仔細琢磨才能做出來的…熟能生巧吧。

效果

    qDebug() << Logger::set_modes(LoggerFlag::debug_logger_flag());
    Logger::infos() << "w";
    Logger::warnings() << "ww";
    Logger::debugs() << "www";
    Logger::errors() << "wwww";
    Logger::criticals() << "wwwww";


    qDebug() << Logger::set_modes(LoggerFlag::logger_flag());
    Logger::infos() << "w";
    Logger::warnings() << "ww";
    Logger::debugs() << "www";
    Logger::errors() << "wwww";
    Logger::criticals() << "wwwww";
    this->init_client();

    auto dex = Logger::get_logger("main");
    dex->info() << "...";
    dex->warning() << "...";
    dex->debug() << "...";
    dex->error() << "...";
    dex->critical() << "...";

    dex->set_mode(LoggerFlag::debug_logger_flag());
    qDebug() << "------------";
    dex->info() << "...";
    dex->warning() << "...";
    dex->debug() << "...";
    dex->error() << "...";
    dex->critical() << "...";


    auto dey = Logger::get_logger("main");
    qDebug() << "------------";
    dey->info() << "...";
    dey->warning() << "...";
    dey->debug() << "...";
    dey->error() << "...";
    dey->critical() << "...";

    Logger::get_logger("a")->info() << "ww";
    Logger::get_logger("b")->info() << "ww";
    Logger::get_logger("c")->info() << "ww";
true
www
wwww
wwwww
true
w
ww
www
wwww
wwwww
...
...
...
...
...
------------
...
...
...
------------
...
...
...
ww
ww
ww
logger "a" is destructed
logger "b" is destructed
logger "c" is destructed
logger "main" is destructed

貼一下完整代碼

#ifndef LOGGGGER_H
#define LOGGGGER_H


#include <QString>
#include <iostream>
#include <string>
#include <map>
#include <mutex>
#include <type_traits>
#include <QDebug>


/* Logger級別 */
namespace LoggerFlag {
    struct logger_flag                                       {};
    struct critical_logger_flag : public logger_flag         {};
    struct error_logger_flag    : public critical_logger_flag{};
    struct debug_logger_flag    : public error_logger_flag   {};
    struct warning_logger_flag  : public debug_logger_flag   {};
    struct info_logger_flag     : public warning_logger_flag {};

    template<typename m_flag> struct type_traitor;
}

/* Logger指針 */
class LoggerManagable
{
protected:
    typedef QDebug OutStream;
public:
    LoggerManagable();
    virtual ~LoggerManagable() = 0;

    virtual OutStream _critical() = 0;
    virtual OutStream _error() = 0;
    virtual OutStream _debug() = 0;
    virtual OutStream _warning() = 0;
    virtual OutStream _info() = 0;
    template<typename request_bool_type>
    inline LoggerManagable::OutStream request_stream();
};

/* Logger單例 */
class Logger
{
    static Logger m_logger_instance;
    friend class LoggerManager;
protected:
    typedef QDebug OutStream;
public:

    static Logger *get_logger(const std::string &logger_name);

    static OutStream criticals();
    static OutStream errors();
    static OutStream debugs();
    static OutStream warnings();
    static void infos(const char *msg, ...);
    static OutStream infos();

    bool set_mode(LoggerFlag::logger_flag);
    bool set_mode(LoggerFlag::critical_logger_flag);
    bool set_mode(LoggerFlag::error_logger_flag);
    bool set_mode(LoggerFlag::debug_logger_flag);
    bool set_mode(LoggerFlag::warning_logger_flag);
    bool set_mode(LoggerFlag::info_logger_flag);

    static bool set_modes(LoggerFlag::logger_flag);
    static bool set_modes(LoggerFlag::critical_logger_flag);
    static bool set_modes(LoggerFlag::error_logger_flag);
    static bool set_modes(LoggerFlag::debug_logger_flag);
    static bool set_modes(LoggerFlag::warning_logger_flag);
    static bool set_modes(LoggerFlag::info_logger_flag);

    OutStream critical();
    OutStream error();
    OutStream debug();
    OutStream warning();
    OutStream info();

public:
protected:
    Logger();
    virtual ~Logger();
private:
    template<typename out_flag=LoggerFlag::logger_flag>
    Logger(out_flag);
    LoggerManagable *handler;
};

/* Logger單例管理器 */
class LoggerManager{
    friend class Logger;
    static std::map<std::string, Logger*> m_logger_instances;
    static LoggerManager logger_destructor;
public:
    LoggerManager();
    ~LoggerManager();
};


/* Logger指針 */
template <typename output_flag>
class LoggerHelper: public LoggerManagable
{
public:
    LoggerHelper();
    ~LoggerHelper();

    OutStream _critical();
    OutStream _error();
    OutStream _debug();
    OutStream _warning();
    OutStream _info();
};


#endif // LOGGGGER_H
#include "Logger.h"
#include <QDebug>
#include <QMessageLogger>

/*********************************** Singletons ***********************************/

LoggerManager LoggerManager::logger_destructor;
Logger Logger::m_logger_instance;
std::map<std::string, Logger*> LoggerManager::m_logger_instances;


/*********************************** LoggerFlag ***********************************/

namespace LoggerFlag {

    template<typename m_flag>
    struct type_traitor {
        typedef std::true_type enable_info;
        typedef std::true_type enable_warning;
        typedef std::true_type enable_debug;
        typedef std::true_type enable_error;
        typedef std::true_type enable_critical;
    };

    template<>
    struct type_traitor<critical_logger_flag> {
        typedef logger_flag _ww;
        typedef std::false_type enable_info;
        typedef std::false_type enable_warning;
        typedef std::false_type enable_debug;
        typedef std::false_type enable_error;
        typedef std::true_type enable_critical;
    };

    template<>
    struct type_traitor<error_logger_flag> {
        typedef logger_flag _ww;
        typedef std::false_type enable_info;
        typedef std::false_type enable_warning;
        typedef std::false_type enable_debug;
        typedef std::true_type enable_error;
        typedef std::true_type enable_critical;
    };

    template<>
    struct type_traitor<debug_logger_flag> {
        typedef logger_flag _ww;
        typedef std::false_type enable_info;
        typedef std::false_type enable_warning;
        typedef std::true_type enable_debug;
        typedef std::true_type enable_error;
        typedef std::true_type enable_critical;
    };

    template<>
    struct type_traitor<warning_logger_flag> {
        typedef logger_flag _ww;
        typedef std::false_type enable_info;
        typedef std::true_type enable_warning;
        typedef std::true_type enable_debug;
        typedef std::true_type enable_error;
        typedef std::true_type enable_critical;
    };

    template<>
    struct type_traitor<info_logger_flag> {
        typedef logger_flag _ww;
        typedef std::false_type enable_info;
        typedef std::true_type enable_warning;
        typedef std::true_type enable_debug;
        typedef std::true_type enable_error;
        typedef std::true_type enable_critical;
    };
}


/************************************* Logger *************************************/

Logger::Logger()
{
    this->handler = new LoggerHelper<LoggerFlag::logger_flag>;
}

Logger::~Logger()
{
    if (handler != nullptr) {
        delete handler;
    }
}

Logger *Logger::get_logger(const std::string &logger_name)
{
    static std::mutex alloc_mutex;
    if (!LoggerManager::m_logger_instances.count(logger_name)) {
        alloc_mutex.lock();
        if (!LoggerManager::m_logger_instances.count(logger_name)) {
            LoggerManager::m_logger_instances[logger_name] = new Logger();
        }
        alloc_mutex.unlock();
    }
    return LoggerManager::m_logger_instances[logger_name];
}


/********************************* static methods *********************************/

Logger::OutStream Logger::criticals()
{
    return Logger::m_logger_instance.handler->_critical();
}

Logger::OutStream Logger::errors()
{
    return Logger::m_logger_instance.handler->_error();
}

Logger::OutStream Logger::debugs()
{
    return Logger::m_logger_instance.handler->_debug();
}

Logger::OutStream Logger::warnings()
{
    return Logger::m_logger_instance.handler->_warning();
}

Logger::OutStream Logger::infos()
{
    return Logger::m_logger_instance.handler->_info();
}


/******************************** instance methods ********************************/
Logger::OutStream Logger::critical()
{
    return this->handler->_critical();
}

Logger::OutStream Logger::error()
{
    return this->handler->_error();
}

Logger::OutStream Logger::debug()
{
    return this->handler->_debug();
}

Logger::OutStream Logger::warning()
{
    return this->handler->_warning();
}

Logger::OutStream Logger::info()
{
    return this->handler->_info();
}


/******************************** aborted methods ********************************/

//template<typename out_flag>
//bool Logger::set_mode()
//{
//    if (this->handler != nullptr) {
//        delete this->handler;
//        this->handler = nullptr;
//    }
//    this->handler = new LoggerHelper<out_flag>;
//    return this->handler != nullptr;
//}

//template<>
//bool Logger::set_mode<LoggerFlag::critical_logger_flag>()
//{
//    if (this->handler != nullptr) {
//        delete this->handler;
//        this->handler = nullptr;
//    }
//    this->handler = new LoggerHelper<LoggerFlag::critical_logger_flag>;
//    return this->handler != nullptr;
//}

//template<>
//bool Logger::set_mode<LoggerFlag::error_logger_flag>()
//{
//    if (this->handler != nullptr) {
//        delete this->handler;
//        this->handler = nullptr;
//    }
//    this->handler = new LoggerHelper<LoggerFlag::error_logger_flag>;
//    return this->handler != nullptr;
//}

//template<>
//bool Logger::set_mode<LoggerFlag::debug_logger_flag>()
//{
//    if (this->handler != nullptr) {
//        delete this->handler;
//        this->handler = nullptr;
//    }
//    this->handler = new LoggerHelper<LoggerFlag::debug_logger_flag>;
//    return this->handler != nullptr;
//}

//template<>
//bool Logger::set_mode<LoggerFlag::warning_logger_flag>()
//{
//    if (this->handler != nullptr) {
//        delete this->handler;
//        this->handler = nullptr;
//    }
//    this->handler = new LoggerHelper<LoggerFlag::warning_logger_flag>;
//    return this->handler != nullptr;
//}

//template<>
//bool Logger::set_mode<LoggerFlag::info_logger_flag>()
//{
//    if (this->handler != nullptr) {
//        delete this->handler;
//        this->handler = nullptr;
//    }
//    this->handler = new LoggerHelper<LoggerFlag::info_logger_flag>;
//    return this->handler != nullptr;
//}

//template<>
//bool Logger::set_modes<LoggerFlag::logger_flag>()
//{
//    if (m_logger_instance.handler != nullptr) {
//        delete m_logger_instance.handler;
//        m_logger_instance.handler = nullptr;
//    }
//    m_logger_instance.handler = new LoggerHelper<LoggerFlag::logger_flag>;
//    return m_logger_instance.handler != nullptr;
//}

//template<>
//bool Logger::set_modes<LoggerFlag::critical_logger_flag>()
//{
//    if (m_logger_instance.handler != nullptr) {
//        delete m_logger_instance.handler;
//        m_logger_instance.handler = nullptr;
//    }
//    m_logger_instance.handler = new LoggerHelper<LoggerFlag::critical_logger_flag>;
//    return m_logger_instance.handler != nullptr;
//}

//template<>
//bool Logger::set_modes<LoggerFlag::error_logger_flag>()
//{
//    if (m_logger_instance.handler != nullptr) {
//        delete m_logger_instance.handler;
//        m_logger_instance.handler = nullptr;
//    }
//    m_logger_instance.handler = new LoggerHelper<LoggerFlag::error_logger_flag>;
//    return m_logger_instance.handler != nullptr;
//}

//template<>
//bool Logger::set_modes<LoggerFlag::debug_logger_flag>()
//{
//    if (m_logger_instance.handler != nullptr) {
//        delete m_logger_instance.handler;
//        m_logger_instance.handler = nullptr;
//    }
//    m_logger_instance.handler = new LoggerHelper<LoggerFlag::debug_logger_flag>;
//    return m_logger_instance.handler != nullptr;
//}

//template<>
//bool Logger::set_modes<LoggerFlag::warning_logger_flag>()
//{
//    if (m_logger_instance.handler != nullptr) {
//        delete m_logger_instance.handler;
//        m_logger_instance.handler = nullptr;
//    }
//    m_logger_instance.handler = new LoggerHelper<LoggerFlag::warning_logger_flag>;
//    return m_logger_instance.handler != nullptr;
//}

//template<>
//bool Logger::set_modes<LoggerFlag::info_logger_flag>()
//{
//    if (m_logger_instance.handler != nullptr) {
//        delete m_logger_instance.handler;
//        m_logger_instance.handler = nullptr;
//    }
//    m_logger_instance.handler = new LoggerHelper<LoggerFlag::info_logger_flag>;
//    return m_logger_instance.handler != nullptr;
//}


//template<typename out_flag>
//bool Logger::set_modes()
//{
//    qDebug() << "this flag is invalid";
//    return false;
//}


/******************************** set_mode methods ********************************/

bool Logger::set_mode(LoggerFlag::critical_logger_flag)
{
    if (this->handler != nullptr) {
        delete this->handler;
        this->handler = nullptr;
    }
    this->handler = new LoggerHelper<LoggerFlag::critical_logger_flag>;
    return this->handler != nullptr;
}

bool Logger::set_mode(LoggerFlag::error_logger_flag)
{
    if (this->handler != nullptr) {
        delete this->handler;
        this->handler = nullptr;
    }
    this->handler = new LoggerHelper<LoggerFlag::error_logger_flag>;
    return this->handler != nullptr;
}

bool Logger::set_mode(LoggerFlag::debug_logger_flag)
{
    if (this->handler != nullptr) {
        delete this->handler;
        this->handler = nullptr;
    }
    this->handler = new LoggerHelper<LoggerFlag::debug_logger_flag>;
    return this->handler != nullptr;
}

bool Logger::set_mode(LoggerFlag::warning_logger_flag)
{
    if (this->handler != nullptr) {
        delete this->handler;
        this->handler = nullptr;
    }
    this->handler = new LoggerHelper<LoggerFlag::warning_logger_flag>;
    return this->handler != nullptr;
}
bool Logger::set_mode(LoggerFlag::info_logger_flag)
{
    if (this->handler != nullptr) {
        delete this->handler;
        this->handler = nullptr;
    }
    this->handler = new LoggerHelper<LoggerFlag::info_logger_flag>;
    return this->handler != nullptr;
}

bool Logger::set_mode(LoggerFlag::logger_flag)
{
    if (this->handler != nullptr) {
        delete this->handler;
        this->handler = nullptr;
    }
    this->handler = new LoggerHelper<LoggerFlag::logger_flag>;
    return this->handler != nullptr;
}


/******************************** setmodes methods ********************************/

bool Logger::set_modes(LoggerFlag::logger_flag)
{
    if (m_logger_instance.handler != nullptr) {
        delete m_logger_instance.handler;
        m_logger_instance.handler = nullptr;
    }
    m_logger_instance.handler = new LoggerHelper<LoggerFlag::logger_flag>;
    return m_logger_instance.handler != nullptr;
}

bool Logger::set_modes(LoggerFlag::info_logger_flag)
{
    if (m_logger_instance.handler != nullptr) {
        delete m_logger_instance.handler;
        m_logger_instance.handler = nullptr;
    }
    m_logger_instance.handler = new LoggerHelper<LoggerFlag::info_logger_flag>;
    return m_logger_instance.handler != nullptr;
}

bool Logger::set_modes(LoggerFlag::warning_logger_flag)
{
    if (m_logger_instance.handler != nullptr) {
        delete m_logger_instance.handler;
        m_logger_instance.handler = nullptr;
    }
    m_logger_instance.handler = new LoggerHelper<LoggerFlag::warning_logger_flag>;
    return m_logger_instance.handler != nullptr;
}

bool Logger::set_modes(LoggerFlag::debug_logger_flag)
{
    if (m_logger_instance.handler != nullptr) {
        delete m_logger_instance.handler;
        m_logger_instance.handler = nullptr;
    }
    m_logger_instance.handler = new LoggerHelper<LoggerFlag::debug_logger_flag>;
    return m_logger_instance.handler != nullptr;
}

bool Logger::set_modes(LoggerFlag::error_logger_flag)
{
    if (m_logger_instance.handler != nullptr) {
        delete m_logger_instance.handler;
        m_logger_instance.handler = nullptr;
    }
    m_logger_instance.handler = new LoggerHelper<LoggerFlag::error_logger_flag>;
    return m_logger_instance.handler != nullptr;
}

bool Logger::set_modes(LoggerFlag::critical_logger_flag)
{
    if (m_logger_instance.handler != nullptr) {
        delete m_logger_instance.handler;
        m_logger_instance.handler = nullptr;
    }
    m_logger_instance.handler = new LoggerHelper<LoggerFlag::critical_logger_flag>;
    return m_logger_instance.handler != nullptr;
}


/******************************** Logger Manager *********************************/

LoggerManager::LoggerManager()
{
    m_logger_instances.clear();
}

LoggerManager::~LoggerManager()
{
    for (auto &logger_instance: m_logger_instances) {
        if (logger_instance.second != nullptr) {
#ifdef DEBUG
            qDebug() << "logger" << QString::fromStdString(logger_instance.first) << "is destructed";
#endif
            delete logger_instance.second;
            logger_instance.second = nullptr;
        }
    }
}


/******************************** request stream ********************************/

template<typename request_bool_type>
inline LoggerManagable::OutStream LoggerManagable::request_stream() {
    static QString idle_buffer;
    static QDebug idle_dbg(&idle_buffer);
    idle_buffer.clear();
    return idle_dbg;
}

template<>
inline LoggerManagable::OutStream LoggerManagable::request_stream<std::true_type>() {
    return qDebug();
}


/****************************** select output or not ******************************/

template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_critical()
{
    return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_critical::type>();
}

template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_error()
{
    return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_error::type>();
}

template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_debug()
{
    return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_debug::type>();
}

template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_warning()
{
    return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_warning::type>();
}


template<typename out_flag>
LoggerManagable::OutStream LoggerHelper<out_flag>::_info()
{
    return request_stream<typename LoggerFlag::type_traitor<out_flag>::enable_info::type>();
}


/******************************** void constructor ********************************/
template<typename output_flag>
LoggerHelper<output_flag>::LoggerHelper() {}

template<typename output_flag>
LoggerHelper<output_flag>::~LoggerHelper() {}

LoggerManagable::LoggerManagable() {}
LoggerManagable::~LoggerManagable() {}

看起來有點長,但都是複製粘貼…


補充:
有一個小bug= =,沒想到運行了十幾次以後隨機出現了這個錯誤。
LoggerManager LoggerManager::logger_destructorstd::map<> m_logger_instances之間有依賴關係(你也不能假定全局變量的初始化有先後順序,這和編譯器有關,是未定義行爲),不能同時聲明爲全局變量。解決辦法是將m_logger_instances設爲指針,並在LoggerManager中完成對m_logger_instances的操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章