日志落地模块
设计
功能是,将格式化完成后的日志消息字符串,输出到指定的位置
支持将日志落地到差别的位置
滚动文件按照时间或者大小进行滚动切换,可以按照天数对日志信息进行管理
我们这里实现按照大小进行滚动文件的设计
同时也是支持落地方向的扩展,可以写入到云服务器或者数据库中
用户可以自己编写一个新的日志落地模块进行实现,因此须要设计一个简单工厂模式进行管理
实现头脑是这样的
- 抽象出落地模块的基类
- 派生出差别落地方向的子类
- 利用工厂模式进行创建和表示的分离,便于对象的扩展
实现
- /*
- 日志落地模块的实现
- 1. 抽象落地基类
- 2. 派生子类
- 3. 使用工厂模式进行创建与表示的分离
- */
- #pragma once
- #include "util.hpp"
- #include <memory>
- #include <fstream>
- #include <cassert>
- #include <sstream>
- namespace Xulog
- {
- class LogSink
- {
- public:
- using ptr = std::shared_ptr<LogSink>;
- LogSink() {}
- virtual ~LogSink() {}
- virtual void log(const char *data, size_t len) = 0;
- };
- // 标准输出
- class StdoutSink : public LogSink
- {
- public:
- // 日志写入到标准输出
- void log(const char *data, size_t len)
- {
- std::cout.write(data, len);
- }
- };
- // 指定文件
- 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)
- {
- _ofs.write(data, len);
- assert(_ofs.good());
- }
- private:
- std::string _pathname;
- std::ofstream _ofs;
- };
- // 滚动文件(大小)
- class RollSinkBySize : public LogSink
- {
- public:
- RollSinkBySize(const std::string &basename, size_t max_size)
- : _basename(basename), _max_fsize(max_size), _current_fsize(0), _cnt(0)
- {
- std::string pathname = creatNewFIle();
- 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)
- {
- if (_current_fsize >= _max_fsize)
- {
- std::string pathname = creatNewFIle();
- _ofs.close(); // 关闭原来已经打开的文件
- _ofs.open(pathname, std::ios::binary | std::ios::app);
- assert(_ofs.is_open());
- _current_fsize = 0;
- // _cnt = 0;
- }
- _ofs.write(data, len);
- assert(_ofs.good());
- _current_fsize += len;
- }
- private:
- std::string creatNewFIle() // 大小判断,超过则创建新文件
- {
- // 获取系统时间,构造文件扩展名
- time_t t = Util::Date::getTime();
- struct tm lt;
- localtime_r(&t, <);
- std::stringstream filename;
- filename << _basename << lt.tm_year + 1900 << lt.tm_mon + 1 << lt.tm_mday << lt.tm_hour << lt.tm_min << lt.tm_sec << "-" << _cnt++ << ".log";
- return filename.str();
- }
- private:
- std::string _basename; // 基础文件名 (+扩展文件名-时间|计数器)
- std::ofstream _ofs;
- size_t _max_fsize; // 大小上限
- size_t _current_fsize; // 当前大小
- size_t _cnt; // 日志数量
- };
-
- // 简单工厂模式
- class SinkFactory
- {
- public:
- template <typename SinkType, typename... Args>
- static LogSink::ptr create(Args &&...args)
- {
- return std::make_shared<SinkType>(std::forward<Args>(args)...);
- }
- };
- }
复制代码 扩展实现
- // 扩展测试: 滚动文件(时间)
- // 1. 以时间段滚动
- // 2. time(nullptr)%gap;
- enum class TimeGap
- {
- GAP_SECOND,
- GAP_MINUTE,
- GAP_HOUR,
- GAP_DAY
- };
- class RollSinkByTime : public Xulog::LogSink
- {
- public:
- // 传入文件名时,构造并打开文件,将操作句柄管理起来
- RollSinkByTime(const std::string &basename, TimeGap gap_type)
- : _basename(basename)
- {
- switch (gap_type)
- {
- case TimeGap::GAP_SECOND:
- _gap_size = 1;
- break;
- case TimeGap::GAP_MINUTE:
- _gap_size = 60;
- break;
- case TimeGap::GAP_HOUR:
- _gap_size = 3600;
- break;
- case TimeGap::GAP_DAY:
- _gap_size = 3600 * 24;
- break;
- }
- _current_gap = _gap_size == 1 ? Xulog::Util::Date::getTime() : (Xulog::Util::Date::getTime() % _gap_size);
- std::string filename = createNewFile();
- Xulog::Util::File::createDirectory(Xulog::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)
- {
- time_t current = Xulog::Util::Date::getTime();
- if (current % _gap_size != _current_gap)
- {
- std::string filename = createNewFile();
- _ofs.close();
- _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 = Xulog::Util::Date::getTime();
- struct tm lt;
- localtime_r(&t, <);
- std::stringstream filename;
- filename << _basename << lt.tm_year + 1900 << lt.tm_mon + 1 << lt.tm_mday << lt.tm_hour << lt.tm_min << lt.tm_sec << ".log";
- return filename.str();
- }
- private:
- std::string _basename;
- std::ofstream _ofs;
- size_t _current_gap; // 当前时间段的个数
- size_t _gap_size; // 间隔大小
- };
复制代码 测试
- Xulog::LogMsg msg(Xulog::LogLevel::value::ERROR, 124, "main.cc", "root", "格式化功能测试");
- Xulog::Formatter fmt1;
- std::string str1 = fmt1.Format(msg);
- // 测试原生日志落地模块
- Xulog::LogSink::ptr std_lsp = Xulog::SinkFactory::create<Xulog::StdoutSink>();
- Xulog::LogSink::ptr file_lsp = Xulog::SinkFactory::create<Xulog::FileSink>("./log/test.log");
- Xulog::LogSink::ptr roll_lsp = Xulog::SinkFactory::create<Xulog::RollSinkBySize>("./log/roll-", 1024 * 1024); // 每个文件1MB
- Xulog::LogSink::ptr time_lsp = Xulog::SinkFactory::create<RollSinkByTime>("./log/roll-", TimeGap::GAP_SECOND); // 每个文件1s
- std_lsp->log(str1.c_str(), str1.size());
- file_lsp->log(str1.c_str(), str1.size());
- size_t size = 0;
- size_t cnt = 0;
- while (size < 1024 * 1024 * 100) // 100 个
- {
- std::string tmp = std::to_string(cnt++);
- tmp += str1;
- roll_lsp->log(tmp.c_str(), tmp.size());
- size += tmp.size();
- }
- time_t t = Xulog::Util::Date::getTime();
- while (Xulog::Util::Date::getTime() < t + 3)
- {
- time_lsp->log(str1.c_str(), str1.size());
- }
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |