项目:抓虫记日志系统(四)

目录:

  1. 目录

    一、引言

    二、局部日志制造器和局部日志器

    三、全局日志制造器和全局日志器

    四、全局日志器的管理器

    五、同步日志器和异步日志器

一、引言

        结合前文,我们实现了日志输出的时间、日志等级、格式化输出内容、异步日志器的缓冲区、异步日志器的输出。实现了日志器大体的框架。

        我们从日志获取到的有效信息、输出到的地方,以及多线程去输出日志要输出的信息用缓冲区类存储多线程日志器输出的信息,一个Buffer类单独管理多线程输出信息,从而避免了输出位置冲突的情况和输出内容完毕清除的情况。为了避免多线程之间的线程冲突,我们使用了互斥锁。互斥锁相当于一个保护机制,他限制了进入线程的数量。但是我们开发时最好还是只允许一个线程访问公共资源。何谓公共资源呢?就是不属于这个函数的外部资源,大家都知道在函数内创建并使用最后在函数内销毁的是临时资源,那与他相对的就是公共资源,将公共资源保护起来,避免收到其他线程的干扰。

        这篇博客小编打算聊聊最后一步全局日志制造器。

        在制造日志器过程中,我们使用指针传递的形式生成的日志器,无需构造中间值传递,非常快速便捷。为了防止指针执行的资源没有得到释放所以我们使用智能指针,智能管理规划好指针的析构工作。同时使用指针访问资源,这样要求日志器全局使用也只需要申请一个全局的智能指针管理存储对象(可以是vector)。我们使用日志器的名称在日志制造器中查找。当然我们通过传递形参告知日志制造器我们要制造的日志器具有什么功能。例如是同步还是异步,落地方向是都包括还是包括哪几个,限定日志等级是什么。

二、局部日志制造器和局部日志器

        为了更好的输出日志等级,我们将日志器做了一点微小的优化,直接将日志等级名作为函数名,封装日志器的输出。

        局部日志制造器,我们只需要创建他就好了,不用将他交给某一全局对象。另外我们原定计划是使用vector线性表来存储好局部日志器的,但是我们一般都是通过日志器的名称来查找日志器。所以我们使用unordered_map,这个unordered_map以后会有详细资料的,大家如果不太了解C++的这个容器的话可以点进下面的链接了解unordered_map容器的接口和大致的一个搜索时间复杂度O(1):

        https://cplusplus.com/reference/unordered_map/.

        局部日志器我们只需要提供一个通过形参制造日志器的接口就行了,接口返回一个日志器的智能指针。因为局部日志制造器和全局日志制造器有非常多的相似性。所以我们可以通过继承某一个纯虚类搭建一个框架。实现所有纯虚类中的纯虚函数。这样如果我们要进行新的添加日志制造器,也只需要一个新的类去继承这个纯虚类就可以做到快速搭建了。

三、全局日志制造器和全局日志器

        为了满足一些日志器的需要伴随文件开始直到文件的结束。我们使用全局日志器。那我们该如何做到全局呢?其实就和局部日志器不同的是使用一个全局的对象进行管理指向全局的日志器的智能指针。全局的对象内置了一个static对象。需要初始化日志器时再创建,我们称为懒汉模式。

四、全局日志器的管理器

        全局日志器的管理器肯定也是一个static静态对象。由于是全局对象,所以出现一个就够了。所以我们为了添加全局日志器所以我们需要在全局日志器管理器中添加一个引用自身也就是全局日志器管理器的对象。使用时我们再进行创建,创建太早了也是一种对资源的浪费。这就是懒汉模式。先进行创建,再使用,这就是饿汉模式。这两种都是可以的。由于我们需要实例化出对象才可以调用类中的函数,所以我们选择使用饿汉模式。值得一提的是就算我们将函数static,类函数使用了类中的变量不是static,也还是无法调用的。

五、同步日志器和异步日志器

        我们设置类里面包含纯虚函数,让其他类继承这个类,相当于一个框架。框架虽然限制了我们的思维,但是他能够极好地保证了代码的可靠性。

