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

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

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

位置分类:

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

    };
相关推荐
tan180°4 小时前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
彭祥.5 小时前
Jetson边缘计算主板:Ubuntu 环境配置 CUDA 与 cudNN 推理环境 + OpenCV 与 C++ 进行目标分类
c++·opencv·分类
lzb_kkk6 小时前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节
胖大和尚8 小时前
clang 编译器怎么查看在编译过程中做了哪些优化
c++·clang
&Sinnt&8 小时前
Git 版本控制完全指南:从入门到精通
git·后端
钱彬 (Qian Bin)9 小时前
一文掌握Qt Quick数字图像处理项目开发(基于Qt 6.9 C++和QML,代码开源)
c++·开源·qml·qt quick·qt6.9·数字图像处理项目·美观界面
双叶8369 小时前
(C++)学生管理系统(正式版)(map数组的应用)(string应用)(引用)(文件储存的应用)(C++教学)(C++项目)
c语言·开发语言·数据结构·c++
源代码•宸9 小时前
C++高频知识点(二)
开发语言·c++·经验分享
jyan_敬言11 小时前
【C++】string类(二)相关接口介绍及其使用
android·开发语言·c++·青少年编程·visual studio
Tiny21411 小时前
多人协同开发时Git使用命令
git