spdlog源码分析:日志输出目标sink

spdlog提供了多种输出目标:环形日志,每日日志,控制台日志,syslog日志,并且可以自己进行扩展。在选择输出目标的同时,我们可以选择使用单线程或多线程版本。日志输出目标的基类是sink,有两个虚函数需要实现。

class sink
{
public:
    virtual ~sink() {}
    /*日志输出*/
    virtual void log(const details::log_msg& msg) = 0;
    /*冲刷日志,清出缓存中的日志*/
    virtual void flush() = 0;
};

在sink的基础上,又提供单、多线程选择的base_sink,通过模板Mutex选择单、多线程版本

template<class Mutex>
class base_sink:public sink
{
public:
    base_sink():_mutex() {}
    virtual ~base_sink() = default;

    base_sink(const base_sink&) = delete;
    base_sink& operator=(const base_sink&) = delete;

    void log(const details::log_msg& msg) override
    {
        /*锁保护,如果是单线程,这个锁什么也不做*/
        std::lock_guard<Mutex> lock(_mutex);
        _sink_it(msg);
    }

protected:
    virtual void _sink_it(const details::log_msg& msg) = 0;
    Mutex _mutex;
};

这样一来,实现一个日志输出目标只需实现两个虚函数_sink_it和flush,比如控制台日志

template <class Mutex>
class stdout_sink : public base_sink<Mutex>
{
    using MyType = stdout_sink<Mutex>;
public:
    stdout_sink() {}
    static std::shared_ptr<MyType> instance()
    {
        static std::shared_ptr<MyType> instance = std::make_shared<MyType>();
        return instance;
    }

    void _sink_it(const details::log_msg& msg) override
    {
        fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout);
        flush();
    }

    void flush() override
    {
        fflush(stdout);
    }
};

单线程日志使用的锁是null_mutex,多线程使用的锁是mutex

typedef stdout_sink<details::null_mutex> stdout_sink_st;
typedef stdout_sink<std::mutex> stdout_sink_mt;

null_mutex什么都不做

struct null_mutex
{
    void lock() {}
    void unlock() {}
    bool try_lock()
    {
        return true;
    }
};

你可能感兴趣的:(C++,spdlog)