日志系统——落地模块

一条日志可以输出到显示屏,也可以输出到指定文件,更灵活一点可以根据文件大小和日志时间自动设置输出目的,将这种想法落实于代码中,就需要定义各个类表示不同落地方向,再有一个抽象落地基类进行统一调用方法

日志落地类

抽象基类

cpp 复制代码
  class LogLand   //使用land命名空间进行限定
   {
   public:
       virtual ~LogLand() {}
       virtual void landing(const char *data, size_t len) = 0;
   };

landing方法是一个需要被派生类重写的函数,每一个派生类都通过landing方法进行日志消息的输出
标准输出落地类

cpp 复制代码
   class StdoutLogLand : public LogLand
   {
   public:
       virtual void landing(const char *data, size_t len) override
       {
       		std::cout.write(data, len); //避免使用<<进行输出,因为<<遇到\0会终止,write更加安全
       }
   };

指定文件落地类

cpp 复制代码
class FileLogLand : public LogLand
{
private:
   std::ofstream _file;
   std::string _filename;
public:
   FileLogLand(const char *file): _filename(file)
	{
    util::File::createDirectory(util::File::path(file)); // 创建文件所在目录
    _file.open(_filename, std::ios::app | std::ios::binary);
    assert(_file.is_open());
	}
   virtual void landing(const char *data, size_t len) override
   {
	_file.write(data, len);
	assert(_file.good()); // 检查是否写入发生错误
   }
};

用户传入的文件路径可能不存在,需要在构造函数中进行判断,如果不存在则创建
滚动文件落地类(按文件大小、按日志时间)

cpp 复制代码
   class ScrollBySizeLogLand : public LogLand
   {
   private:
       size_t _name_cnt = 0; //防止1s之内创建多文件 ,可能在极端情况下1s之内就已经写满了一个文件,再次创建一个文件会导致文件名冲突
       std::ofstream _file;
       std::string _basename; //每一次生成的文件名格式为basename+时间信息(最小单位为秒)
       size_t _max_size; //文件大小上限
       size_t _cur_size = 0; //当前文件大小
   public:
       ScrollBySizeLogLand(const char *file, size_t maxsize = 1024 * 1024 * 1024); // 默认最大为1G
       virtual void landing(const char *data, size_t len) override;
   private:
       std::string setFilename();
   };

   class ScrollByTimeLogLand : public LogLand
   {
   private:
       time_t _time_gap; //表示每过一个time_gap秒数就切换一个文件
       time_t _cur_gap;
       std::ofstream _file;
       std::string _basename;
   public:
       enum struct TimeGap
       {
           SECOND = 1,
           MINUTE = 60,
           HOUR = 3600,
           DAT = 3600 * 24
       };
       ScrollByTimeLogLand(const char *file, TimeGap gap);
       virtual void landing(const char *data, size_t len) override;
   private:
       std::string setFilename();
   };

滚动文件方法实现:

cpp 复制代码
land::ScrollBySizeLogLand::ScrollBySizeLogLand(const char *file, size_t maxsize)
    : _basename(file), _max_size(maxsize)
{
    util::File::createDirectory(util::File::path(file));
    // 创建文件所在目录+创建文件
    _file.open(_basename + setFilename(), std::ios::binary | std::ios::app);
    assert(_file.is_open());
}
std::string land::ScrollBySizeLogLand::setFilename()
{
    std::stringstream ss;
    time_t timestamp = util::Date::getTime();
    struct tm *t = localtime(&timestamp);
    ss << t->tm_year + 1900;
    ss << t->tm_mon + 1;
    ss << t->tm_mday;
    ss << t->tm_hour;
    ss << t->tm_min;
    ss << t->tm_sec;
    ss << "-" + std::to_string(_name_cnt++) + ".log";
    return ss.str();
}
void land::ScrollBySizeLogLand::landing(const char *data, size_t len)
{
    if (_cur_size >= _max_size)
    {
        _file.close(); //! 关闭原来的文件
        _cur_size = 0; //! 归置_cur_size
        _file.open(_basename + setFilename(), std::ios::app | std::ios::binary);
        assert(_file.is_open());
    }
    _file.write(data, len);
    assert(_file.good());
    _cur_size += len;
}

land::ScrollByTimeLogLand::ScrollByTimeLogLand(const char *file, TimeGap gap)
    : _basename(file), _time_gap((time_t)gap)
{
    _cur_gap = util::Date::getTime();
    util::File::createDirectory(util::File::path(file));
    _file.open(_basename + setFilename(), std::ios::binary | std::ios::app);
    assert(_file.is_open());
}
void land::ScrollByTimeLogLand::landing(const char *data, size_t len)
{
    if (_cur_gap + _time_gap == util::Date::getTime())
    {
        _cur_gap += _time_gap;
        _file.close();
        _file.open(_basename + setFilename(), std::ios::binary | std::ios::app);
        assert(_file.is_open());
    }
    _file.write(data, len);
    assert(_file.good());
}

std::string land::ScrollByTimeLogLand::setFilename()
{
    std::stringstream ss;
    time_t timestamp = util::Date::getTime();
    struct tm *t = localtime(&timestamp);
    ss << t->tm_year + 1900;
    ss << t->tm_mon + 1;
    ss << t->tm_mday;
    ss << t->tm_hour;
    ss << t->tm_min;
    ss << t->tm_sec;
    ss << "-.log";
    return ss.str();
}
相关推荐
努力奋斗的小杨13 分钟前
学习MySQL的第十二天
数据库·笔记·学习·mysql·navicat
枫叶20001 小时前
OceanBase数据库-学习笔记1-概论
数据库·笔记·学习·oceanbase
Ethon_王1 小时前
走进Qt--工程文件解析与构建系统
c++·qt
一点.点1 小时前
李沐动手深度学习(pycharm中运行笔记)——04.数据预处理
pytorch·笔记·python·深度学习·pycharm·动手深度学习
一点.点1 小时前
李沐动手深度学习(pycharm中运行笔记)——07.自动求导
pytorch·笔记·python·深度学习·pycharm·动手深度学习
tcoding1 小时前
《MySQL 技术内幕-innoDB 存储引擎》笔记
数据库·笔记·mysql
RaLi和夕1 小时前
单片机学习笔记9.数码管
汇编·笔记·单片机·嵌入式硬件·学习
见青..2 小时前
【学习笔记】文件包含漏洞--本地远程包含、伪协议、加密编码
前端·笔记·学习·web安全·文件包含
flying robot2 小时前
小结:BFD
笔记
工藤新一¹2 小时前
C++/SDL进阶游戏开发 —— 双人塔防游戏(代号:村庄保卫战 13)
c++·游戏·游戏引擎·毕业设计·sdl·c++游戏开发·渲染库