代码如下:

#ifndef __LOGGER_HPP___
#define __LOGGER_HPP___

#include <iostream>
#include <vector>
#include <atomic>
#include <mutex>
#include <memory>
#include <cstdarg>
#include <functional>
#include <unordered_map>
#include "Until.hpp"
#include "Level.hpp"
#include "Format.hpp"
#include "Message.hpp"
#include "Sink.hpp"

#include "Looper.hpp"

namespace Logs
{
    class Logger
    {
    public:
        using Ptr = std::shared_ptr<Logger>;

        Logger( Level::Value& limit_level
            , Formatter::Ptr& formatter
            ,const std::string& logger_name
            ,std::vector<Sink::Ptr>& sinks
            )
            :_limit_level(limit_level)
            ,_formatter(formatter)
            ,_logger_name(logger_name)
            ,_sinks(sinks.begin(),sinks.end())
        {
            ;
        }
        const std::string& loggerName()
        {
            return _logger_name;
        }
        void debug(const std::string& file,size_t line,const std::string& fmt,...)
        {
            if(Level::Value::DEBUG < _limit_level)
            {
                return ;
            }
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf failed!!\n";

                return ;
            }
            va_end(ap);
            Serialize(Level::Value::DEBUG,file,line,res);

            free(res);
        }
        void info(const std::string& file,size_t line,const std::string& fmt,...)
        {
            if(Level::Value::INFO < _limit_level)
            {
                return ;
            }
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf failed!!\n";

                return ;
            }
            va_end(ap);
            Serialize(Level::Value::INFO,file,line,res);
            
            free(res);
        }
        void warn(const std::string& file,size_t line,const std::string& fmt,...)
        {
            if(Level::Value::WARN < _limit_level)
            {
                return ;
            }
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf failed!!\n";

                return ;
            }
            va_end(ap);
            Serialize(Level::Value::WARN,file,line,res);
            
            free(res);
        }
        void error(const std::string& file,size_t line,const std::string& fmt,...)
        {
            if(Level::Value::ERROR < _limit_level)
            {
                return ;
            }
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf failed!!\n";

                return ;
            }
            va_end(ap);
            Serialize(Level::Value::ERROR,file,line,res);
            
            free(res);
        }
        void fatal(const std::string& file,size_t line,const std::string& fmt,...)
        {
            if(Level::Value::FATAL < _limit_level)
            {
                return ;
            }
            va_list ap;
            va_start(ap,fmt);
            char* res;
            // vasprintf根据不定参数的列表中的数据进行字符串的初始化。
            // 这res是动态申请的资源,记得释放。
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret == -1)
            {
                std::cout << "vasprintf failed!!\n";

                return ;
            }
            va_end(ap);
            Serialize(Level::Value::FATAL,file,line,res);
            
            free(res);
        }
    //protected:
        virtual void log(const char* str,size_t len) = 0;
        void Serialize(Level::Value level,const std::string& file,size_t line,char* res)
        {
            Message msg(Until::Time::GetTime(),level,file,line,res,_logger_name);
            std::stringstream ss;
            //ss << res << "\n";
            _formatter->format(ss,msg);
            log(ss.str().c_str(),ss.str().size());
        }
    protected:
        std::mutex _mutex;
        std::atomic<Level::Value> _limit_level;
        Formatter::Ptr _formatter;
        std::string _logger_name;
        std::vector<Sink::Ptr> _sinks;
    };
    // 同步日志器。
    class SyncLogger : public Logger
    {
    public:
        SyncLogger(Level::Value& limit_level
            ,Formatter::Ptr& formatter
            ,const std::string& logger_name
            ,std::vector<Sink::Ptr>& sinks
            )
            :Logger(limit_level,formatter,logger_name,sinks)
        {
            ;
        }
        void log(const char* str,size_t len) override
        {
            std::unique_lock<std::mutex> _lock(_mutex);
            if(_sinks.empty())
            {
                return ;
            }
            for(auto& sink : _sinks)
            {
                sink->log(str,len);
            }
        }
    private:
    };
    // 异步日志器。
    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(Level::Value limit_level
                    ,Formatter::Ptr formatter
                    ,const std::string&  logger_name
                    ,std::vector<Sink::Ptr>& sinks
                    ,AsyncType looper_type = AsyncType::ASYNC_SAFE)
            :Logger(limit_level,formatter,logger_name,sinks)
            ,_looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog,this,std::placeholders::_1),looper_type))
            ,_looper_type(looper_type)
        {
            std::cout << Level::To_String(_limit_level) << "异步日志器: " << _logger_name << "创建成功...\n";
            std::cout << "sink:" << _sinks.size() << "\n";
        }
        // push进缓冲区。 
        void log(const char* str,size_t len) override
        {
            _looper->push(str,len);
        }
        // 设计一个实际落地函数。(将缓冲区的内容落地)
        void realLog(Buffer& buffer)
        {
            if(_sinks.empty())
            {
                return ;
            }
            std::cout << _sinks.size() << std::endl;
            for(auto& sink : _sinks)
            {
                sink->log(buffer.begin(),buffer.readAbleLen());
            }
        }
    private:
        AsyncLooper::Ptr _looper;
        AsyncType _looper_type;
    };

    enum class LoggerType
    {
        LOGGER_ASYNC,
        LOGGER_SYNC
    };

    class LoggerBuilder
    {
    public:
        using Ptr = std::shared_ptr<LoggerBuilder>;
        // LoggerBuilder(LoggerType logger_type
        //            ,AsyncType looper_type
        //            ,Level::Value limit_level
        //            //,Formatter::Ptr& formatter
        //            ,const std::string& logger_name
        //            //,std::vector<Sink::Ptr>& sinks
        //            )
        //     :_logger_type(logger_type)
        //     ,_limit_level(limit_level)
        //     //,_formatter(formatter)
        //     ,_logger_name(logger_name)
        //     //,_sinks(sinks.begin(),sinks.end())
        //     ,_looper_type(looper_type) // 默认是安全的。
        // {
        //     ;
        // }
        LoggerBuilder()
            :_limit_level(Level::Value::DEBUG)
            ,_logger_type(LoggerType::LOGGER_SYNC)
            ,_looper_type(AsyncType::ASYNC_SAFE)
        {}
        void BuildLoggerType(LoggerType type)// 调整为不安全的。
        {
            _logger_type = type;
        }
        void BuildAsyncUnsafe()
        {
            _looper_type = AsyncType::ASYNC_UNSAFE;
        }
        void BuildLoggerName(const std::string& name)
        {
            _logger_name = name;
        }
        void BuildLoggerLevel(Level::Value level)
        {
            _limit_level = level;
        }
        void BuildFormatter(const std::string& pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }

        template< typename SinkType , typename ...Args >
        void BuildSink(Args&& ...args)
        {
            Sink::Ptr psink = SinkFactory::CreateSink<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }

        virtual Logger::Ptr Build() = 0;
    protected:
        LoggerType _logger_type;
        AsyncType _looper_type;
        Level::Value _limit_level;
        Formatter::Ptr _formatter;
        std::string _logger_name;
        std::vector<Sink::Ptr> _sinks;
    };

    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        // LocalLoggerBuilder(LoggerType logger_type
        //            ,Level::Value limit_level
        //            //,Formatter::Ptr& formatter
        //            ,const std::string& logger_name
        //            //,std::vector<Sink::Ptr>& sinks
        //            ,AsyncType looper_type = AsyncType::ASYNC_SAFE
        //            )
        //     :LoggerBuilder(logger_type,looper_type,limit_level,logger_name)
        // {
        //     ;
        // }
        LocalLoggerBuilder()
            :LoggerBuilder()
        {}
        Logger::Ptr Build() override
        {
            // 日志器的名字是查找日志器的唯一凭证。
            // 不可或缺。
            assert(_logger_name.size());
            // 接下来再慢慢改。
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                BuildSink<StdoutSink>();
            }
            // 异步日志器
            if(_logger_type == LoggerType::LOGGER_ASYNC)
            {
                // Level::Value limit_level
                //     ,Formatter::Ptr formatter
                //     ,const std::string&  logger_name
                //     ,std::vector<Sink::Ptr>& sinks
                //     ,AsyncType looper_type = AsyncType::ASYNC_SAFE
                std::cout << "制造异步日志器" << std::endl;
                std::cout <<"_sinks:" << _sinks.size() << "\n";
                return std::make_shared<AsyncLogger>(_limit_level,_formatter,_logger_name,_sinks,_looper_type);
            }

            // 同步日志器
            // Level::Value& limit_level
            // ,Formatter::Ptr& formatter
            // ,const std::string& logger_name
            // ,std::vector<Sink::Ptr>& sinks
            return std::make_shared<SyncLogger>(_limit_level,_formatter,_logger_name,_sinks);
        }
    };

    class LoggerManager
    {
    public:
        static LoggerManager& getInc()
        {
            // static 是有线程安全的,不用担心会创建多个static对象。
            static LoggerManager self;
            return self;
        }
        void addLogger(Logger::Ptr logger)
        {
            // 访问公共资源时记得加锁。
            if(hasLogger(logger->loggerName()))
            {
                return ;
            }
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->loggerName(),logger));
        }
        bool hasLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            std::unordered_map<std::string,Logger::Ptr>::iterator pos = _loggers.find(name);
            if(pos == _loggers.end())
            {
                return false;
            }

            return true;
        }
        Logger::Ptr getLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            std::unordered_map<std::string,Logger::Ptr>::iterator pos = _loggers.find(name);
            if(pos == _loggers.end())
            {
                return nullptr;
            }

            return pos->second;
        }
        Logger::Ptr rootLogger()
        {
            return _root_logger;
        }
    private:
        // LoggerManage(LoggerType logger_type
        //            ,Level::Value limit_level
        //            //,Formatter::Ptr& formatter
        //            ,const std::string& logger_name
        //            //,std::vector<Sink::Ptr>& sinks
        //            ,AsyncType looper_type = AsyncType::ASYNC_SAFE)
        LoggerManager()
        {
            std::unique_ptr<LoggerBuilder> build(std::make_unique<LocalLoggerBuilder>());
            build->BuildLoggerName("root");
            _root_logger = build->Build();
            _loggers.insert(std::make_pair("root",_root_logger));
        }
    private:
        std::mutex _mutex; 
        Logger::Ptr _root_logger; // 默认日志器。
        std::unordered_map<std::string,Logger::Ptr> _loggers;
    };
    
    // 设计一个全局日志器制造者。
    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        // LocalLoggerBuilder(LoggerType logger_type
        //            ,Level::Value limit_level
        //            //,Formatter::Ptr& formatter
        //            ,const std::string& logger_name
        //            //,std::vector<Sink::Ptr>& sinks
        //            ,AsyncType looper_type = AsyncType::ASYNC_SAFE
        //            )
        //     :LoggerBuilder(logger_type,looper_type,limit_level,logger_name)
        // {
        //     ;
        // }
        GlobalLoggerBuilder(){}
        Logger::Ptr Build() override
        {
            // 日志器的名字是查找日志器的唯一凭证。
            // 不可或缺。
            assert(_logger_name.size());
            // 接下来再慢慢改。
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if(_sinks.empty())
            {
                BuildSink<StdoutSink>();
            }

            Logger::Ptr logger;

            // 异步日志器
            if(_logger_type == LoggerType::LOGGER_ASYNC)
            {
                logger = std::make_shared<AsyncLogger>(_limit_level,_formatter,_logger_name,_sinks,_looper_type);
            }

            std::make_shared<SyncLogger>(_limit_level,_formatter,_logger_name,_sinks);
            
            LoggerManager::getInc().addLogger(logger);
            return logger;
        }
    };
}

#endif
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值