当前位置: 首页 > news >正文

项目日志——日志落地模块的设计、实现、测试

文章目录

    • 日志落地模块
      • 设计
      • 实现
      • 扩展实现
      • 测试

日志落地模块

设计

功能是,将格式化完成后的日志消息字符串,输出到指定的位置

支持将日志落地到不同的位置

  • 标准输出
  • 指定文件
  • 滚动文件

滚动文件按照时间或者大小进行滚动切换,可以按照天数对日志信息进行管理

我们这里实现按照大小进行滚动文件的设计

同时也是支持落地方向的扩展,可以写入到云服务器或者数据库中

用户可以自己编写一个新的日志落地模块进行实现,因此需要设计一个简单工厂模式进行管理

实现思想是这样的

  1. 抽象出落地模块的基类
  2. 派生出不同落地方向的子类
  3. 使用工厂模式进行创建和表示的分离,便于对象的扩展

实现

/*日志落地模块的实现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, &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 << "-" << _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, &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;    // 间隔大小
};

测试

    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); // 每个文件1MBXulog::LogSink::ptr time_lsp = Xulog::SinkFactory::create<RollSinkByTime>("./log/roll-", TimeGap::GAP_SECOND); // 每个文件1sstd_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());}

相关文章:

项目日志——日志落地模块的设计、实现、测试

文章目录 日志落地模块设计实现扩展实现测试 日志落地模块 设计 功能是&#xff0c;将格式化完成后的日志消息字符串&#xff0c;输出到指定的位置 支持将日志落地到不同的位置 标准输出指定文件滚动文件 滚动文件按照时间或者大小进行滚动切换&#xff0c;可以按照天数对…...

CTK框架(七):事件监听

目录 1.概述 2.监听接口 3.具体实现 1.概述 CTK&#xff08;Common Toolkit&#xff09;框架中的事件监听机制是一个重要的功能&#xff0c;它允许开发者在特定事件发生时接收到通知并执行相应的操作。CTK框架主要支持三种类型的事件监听&#xff1a;框架事件、插件事件和服…...

一区霜冰算法+双向深度学习模型+注意力机制!RIME-BiTCN-BiGRU-Attention

一区霜冰算法双向深度学习模型注意力机制&#xff01;RIME-BiTCN-BiGRU-Attention 目录 一区霜冰算法双向深度学习模型注意力机制&#xff01;RIME-BiTCN-BiGRU-Attention效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现RIME-BiTCN-BiGRU-Attention霜冰算法…...

C语言 | Leetcode C语言题解之第396题旋转函数

题目&#xff1a; 题解&#xff1a; #define MAX(a, b) ((a) > (b) ? (a) : (b))int maxRotateFunction(int* nums, int numsSize){int f 0, numSum 0;for (int i 0; i < numsSize; i) {f i * nums[i];numSum nums[i];}int res f;for (int i numsSize - 1; i &g…...

利士策分享,克服生活中的困难:走好勇攀高峰的每一步

利士策分享&#xff0c;克服生活中的困难&#xff1a;走好勇攀高峰的每一步 在这个纷繁复杂的世界里&#xff0c;每个人都是自己生命旅程中的行者&#xff0c;而生活&#xff0c;则是一条既铺满鲜花又布满荆棘的道路。 我们或许会在某个清晨醒来&#xff0c;发现自己正站在一座…...

PurchasereturnController

目录 1、 PurchasereturnController 1.1、 反审核退货单 1.1.1、 //配件ID 1.1.2、 //配件编码 1.1.3、 //修改后仓库 1.1.4、 //修改配件信息表库存量 PurchasereturnController using QXQPS.Models; using QXQPS.Vo; using System; using System.Collection…...

mysql 学习笔记 八

总结 自动提交 查看自动提交状态&#xff1a;SELECT AUTOCOMMIT &#xff1b; 设置自动提交状态&#xff1a;SET AUTOCOMMIT 0 。 手动提交 AUTOCOMMIT 0 时&#xff0c;使用 COMMIT 命令提交事务。 事务回滚 AUTOCOMMIT 0 时&#xff0c;使用 ROLLBACK 命令回滚事务。 …...

反序列化漏洞练习2

拿到题目&#xff0c;发现目标是获得flag.php的内容,且sis中admin和passwd等于sis2407时会输出fag的内容 根据源码编写序列化代码 <?php error_reporting(0); class sis{public $admin;public $passwd;public function __construct(){$this->admin "sis2407"…...

基于SpringBoot的社区医院管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于JavaSpringBootVueMySQL的社团管理系统【附源码文档】、…...

YOLOv8安装配置教程(Windows版)

YOLOv8安装配置教程&#xff08;Windows版&#xff09; 简介&#xff1a;最近由于选择了人工智能方向的专业选修课&#xff0c;课程需要安装配置YOLOv8&#xff0c;经过查阅各种资料后才发现&#xff0c;许多教程都比较老旧&#xff0c;并且文件位置也发生了变化&#xff0c;所…...

Linux的历史,版本,Linux的环境安装、简单学习4个基本的Linux指令等的介绍

文章目录 前言一、Linux的历史二、版本三、Linux的环境安装1. 腾讯云服务器的申请2. xshell的安装与使用 四、 简单学习4个基本的Linux指令1. ls2. pwd3. mkdir4. cd 总结 前言 Linux的历史&#xff0c;版本&#xff0c;Linux的环境安装、简单学习4个基本的Linux指令等的介绍 …...

【论文阅读】01-Survey on Temporal Knowledge Graph

原文名称&#xff1a;Survey on Temporal Knowledge Graph 1 Introduction 目前有两种方法:基于距离模型的嵌入变换方法和基于语义匹配模型的双线性模型。它们的思想都是将包含实体和关系的知识图谱嵌入到连续的低纬度实向量空间中 时间知识图的推理有两种&#xff0c;第一种是…...

【AIGC】InstructPixPix:基于文本引导的图像编辑技术

github:diffusers/examples/instruct_pix2pix/train_instruct_pix2pix_sdxl.py at main huggingface/diffusers GitHub 论文&#xff1a;https://arxiv.org/pdf/2211.09800 摘要 我们提出了一种从人类指令编辑图像的方法&#xff1a;给定一个输入图像和告诉模型做什么的书面…...

无人机动力系统设计之桨叶推力计算

无人机动力系统设计之桨叶推力计算 1. 源由2. 关键参数2.1 特性参数2.1.1 材质&#xff08;Material&#xff09;2.1.2 叶片数量&#xff08;Number of Blades&#xff09;2.1.3 重量&#xff08;Weight&#xff09;2.1.4 噪音水平&#xff08;Noise Level&#xff09; 2.2 安装…...

LabVIEW重构其他语言开发的旧系统

在面对一个运行已久、代码不清晰的项目时&#xff0c;如果该项目涉及复杂的通讯协议&#xff08;如串口和488通讯&#xff09;&#xff0c;重新开发并优化成LabVIEW版本可以极大提升系统的易用性和维护性。为了确保通讯协议的顺利解析和移植&#xff0c;借助专业工具分析现有通…...

[晕事]今天做了件晕事43 python-byte串长度与转义字符

今天办了一件晕事&#xff0c;导致测试结果与预期不一致。 过程是&#xff0c;组装byte串的时候&#xff0c;整个字符串里有转义字符\x0d。 from scapy.all import IPv6, UDP pkt IPv6(src"2002:db8:a0b:12f0::157", dst"2002:db8:a0b:12f0::13")/UDP(sp…...

初识redis(String,Hash,List,Set,SortedSet)

认识NoSql sql关系型数据库 nosql非关系型数据库 nosql具有非结构化&#xff0c;Key/Value&#xff0c;Document&#xff0c;Draph 无关联的&#xff0c;非sql&#xff0c;BASE&#xff08;原子性&#xff0c;持久性&#xff0c;一致性&#xff0c;隔离性&#xff09; 认识r…...

Ton与ETH的一些独特的区别

文章目录 前言一、智能合约需要收取租金。二、从数据到大数据的转变三、智能合约不能运行其他合约的getter方法四、合约不是无法改变的五、Ton取消了无限制的数据结构六、钱包和地址具有独立性 前言 TON区块链是一个现代化的区块链&#xff0c;它为智能合约开发带来了一些全新…...

C++ | Leetcode C++题解之第396题旋转图像

题目&#xff1a; 题解&#xff1a; class Solution { public:int maxRotateFunction(vector<int>& nums) {int f 0, n nums.size();int numSum accumulate(nums.begin(), nums.end(), 0);for (int i 0; i < n; i) {f i * nums[i];}int res f;for (int i …...

前向渲染路径

1、前向渲染路径处理光照的方式 前向渲染路径中会将光源分为以下3种处理方式&#xff1a; 逐像素处理&#xff08;需要高等质量处理的光&#xff09;逐顶点处理&#xff08;需要中等质量处理的光&#xff09;球谐函数&#xff08;SH&#xff09;处理&#xff08;需要低等质量…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...