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

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

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

位置分类:

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)...);
            }

    };
相关推荐
vibecoding日记12 小时前
为什么我就想要「线性历史 + Signed Commits」,GitHub 却把我当猴耍 🤬🎙️
git·编程工具
端平入洛16 小时前
delete又未完全delete
c++
程序员小崔日记1 天前
如何将代码轻松上传到 Gitee?Git 使用全攻略!
git·gitee·上传
端平入洛2 天前
auto有时不auto
c++
Bigger2 天前
为什么你的 Git 提交需要签名?—— Git Commit Signing 完全指南
git·开源·github
DianSan_ERP3 天前
电商API接口全链路监控:构建坚不可摧的线上运维防线
大数据·运维·网络·人工智能·git·servlet
哇哈哈20213 天前
信号量和信号
linux·c++
多恩Stone3 天前
【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系
开发语言·c++·人工智能·python·算法·3d·aigc
智渊AI3 天前
Ubuntu 20.04/22.04 下通过 NVM 安装 Node.js 22(LTS 稳定版)
ubuntu·node.js·vim