项目日志——日志落地模块的设计、实现、测试

打印 上一主题 下一主题

主题 866|帖子 866|积分 2600

日志落地模块

设计

功能是,将格式化完成后的日志消息字符串,输出到指定的位置
支持将日志落地到差别的位置


  • 尺度输出
  • 指定文件
  • 滚动文件
滚动文件按照时间或者大小进行滚动切换,可以按照天数对日志信息进行管理
我们这里实现按照大小进行滚动文件的设计
同时也是支持落地方向的扩展,可以写入到云服务器或者数据库中
用户可以自己编写一个新的日志落地模块进行实现,因此须要设计一个简单工厂模式进行管理
实现头脑是这样的

  • 抽象出落地模块的基类
  • 派生出差别落地方向的子类
  • 利用工厂模式进行创建和表示的分离,便于对象的扩展
实现

  1. /*
  2.     日志落地模块的实现
  3.         1. 抽象落地基类
  4.         2. 派生子类
  5.         3. 使用工厂模式进行创建与表示的分离
  6. */
  7. #pragma once
  8. #include "util.hpp"
  9. #include <memory>
  10. #include <fstream>
  11. #include <cassert>
  12. #include <sstream>
  13. namespace Xulog
  14. {
  15.     class LogSink
  16.     {
  17.     public:
  18.         using ptr = std::shared_ptr<LogSink>;
  19.         LogSink() {}
  20.         virtual ~LogSink() {}
  21.         virtual void log(const char *data, size_t len) = 0;
  22.     };
  23.     // 标准输出
  24.     class StdoutSink : public LogSink
  25.     {
  26.     public:
  27.         // 日志写入到标准输出
  28.         void log(const char *data, size_t len)
  29.         {
  30.             std::cout.write(data, len);
  31.         }
  32.     };
  33.     // 指定文件
  34.     class FileSink : public LogSink
  35.     {
  36.     public:
  37.         // 传入文件名时,构造并打开文件,将操作句柄管理起来
  38.         FileSink(const std::string &pathname)
  39.             : _pathname(pathname)
  40.         {
  41.             Util::File::createDirectory(Util::File::path(_pathname)); // 创建目录
  42.             _ofs.open(_pathname, std::ios::binary | std::ios::app);   // 打开文件
  43.             assert(_ofs.is_open());
  44.         }
  45.         void log(const char *data, size_t len)
  46.         {
  47.             _ofs.write(data, len);
  48.             assert(_ofs.good());
  49.         }
  50.     private:
  51.         std::string _pathname;
  52.         std::ofstream _ofs;
  53.     };
  54.     // 滚动文件(大小)
  55.     class RollSinkBySize : public LogSink
  56.     {
  57.     public:
  58.         RollSinkBySize(const std::string &basename, size_t max_size)
  59.             : _basename(basename), _max_fsize(max_size), _current_fsize(0), _cnt(0)
  60.         {
  61.             std::string pathname = creatNewFIle();
  62.             Util::File::createDirectory(Util::File::path(pathname)); // 创建目录
  63.             _ofs.open(pathname, std::ios::binary | std::ios::app);
  64.             assert(_ofs.is_open());
  65.         }
  66.         void log(const char *data, size_t len)
  67.         {
  68.             if (_current_fsize >= _max_fsize)
  69.             {
  70.                 std::string pathname = creatNewFIle();
  71.                 _ofs.close(); // 关闭原来已经打开的文件
  72.                 _ofs.open(pathname, std::ios::binary | std::ios::app);
  73.                 assert(_ofs.is_open());
  74.                 _current_fsize = 0;
  75.                 // _cnt = 0;
  76.             }
  77.             _ofs.write(data, len);
  78.             assert(_ofs.good());
  79.             _current_fsize += len;
  80.         }
  81.     private:
  82.         std::string creatNewFIle() // 大小判断,超过则创建新文件
  83.         {
  84.             // 获取系统时间,构造文件扩展名
  85.             time_t t = Util::Date::getTime();
  86.             struct tm lt;
  87.             localtime_r(&t, &lt);
  88.             std::stringstream filename;
  89.             filename << _basename << lt.tm_year + 1900 << lt.tm_mon + 1 << lt.tm_mday << lt.tm_hour << lt.tm_min << lt.tm_sec << "-" << _cnt++ << ".log";
  90.             return filename.str();
  91.         }
  92.     private:
  93.         std::string _basename; // 基础文件名 (+扩展文件名-时间|计数器)
  94.         std::ofstream _ofs;
  95.         size_t _max_fsize;     // 大小上限
  96.         size_t _current_fsize; // 当前大小
  97.         size_t _cnt;           // 日志数量
  98.     };
  99.    
  100.     // 简单工厂模式
  101.     class SinkFactory
  102.     {
  103.     public:
  104.         template <typename SinkType, typename... Args>
  105.         static LogSink::ptr create(Args &&...args)
  106.         {
  107.             return std::make_shared<SinkType>(std::forward<Args>(args)...);
  108.         }
  109.     };
  110. }
复制代码
扩展实现

  1. // 扩展测试: 滚动文件(时间)
  2. // 1. 以时间段滚动
  3. // 2. time(nullptr)%gap;
  4. enum class TimeGap
  5. {
  6.     GAP_SECOND,
  7.     GAP_MINUTE,
  8.     GAP_HOUR,
  9.     GAP_DAY
  10. };
  11. class RollSinkByTime : public Xulog::LogSink
  12. {
  13. public:
  14.     // 传入文件名时,构造并打开文件,将操作句柄管理起来
  15.     RollSinkByTime(const std::string &basename, TimeGap gap_type)
  16.         : _basename(basename)
  17.     {
  18.         switch (gap_type)
  19.         {
  20.         case TimeGap::GAP_SECOND:
  21.             _gap_size = 1;
  22.             break;
  23.         case TimeGap::GAP_MINUTE:
  24.             _gap_size = 60;
  25.             break;
  26.         case TimeGap::GAP_HOUR:
  27.             _gap_size = 3600;
  28.             break;
  29.         case TimeGap::GAP_DAY:
  30.             _gap_size = 3600 * 24;
  31.             break;
  32.         }
  33.         _current_gap = _gap_size == 1 ? Xulog::Util::Date::getTime() : (Xulog::Util::Date::getTime() % _gap_size);
  34.         std::string filename = createNewFile();
  35.         Xulog::Util::File::createDirectory(Xulog::Util::File::path(filename)); // 创建目录
  36.         _ofs.open(filename, std::ios::binary | std::ios::app);
  37.         assert(_ofs.is_open());
  38.     }
  39.     void log(const char *data, size_t len)
  40.     {
  41.         time_t current = Xulog::Util::Date::getTime();
  42.         if (current % _gap_size != _current_gap)
  43.         {
  44.             std::string filename = createNewFile();
  45.             _ofs.close();
  46.             _ofs.open(filename, std::ios::binary | std::ios::app);
  47.             assert(_ofs.is_open());
  48.         }
  49.         _ofs.write(data, len);
  50.         assert(_ofs.good());
  51.     }
  52. private:
  53.     std::string createNewFile()
  54.     {
  55.         time_t t = Xulog::Util::Date::getTime();
  56.         struct tm lt;
  57.         localtime_r(&t, &lt);
  58.         std::stringstream filename;
  59.         filename << _basename << lt.tm_year + 1900 << lt.tm_mon + 1 << lt.tm_mday << lt.tm_hour << lt.tm_min << lt.tm_sec << ".log";
  60.         return filename.str();
  61.     }
  62. private:
  63.     std::string _basename;
  64.     std::ofstream _ofs;
  65.     size_t _current_gap; // 当前时间段的个数
  66.     size_t _gap_size;    // 间隔大小
  67. };
复制代码
测试

  1.     Xulog::LogMsg msg(Xulog::LogLevel::value::ERROR, 124, "main.cc", "root", "格式化功能测试");
  2.     Xulog::Formatter fmt1;
  3.     std::string str1 = fmt1.Format(msg);
  4.     // 测试原生日志落地模块
  5.     Xulog::LogSink::ptr std_lsp = Xulog::SinkFactory::create<Xulog::StdoutSink>();
  6.     Xulog::LogSink::ptr file_lsp = Xulog::SinkFactory::create<Xulog::FileSink>("./log/test.log");
  7.     Xulog::LogSink::ptr roll_lsp = Xulog::SinkFactory::create<Xulog::RollSinkBySize>("./log/roll-", 1024 * 1024); // 每个文件1MB
  8.     Xulog::LogSink::ptr time_lsp = Xulog::SinkFactory::create<RollSinkByTime>("./log/roll-", TimeGap::GAP_SECOND); // 每个文件1s
  9.     std_lsp->log(str1.c_str(), str1.size());
  10.     file_lsp->log(str1.c_str(), str1.size());
  11.     size_t size = 0;
  12.     size_t cnt = 0;
  13.     while (size < 1024 * 1024 * 100) // 100 个
  14.     {
  15.         std::string tmp = std::to_string(cnt++);
  16.         tmp += str1;
  17.         roll_lsp->log(tmp.c_str(), tmp.size());
  18.         size += tmp.size();
  19.     }
  20.     time_t t = Xulog::Util::Date::getTime();
  21.     while (Xulog::Util::Date::getTime() < t + 3)
  22.     {
  23.         time_lsp->log(str1.c_str(), str1.size());
  24.     }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

拉不拉稀肚拉稀

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表