项目日志——日志器模块的设计、同步日志器实现、测试

文章目录

    • 日志器模块
      • 设计
      • 同步日志器实现
      • 测试

日志器模块

设计

日志器模块的主要功能就是将前面的所有模块进行整合,向外提供接口,完成不同等级日志的输出

需要管理的成员有

  • 格式化模块的对象
  • 落地模块的对象组
  • 当前默认的输出等级
  • 互斥锁
  • 日志器名称
  • 各个等级的日志输出操作

对于同步日志和异步日志,实现的方式是不同的,因此需要抽象出一个基类,再派生出两个子类

同步日志器实现

/*日志器模块的实现1. 抽象日志器基类2. 派生同步异步日志器子类
*/
#pragma once
// #ifndef _GUN_SOURCE
// #define _GNU_SOURCE
// #endif
#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>namespace Xulog
{class Logger{public:using ptr = std::shared_ptr<Logger>;Logger(const std::string &loggername, LogLevel::value level, Formatter::ptr &formatter, std::vector<LogSink::ptr> sinks): _logger_name(loggername), _limit_level(level), _formatter(formatter), _sinks(sinks.begin(), sinks.end()){}// 构造日志消息,格式化,交给输出接口void debug(const std::string &file, size_t line, const std::string &fmt, ...){// 是否达到输出等级if (LogLevel::value::DEBUG < _limit_level)return;// 将不定参进行格式化,将其转为字符串va_list ap;va_start(ap, fmt);char *res;int ret = vasprintf(&res, fmt.c_str(), ap);if (ret == -1){std::cout << "vasprintf fail\n";return;}va_end(ap);serialize(LogLevel::value::DEBUG, file, line, res);free(res);}void info(const std::string &file, size_t line, const std::string &fmt, ...){// 是否达到输出等级if (LogLevel::value::INFO < _limit_level)return;// 将不定参进行格式化,将其转为字符串va_list ap;va_start(ap, fmt);char *res;int ret = vasprintf(&res, fmt.c_str(), ap);if (ret == -1){std::cout << "vasprintf fail\n";return;}va_end(ap);serialize(LogLevel::value::INFO, file, line, res);free(res);}void warn(const std::string &file, size_t line, const std::string &fmt, ...){// 是否达到输出等级if (LogLevel::value::WARN < _limit_level)return;// 将不定参进行格式化,将其转为字符串va_list ap;va_start(ap, fmt);char *res;int ret = vasprintf(&res, fmt.c_str(), ap);if (ret == -1){std::cout << "vasprintf fail\n";return;}va_end(ap);serialize(LogLevel::value::WARN, file, line, res);free(res);}void error(const std::string &file, size_t line, const std::string &fmt, ...){// 是否达到输出等级if (LogLevel::value::ERROR < _limit_level)return;// 将不定参进行格式化,将其转为字符串va_list ap;va_start(ap, fmt);char *res;int ret = vasprintf(&res, fmt.c_str(), ap);if (ret == -1){std::cout << "vasprintf fail\n";return;}va_end(ap);serialize(LogLevel::value::ERROR, file, line, res);free(res);}void fatal(const std::string &file, size_t line, const std::string &fmt, ...){// 是否达到输出等级if (LogLevel::value::FATAL < _limit_level)return;// 将不定参进行格式化,将其转为字符串va_list ap;va_start(ap, fmt);char *res;int ret = vasprintf(&res, fmt.c_str(), ap);if (ret == -1){std::cout << "vasprintf fail\n";return;}va_end(ap);serialize(LogLevel::value::FATAL, file, line, res);free(res);}protected:// 抽象接口完成实际的落地输出,同步异步的落地方式不同virtual void log(const char *data, size_t len) = 0;void serialize(LogLevel::value level, const std::string &file, size_t line, char *str){// 日志内容格式化LogMsg msg(level, line, file, _logger_name, str);std::stringstream ss;_formatter->Format(ss, msg);// 日志落地log(ss.str().c_str(), ss.str().size());}std::mutex _mutex;std::string _logger_name;std::atomic<LogLevel::value> _limit_level;Formatter::ptr _formatter;std::vector<LogSink::ptr> _sinks;};// 同步日志器class SyncLogger : public Logger{public:SyncLogger(const std::string &loggername, LogLevel::value level, Formatter::ptr &formatter, std::vector<LogSink::ptr> sinks): Logger(loggername, level, formatter, sinks){}protected:// 直接通过落地模块句柄进行日志输出void log(const char *data, size_t len) override{std::unique_lock<std::mutex> lock(_mutex);if (_sinks.empty())return;elsefor (auto &sink : _sinks){sink->log(data, len);}}};// TODO 异步日志器
}

测试

#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "logger.hpp"// 扩展测试: 滚动文件(时间)
// 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, &lt);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;    // 间隔大小
};int main()
{// 测试同步日志器std::string logger_name = "synclog";Xulog::LogLevel::value limit = Xulog::LogLevel::value::WARN;Xulog::Formatter::ptr fmt(new Xulog::Formatter());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);  // 每个文件1MBXulog::LogSink::ptr time_lsp = Xulog::SinkFactory::create<RollSinkByTime>("./log/roll-", TimeGap::GAP_SECOND); // 每个文件1sstd::vector<Xulog::LogSink::ptr> sinks = {std_lsp, file_lsp, roll_lsp, time_lsp};Xulog::Logger::ptr logger(new Xulog::SyncLogger(logger_name, limit, fmt, sinks));std::string str = "测试同步日志器-";logger->debug(__FILE__, __LINE__, "%s", str.c_str());logger->error(__FILE__, __LINE__, "%s", str.c_str());logger->fatal(__FILE__, __LINE__, "%s", str.c_str());logger->info(__FILE__, __LINE__, "%s", str.c_str());logger->warn(__FILE__, __LINE__, "%s", str.c_str());size_t size = 0;int cnt = 1;while (size < 1024 * 1024 * 10) // 10 个{logger->fatal(__FILE__, __LINE__, "%s-%d", str.c_str(), cnt++);size += 20;}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/53526.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Pygame中Sprite类实现多帧动画3-3

4 使用自定义类MySprite 使用自定义类MySprite实现多帧动画的步骤是首先创建MySprite类的实例&#xff0c;之后使用相关函数对该实例进行操作。 4.1 创建MySprite类的实例 创建MySprite类的实例的代码如图12所示。 图12 创建MySprite类的实例的代码 其中&#xff0c;变量dr…

TortoiseGit无法安装解决方案

Win11安装TortoiseGit报错&#xff0c;错误码&#xff1a;2503&#xff0c;如下图&#xff1a; 开始-右键-Windows PowerShell&#xff08;管理员&#xff09;/终端 (管理员) 输入 msiexec /package 安装程序所在绝对路径&#xff0c; 例如 : msiexec /package D:\我的资料…

利用鸢尾花数据集介绍PCA算法

PCA&#xff1a; 主成分分析&#xff08;PCA, Principal Component Analysis&#xff09;是一种常用的数据降维技术&#xff0c;它可以将高维数据转换为较低维数据&#xff0c;同时尽可能保留数据的主要信息。PCA通过寻找数据的主要方向&#xff0c;即方差最大的方向&#xff0…

小小GCD、LCM拿下拿下

目录 最大公约数&#xff08;GCD&#xff09; 最大公约数&#xff08;GCD&#xff09;求解&#xff1a; 一、辗转相除法 二、三目运算符 三、位运算 最大公约数&#xff08;GCD&#xff09;模板&#xff1a; 最大公约数&#xff08;GCD&#xff09;例题&#xff1a; 最…

stm32之硬件SPI读写W25Q64存储器应用案例

系列文章目录 1. stm32之SPI通信协议 2. stm32之软件SPI读写W25Q64存储器应用案例 3. stm32之SPI通信外设 文章目录 系列文章目录前言一、电路接线图二、应用案例代码三、应用案例代码分析3.1 基本思路3.2 相关库函数介绍3.3 MySPI模块3.3.1 模块初始化3.3.2 SPI基本时序单元模…

丰巢“闯关”港交所上市

社区中随处可见的智能快递柜&#xff0c;即将捧出一个IPO。 近日&#xff0c;丰巢控股有限公司&#xff08;下称“丰巢控股”或“丰巢”&#xff09;正式向港交所递交了招股书&#xff0c;华泰国际担任其独家保荐人。这将是继顺丰控股、顺丰房托、嘉里物流、顺丰同城之后&…

微服务CI/CD实践(六)Jenkins Docker 自动化构建部署Java微服务

微服务CI/CD实践系列&#xff1a; 微服务CI/CD实践&#xff08;一&#xff09;环境准备及虚拟机创建 微服务CI/CD实践&#xff08;二&#xff09;服务器先决准备 微服务CI/CD实践&#xff08;三&#xff09;gitlab部署及nexus3部署 微服务CI/CD实践&#xff08;四&#xff09…

未来餐饮革命:加入我们的智能餐厅代理、自主开拓市场计划!

系统开发集成商&#xff1a;如果您正在开发智慧餐厅系统&#xff0c;忙于寻找各种消费终端接入、那么我们将可以为您提供整套智慧餐厅系统解决方案&#xff0c;从前厅消费到后厨的明厨亮灶的解决方案。 集团公司&#xff1a;想集团化控制子公司食堂运营&#xff0c;又想以最低…

【LeetCode每日一题】——LCR 168.丑数

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目注意】六【题目示例】七【题目提示】八【解题思路】九【时间频度】十【代码实现】十一【提交结果】 一【题目类别】 优先队列 二【题目难度】 中等 三【题目编号】 LCR 168.丑数 四【题目描述…

uts+uniapp踩坑记录(vue3项目

杂记&#xff1a; web-view方面 内嵌html使用web-view时&#xff0c;直接用 uni.postMessage({data: {action: message // 你要传的信息}}); 示例上写的是用 document.addEventListener(UniAppJSBridgeReady, function() { uni.postMessage({ data: { action: postMe…

nohup与

在 Unix/Linux 系统中&#xff0c;nohup 命令和 & 符号都是用来在后台运行命令的工具&#xff0c;但它们有一些区别。 nohup nohup 命令允许你在终端关闭之后继续运行进程。通常情况下&#xff0c;当你退出终端会话时&#xff0c;正在运行的进程会被挂断&#xff08;SIGH…

【大数据】Hadoop里的“MySQL”——Hive,干货满满

【大数据】Hadoop里的“MySQL”——Hive&#xff0c;干货满满 文章脉络 Hive架构 HQL 表类型 创建表语法 分区 数据导入导出 函数 内置函数 UDF Java Python 在阅读本文前&#xff0c;请确保已经对Hadoop的三大组件&#xff08;HDFS、MapReduce、YARN&#xff09;有…

分布式协调服务--ZooKeeper

文章目录 ZooKeeperzk的由来zk解决了什么问题 ZK工作原理ZK数据模型zk功能1.命名服务2.状态同步3.配置中心4.集群管理 zk部署单机启动zk验证zk zk集群集群角色选举过程1.节点角色状态2.选举ID3.具体过程4.心跳机制5.ZAB协议 ZooKeeper 选举示例1.第一轮投票&#xff1a;2.节点收…

以下是分析执行计划中索引使用情况的方法:

一、查看是否使用索引 执行计划通常会明确显示是否使用了索引。如果没有使用索引&#xff0c;可能会看到类似“全表扫描”的描述。例如&#xff1a; “TABLE ACCESS FULL (table_name)”表示对表进行了全表扫描&#xff0c;没有使用索引。 如果使用了索引&#xff0c;会有…

《React Native 应用开发最佳实践》

⭐️React Native 应用开发最佳实践⭐️ 近年来&#xff0c;React Native 应用开发因其能够使用 JavaScript 构建原生移动应用的能力而大受欢迎。它提供了跨平台兼容性、更快的开发时间以及更易于维护的特性&#xff0c;成为了许多开发者的首选。然而&#xff0c;要确保 React…

Unity TextMeshPro 设置竖排

默认竖排是这样的 但是我们要的竖排效果并不是这样我们要是竖排连续的根据文本限制来进行换行 第一步我们先设置文本的旋转Z轴为90如下图 然后我们给文本加一个Tag <rotate270> 如下图 但是这个效果还是不是我们想要的效果我们可以使用TexeMeshPro提供的一个选项EnableR…

Python画笔案例-041 绘制正方形阶梯

1、绘制正方形阶梯 通过 python 的turtle 库绘制正方形阶梯&#xff0c;如下图&#xff1a; 2、实现代码 绘制正方形阶梯&#xff0c;以下为实现代码&#xff1a; """正方形阶梯.py """ import turtledef draw_square(length):for _ in range(6…

Flutter函数

在Dart中&#xff0c;函数为 一等公民&#xff0c;可以作为参数对象传递&#xff0c;也可以作为返回值返回。 函数定义 // 返回值 (可以不写返回值&#xff0c;但建议写)、函数名、参数列表 showMessage(String message) {//函数体print(message); }void showMessage(String m…

以太网--TCP/IP协议(一)

概述 以太网是局域网的一种&#xff0c;其他的比如还有令牌环、FDDI。和局域网对应的就是广域网&#xff0c;如Internet&#xff0c;城域网等。 从网络层次看&#xff0c;局域网协议主要偏重于低层&#xff08;业内一般把物理层、数据链路层归为低层&#xff09;。以太网协议…

【软考】知识产权与标准化

【软考】知识产权与标准化 一.保护范围与对象 1.保护范围与对象 法律法规名称保护对象及范围注意事项著作版权法著作权&#xff0c;文学&#xff0c;绘画&#xff0c;影视等作品1、不需要申请&#xff0c;作品完成即开始保护。2、绘画或摄影作品原件出售(赠予)著作权还归原作…