【7】基于多设计模式下的同步&异步日志系统-代码设计

8.5 日志落地(LogSink)类设计(简单工厂模式)

1.⽇志落地类主要负责落地⽇志消息到⽬的地。
它主要包括以下内容:
• Formatter⽇志格式化器:主要是负责格式化⽇志消息,
• mutex互斥锁:保证多线程⽇志落地过程中的线程安全,避免出现交叉输出的情况。
这个类⽀持可扩展,其成员函数log设置为纯虚函数,当我们需要增加⼀个log输出⽬标, 可以增加⼀个类继承⾃该类并重写log⽅法实现具体的落地⽇志逻辑。
2.⽬前实现了三个不同⽅向上的⽇志落地:
• 标准输出:StdoutSink
• 固定⽂件:FileSink
• 滚动⽂件:RollSink
2.1滚动⽇志⽂件输出的必要性:

▪ 由于机器磁盘空间有限, 我们不可能⼀直⽆限地向⼀个⽂件中增加数据
▪ 如果⼀个⽇志⽂件体积太⼤,⼀⽅⾯是不好打开,另⼀⽅⾯是即时打开了由于包含数据巨⼤,也不利于查找我们需要的信息
▪ 所以实际开发中会对单个⽇志⽂件的⼤⼩也会做⼀些控制,即当⼤⼩超过某个⼤⼩时(如1GB),我们就重新创建⼀个新的⽇志⽂件来滚动写⽇志。 对于那些过期的⽇志, ⼤部分企业内部都有专⻔的运维⼈员去定时清理过期的⽇志,或者设置系统定时任务,定时清理过期⽇志。

2.2⽇志⽂件的滚动思想:

⽇志⽂件滚动的条件有两个:⽂件⼤⼩ 和 时间。我们可以选择:
▪ ⽇志⽂件在⼤于 1GB 的时候会更换新的⽂件
▪ 每天定点滚动⼀个⽇志⽂件

本项⽬基于⽂件⼤⼩的判断滚动⽣成新的⽂件

#ifndef __M_SINK_H__
#define __M_SINK_H__
#include "util.hpp"
#include "message.hpp"
#include "formatter.hpp"
#include <memory>
#include <mutex>
namespace bitlog{
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:
 using ptr = std::shared_ptr<StdoutSink>;
 StdoutSink() = default;
 void log(const char *data, size_t len) {
 std::cout.write(data, len);
 }
};
class FileSink : public LogSink {
 public:
 using ptr = std::shared_ptr<FileSink>;
 FileSink(const std::string &filename):_filename(filename) {
 util::file::create_directory(util::file::path(filename));
 _ofs.open(_filename, std::ios::binary | std::ios::app);
 assert(_ofs.is_open());
 }
 const std::string &file() {return _filename; }
 void log(const char *data, size_t len) {
 _ofs.write((const char*)data, len);
 if (_ofs.good() == false) {
 std::cout << "⽇志输出⽂件失败!\n";
 }
 }
 private:
 std::string _filename;
 std::ofstream _ofs;
};
class RollSink : public LogSink {
 public:
 using ptr = std::shared_ptr<RollSink>;
 RollSink(const std::string &basename, size_t max_fsize):
 _basename(basename), _max_fsize(max_fsize), _cur_fsize(0){
 util::file::create_directory(util::file::path(basename));
 }
 void log(const char *data, size_t len) {
 initLogFile();
 _ofs.write(data, len);
 if (_ofs.good() == false) {
 std::cout << "⽇志输出⽂件失败!\n";
 }
 _cur_fsize += len;
 }
 private:
 void initLogFile() {
 if (_ofs.is_open() == false || _cur_fsize >= _max_fsize) {
 _ofs.close();
 std::string name = createFilename();
 _ofs.open(name, std::ios::binary | std::ios::app);
 assert(_ofs.is_open());
 _cur_fsize = 0;
 return;
 }
 return;
 } 
 std::string createFilename() {
 time_t t = time(NULL);
 struct tm lt;
 localtime_r(&t, &lt);
 std::stringstream ss;
 ss << _basename;
 ss << lt.tm_year + 1900;
 ss << lt.tm_mon + 1;
 ss << lt.tm_mday;
 ss << lt.tm_hour;
 ss << lt.tm_min;
 ss << lt.tm_sec;
 ss << ".log";
 return ss.str();
 }
 private:
 std::string _basename;
 std::ofstream _ofs;
 size_t _max_fsize;
 size_t _cur_fsize;
};
class SinkFactory {
 public:
 template<typename SinkType, typename ...Args>
 static LogSink::ptr create(Args &&...args) {
 return std::make_shared<SinkType>(std::forward<Args>(args)...);
 }
};
}
#endif

最近更新

  1. TCP协议是安全的吗?

    2023-12-16 04:14:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2023-12-16 04:14:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2023-12-16 04:14:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2023-12-16 04:14:02       18 阅读

热门阅读

  1. 超全面网络安全学习知识——(黑客)自学

    2023-12-16 04:14:02       41 阅读
  2. Mybatis配置-类型别名(typeAliases)

    2023-12-16 04:14:02       36 阅读
  3. log4j2 xml 配置文件 屏蔽 第三方 依赖包 的日志

    2023-12-16 04:14:02       38 阅读
  4. 1050 螺旋矩阵

    2023-12-16 04:14:02       33 阅读