同步&异步日志系统-日志落地模块的实现

功能:将格式化完成后的日志消息字符串,输出到指定的位置

扩展:支持同时将日志落地到不同的位置

位置分类:

1.标准输出

2.指定文件(时候进行日志分析)

3.滚动文件(文件按照时间/大小进行滚动切换)

扩展:支持落地方向的扩展

用户可以自己编写一个新的落地模块,将日志进行其他方向的落地。

实现思想

1.抽象出一个落地基类

2.之后根据落地方向从基类派生出不同落地方向的子类

3.使用工厂模式进行创建与表示分离

标准输出

cpp 复制代码
class StdoutSink :public LogSink{
        public:
            void log(const char* data,size_t len)override{
                std::cout.write(data,len);
            }
    };

输入到指定文件

cpp 复制代码
class FileSink :public LogSink{
        public:
        //传入文件路径,并且打开文件
        FileSink(const std::string& pathname)
        :_pathname(pathname){
            //创建日志文件所在的目录
            util::File::createDirectory(util::File::path(pathname));
            //创建并打开日志文件
            _ofs.open(_pathname,std::ios::binary|std::ios::app);
            assert(_ofs.is_open());//判断文件是否打开
        }
        //将日志消息输入到文件里面
            void log(const char* data,size_t len)override{
                _ofs.write(data,len);
                assert(_ofs.good());
            }
        private:
        std::string _pathname;
        std::ofstream _ofs;
    };

以大小进行滚动

cpp 复制代码
class RollBySizeSink :public LogSink{
        public:
        //传入文件路径,并且打开文件
        RollBySizeSink(const std::string& basename,size_t max_size)
        :_basename(basename),_max_fsize(max_size),_cur_fsize(0){
            std::string pathname = createNewFile();
            //创建日志文件所在的目录
            util::File::createDirectory(util::File::path(pathname));
            //创建并打开日志文件
            _ofs.open(pathname,std::ios::binary|std::ios::app);
            assert(_ofs.is_open());//判断文件是否打开
        }
        //写入前判断文件大小,超过了最大大小就要切换文件
            void log(const char* data,size_t len)override{
                if(_cur_fsize>= _max_fsize){
                    std::string pathname = createNewFile();
                    _ofs.close();//关闭原来已经打开的文件。
                    _ofs.open(pathname,std::ios::binary|std::ios::app);
                    assert(_ofs.is_open());
                    _cur_fsize = 0;
                }
                _ofs.write(data,len);
                assert(_ofs.good());
                _cur_fsize += len;
            }
        private:
            std::string createNewFile(){
                //获取系统时间,以时间来构造文件扩展名
                time_t t = util::Date::now();
                struct tm lt;
                localtime_r(&t,&lt);//将时间戳转换为有年月日的结构
                std::stringstream filename;
                filename << _basename;
                filename << lt.tm_year+1900;
                filename << lt.tm_mon+1;
                filename << lt.tm_mday;
                filename << lt.tm_hour;
                filename << lt.tm_min;
                filename << lt.tm_sec;
                filename << "-";
                filename <<_name_count++;
                filename << ".log";
                return filename.str();
            }//进行大小判断,超过指定大小就要切换新文件
        private:
        //基础文件名+扩展文件名(时间生成)组成一个实际的当前输出文件名
            size_t _name_count=0;
            std::string _basename;
            std::ofstream _ofs;
            size_t _max_fsize;//记录最大大小,当前文件超过了这个大小就要切换文件
            size_t _cur_fsize;//记录当前文件已经写入的大小
    };

以时间进行滚动

cpp 复制代码
enum class TimeGap{
    GAP_SECOND,
    GAP_MIUTE,
    GAP_HOUR,
    GAP_DAY,
};
 class RollByTimeSink :public bitlog::LogSink{
        public:
        //传入文件路径,并且打开文件
        RollByTimeSink(const std::string& basename,TimeGap gap_type)
        :_basename(basename){
            switch(gap_type){
                case TimeGap::GAP_SECOND:_gap_size = 1;break;
                case TimeGap::GAP_MIUTE:_gap_size = 60;break;
                case TimeGap::GAP_HOUR:_gap_size = 3600;break;
                case TimeGap::GAP_DAY:_gap_size = 3600*24;break;
            }
            _cur_gap = _gap_size == 1 ? bitlog::util::Date::now() : bitlog::util::Date::now() % _gap_size;
            std::string filename = createNewFile();
            //创建日志文件所在的目录
            bitlog::util::File::createDirectory(bitlog::util::File::path(filename));
            //创建并打开日志文件
            _ofs.open(filename,std::ios::binary|std::ios::app);
            assert(_ofs.is_open());//判断文件是否打开
        }
        //写入前判断文件大小,超过了最大大小就要切换文件
            void log(const char* data,size_t len)override{
            time_t cur =bitlog::util::Date::now();
                if((cur%_gap_size)!=_cur_gap){
                    _ofs.close();
                    std::string filename = createNewFile();
                    _ofs.open(filename,std::ios::binary|std::ios::app);
                    assert(_ofs.is_open());
                }
                _ofs.write(data,len);
                assert(_ofs.good());
                
            }
        private:
            std::string createNewFile(){
                //获取系统时间,以时间来构造文件扩展名
                time_t t = bitlog::util::Date::now();
                struct tm lt;
                localtime_r(&t,&lt);//将时间戳转换为有年月日的结构
                std::stringstream filename;
                filename << _basename;
                filename << lt.tm_year+1900;
                filename << lt.tm_mon+1;
                filename << lt.tm_mday;
                filename << lt.tm_hour;
                filename << lt.tm_min;
                filename << lt.tm_sec;
                filename << ".log";
                return filename.str();
            }//进行大小判断,超过指定大小就要切换新文件
        private:
        std::string _basename;
        std::ofstream _ofs;
        size_t _cur_gap;//当前是第几个时间段
        size_t _gap_size;//时间段的大小
    };

使用简易工厂模式来创建

cpp 复制代码
class SinkFactory{
        public:
        template<typename SinkType,typename ...Args>
            static LogSink::ptr create(Args &&...args){
                return std::make_shared<SinkType>(std::forward<Args>(args)...);
            }

    };
相关推荐
超闻逸事1 分钟前
【题解】[UTPC2024] C.Card Deck
c++·算法
暴力求解12 分钟前
C++类和对象(上)
开发语言·c++·算法
让我们一起加油好吗25 分钟前
【基础算法】枚举(普通枚举、二进制枚举)
开发语言·c++·算法·二进制·枚举·位运算
大锦终26 分钟前
【C++】特殊类设计
开发语言·c++
泽02021 小时前
C++之STL--list
开发语言·c++·list
Dovis(誓平步青云)3 小时前
探索C++标准模板库(STL):String接口的底层实现(下篇)
开发语言·c++·stl·string
KyollBM3 小时前
【CF】Day75——CF (Div. 2) B (数学 + 贪心) + CF 882 (Div. 2) C (01Trie | 区间最大异或和)
c语言·c++·算法
feiyangqingyun4 小时前
Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
c++·qt·udp·gb28181
CV点灯大师4 小时前
C++算法训练营 Day10 栈与队列(1)
c++·redis·算法
养意4 小时前
git提交代码和解决冲突修复bug
git·bug