阅读量:0
一条日志可以输出到显示屏,也可以输出到指定文件,更灵活一点可以根据文件大小和日志时间自动设置输出目的,将这种想法落实于代码中,就需要定义各个类表示不同落地方向,再有一个抽象落地基类进行统一调用方法
日志落地类
抽象基类
class LogLand //使用land命名空间进行限定 { public: virtual ~LogLand() {} virtual void landing(const char *data, size_t len) = 0; };
landing方法是一个需要被派生类重写的函数,每一个派生类都通过landing方法进行日志消息的输出
标准输出落地类
class StdoutLogLand : public LogLand { public: virtual void landing(const char *data, size_t len) override { std::cout.write(data, len); //避免使用<<进行输出,因为<<遇到\0会终止,write更加安全 } };
指定文件落地类
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()); // 检查是否写入发生错误 } };
用户传入的文件路径可能不存在,需要在构造函数中进行判断,如果不存在则创建
滚动文件落地类(按文件大小、按日志时间)
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(); };
滚动文件方法实现:
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(×tamp); 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(×tamp); 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(); }