[C++]——同步异步日志系统(3)

同步异步日志系统

  • 一、日志系统框架设计
    • 1.1模块划分
      • 1.1.1 日志等级模块
      • 1.1.2 日志消息模块
      • 1.1.3 日志消息格式化模块
      • 1.1.4 日志落地模块(日志落地的方向是工厂模式)
      • 1.1.5 日志器模块(日志器的生成是建造者模式)
      • 1.1.6 异步线程模块(日志的输出是用宏完成的代理模式)
      • 1.1.7 单例的日志器管理模块(单例模式实现对日志器的管理)
    • 1.2 模块关系图
  • 二、代码设计
    • 2.1 实用类设计

日志系统:
作用:将一条消息,进行格式化为指定格式的字符串后,写入到指定位置

  1. 日志要写入指定位置(标准输出,指定文件, 滚动文件等等是可扩展得)
    日志系统需要支持将日志消息落地到不同的位置—多落地方向
  2. 日志写入指定位置,支持不同的写入方式(同步,异步)
    同步:业务线程自己负责日志的写入(流程简单,但是有可能会因为阻塞导致效率降低) 异步:业务线程将日志放入缓冲区内存,让其他异步线程负责将日志写入指定位置
  3. 日志输出以日志器为单位,支持多日志器(不同的项目组有不同的输出策略)

一、日志系统框架设计

本项⽬实现的是⼀个多⽇志器⽇志系统,主要实现的功能是让程序员能够轻松的将程序运⾏⽇志信息落地到指定的位置,且⽀持同步异步两种⽅式的⽇志落地⽅式。

1.1模块划分

1.1.1 日志等级模块

枚举出日志分为多少个等级—对不同的日志有不同等级标记–以便于控制输出

  • OFF:关闭
  • DEBUG:调试,调试时的关键信息输出。
  • INFO:提示,普通的提⽰型⽇志信息。
  • WARN:警告,不影响运⾏,但是需要注意⼀下的⽇志。
  • ERROR:错误,程序运⾏出现错误的⽇志。
  • FATAL:致命,⼀般是代码异常导致程序⽆法继续推进运⾏的⽇志。

1.1.2 日志消息模块

封装一条日志所需的各种要素(时间,线程ID,文件名,行号,日志等级,消息主体…)

  • 时间:描述本条⽇志的输出时间。
  • 线程ID:描述本条⽇志是哪个线程输出的。
  • ⽇志等级:描述本条⽇志的等级。
  • ⽇志数据:本条⽇志的有效载荷数据。
  • ⽇志⽂件名:描述本条⽇志在哪个源码⽂件中输出的。
  • ⽇志⾏号:描述本条⽇志在源码⽂件的哪⼀⾏输出的。

1.1.3 日志消息格式化模块

按照指定的格式,对于日志消息中关键要素进行组织,最终得到一个指定格式的字符串

系统默认的输出格式: [%d{%H:%M:%S}]%T[%t]%T[%p]%T[%c]%T%f:%l%T%m%n
[12:38:45] [12345678] [FATAL] [root] main.c:178 套接字创建失败…\n

  • %d{%H:%M:%S}:表⽰⽇期时间,花括号中的内容表示日期时间的格式。
  • %T:表⽰制表符缩进。
  • %t:表⽰线程ID。%p:表⽰⽇志级别。
  • %c:表⽰⽇志器名称,不同的开发组可以创建⾃⼰的⽇志器进⾏⽇志输出,⼩组之间互不影响。
  • %f:表⽰⽇志输出时的源代码⽂件名。
  • %l:表⽰⽇志输出时的源代码⾏号。
  • %m:表⽰给与的⽇志有效载荷数据 。
  • %n:表⽰换行。
  • 设计思想:设计不同的⼦类,不同的⼦类从⽇志消息中取出不同的数据进⾏处理。

1.1.4 日志落地模块(日志落地的方向是工厂模式)

决定了⽇志的落地⽅向,以什么方式输出。

  • 标准输出:表⽰将⽇志进⾏标准输出的打印。
  • ⽇志⽂件输出:表⽰将⽇志写⼊指定的⽂件末尾。
  • 滚动⽂件输出:当前以⽂件⼤⼩进⾏控制,当⼀个⽇志⽂件⼤⼩达到指定⼤⼩,则切换下⼀个⽂件进⾏输出 。
  • 后期,也可以扩展远程⽇志输出,创建客⼾端,将⽇志消息发送给远程的⽇志分析服务器。
  • 设计思想:设计不同的⼦类,不同的⼦类控制不同的⽇志落地⽅向。

1.1.5 日志器模块(日志器的生成是建造者模式)

对上边几个模块的整合,⽤⼾通过⽇志器进⾏⽇志的输出,有效降低⽤⼾的使⽤ 难度。
⽇志消息落地模块对象,⽇志消息格式化模块对象,⽇志输出等级

  • 同步日志器模块—完成日志的同步输出功能。
  • 异步日志器模块—完成日志的异步输出功能(将日志消息发送到日志缓冲器内存)

1.1.6 异步线程模块(日志的输出是用宏完成的代理模式)

负责异步日志的实际落地输出功能

  • 实现对⽇志的异步输出功能,⽤⼾只需要将输出⽇志任务放⼊任务池,异步线程负责⽇志的落地输出功能,提供了更加⾼效的⾮阻塞的⽇志输出。

1.1.7 单例的日志器管理模块(单例模式实现对日志器的管理)

为了方便管理,可以在程序的任意位置使用日志器,我设置一个单例对象。对日志进行全局的管理,以便于能够在项目的任何位置获取指定的日志器进行日志输出。

  • 为了降低项⽬开发的⽇志耦合,不同的项⽬组可以有⾃⼰的⽇志器来控制输出格式以及落地⽅向,因此本项⽬是⼀个多⽇志器的⽇志系统。
  • 管理模块就是对创建的所有⽇志器进⾏统⼀管理。并提供⼀个默认⽇志器,提供标准输出的⽇志输出。

1.2 模块关系图

在这里插入图片描述
通过模块关系图,能够简单快速的了解模块之间的关系。

二、代码设计

2.1 实用类设计

提前完成一些功能和接口。

  1. 首先需要把架子搭起来,功能先声明好。
//  通⽤功能类,与业务⽆关的功能实现
//  1. 获取系统时间
//  2. 判断文件是否存在
//  3. 获取⽂件所在⽬录的路径
//  4. 创建⽬录
//静态接口可以直接使用,不需要实例化对象
#include <iostream>
namespace logsLearn {namespace util{//日期类class Data{public://获取系统时间static time_t now();};//文件类class File{public://判断文件是否存在static bool exists(const std::string &pathname);//获取⽂件所在⽬录的路径static std::string path(const std::string &pathname);//创建⽬录static void createDirectory(const std::string &pathname);};} 
}
  1. 其次在实现各个功能。
// 条件编译,防止头文件重复包含
#ifndef __M_UTIL_H__
#define __M_UTIL_H__
//  通⽤功能类,与业务⽆关的功能实现
//  1. 获取系统时间
//  2. 判断文件是否存在
//  3. 获取⽂件所在⽬录的路径
//  4. 创建⽬录
#include <iostream>
#include <ctime>
#include <sys/stat.h>
#include <sys/types.h>
namespace logsLearn
{namespace util{// 日期类class Data{public:// 获取系统时间static time_t now(){// 返回当前系统时间return time(nullptr);}};// 文件类class File{public:// 判断文件是否存在static bool exists(const std::string &pathname){ // 定义了一个stat的结构体变量struct stat st;// 获取文件信息不成功,进入条件if (stat(pathname.c_str(), &st) < 0){return false;}return true;}// 获取⽂件所在⽬录的路径static std::string path(const std::string &pathname){ if (pathname.empty()) return ".";// pos是当前查找的最后“/\\”的位置size_t pos = pathname.find_last_of("/\\");// 没有找到"/\\"if (pos == std::string::npos)return ".";// 找到了,返回路径,左闭右开原则,要想包括pos位置,需要加1return pathname.substr(0, pos + 1);}// 创建⽬录static void createDirectory(const std::string &pathname){ // pos找到的位置,idx是存的位置size_t pos = 0, idx = 0;while (idx < pathname.size()){// 遍历路径每找到最后一个"/\\"创建文件夹size_t pos = pathname.find_first_of("/\\", idx);if (pos == std::string::npos){ // 创建文件夹,pathname.c_str()表示路径名,0777表示权限mkdir(pathname.c_str(), 0777);}// 前面的路径std::string parent_dir = pathname.substr(0, pos + 1);// 文件是否存在if (exists(parent_dir) == true){idx = pos + 1;continue;}// 文件不存在,创建文件mkdir(parent_dir.c_str(), 0777);idx = pos + 1;}}};}
}
#endif
  1. 我们每次编写完一个模块后,要对其进行单元测试,确保程序的准确性。
//测试代码
#include "util.hpp"
int main()
{//工具类测试std::cout<<logsLearn::util::Data::now()<<std::endl;std::string pathname="./abc/bcd/a.txt";std::cout<<pathname;logsLearn::util::File::createDirectory(logsLearn::util::File::path(pathname));return 0;
}
  1. 界面展示
    make运行之前
    在这里插入图片描述
    make运行之后
    在这里插入图片描述
    补充:
    1.stat函数
    stat函数是用于获取文件信息,比如文件权限,文件类型信息等等。
    函数的声明:
    int stat(const char *pathname, struct stat *buf);
    参数说明:
    pathname:表示文件路径名
    buf:用于保存获取到的文件属性信息(这是一个传出参数)
    返回值说明:成功返回0,失败返回-1并设置errno
    2.mkdir函数
    mkdir函数用于创建一个新的目录。如果指定的目录已经存在,并且没有设置相应的标志来允许覆盖或忽略已存在的目录,则函数会失败;它允许用户为新创建的目录设置权限,这些权限决定了谁可以访问该目录。
    函数声明:
    int mkdir(const char * pathname , mode_t mode);
    参数说明:
    pathname(const char * ):指向以null结尾的字符串的指针,该字符串指定了要创建的目录的路径。路径可以是相对路径或绝对路径。
    mode(mode_t):指定新目录的权限。这些权限位使用八进制数表示(例如,0755),并且会受进程的文件模式创建掩码(umask)的影响。最终权限是请求权限与umask的补码的逻辑与结果。通常,mode参数包括文件所有者(user)、组(group)和其他人(other)的读(r)、写(w)和执行(x)权限的组合。
    返回值说明:成功时,返回0;失败时,返回-1,并设置全局变量errno以指示错误类型(如EACCES表示权限不足,EEXIST表示目录已存在等)。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

速度太慢,跑个分试试:AI语言模型和API性能对比;开源的高质量PDF,DOC提取工具;斯坦福TTT代码实现

✨ 1: Artificial Analysis AI语言模型和API提供商的比较分析&#xff0c;帮助用户选择最佳方案。 Artificial Analysis 是一个专门独立分析AI语言模型和API提供商的平台&#xff0c;旨在帮助用户了解AI领域并选择最适合其需求的模型和API提供商。以下是该平台的主要内容和功…

无法加载文件 xxxx 因为在此系统上禁止运行脚本。有关详细信息,请参阅,Windows执行策略有关问题

无法加载文件 xxxx 因为在此系统上禁止运行脚本。有关详细信息&#xff0c;请参阅&#xff0c;Windows执行策略有关问题 1.1 出现问题 在Windows11中的Windows PowerShell执行一些前端的命令时经常会出现如下问题&#xff1a; PS C:\Users\Admin\Desktop> vue init webpa…

QListWidget、QTreeWidget、QTableWidget的拖放

QListWidget、QTreeWidget、QTableWidget的拖放实验 QAbstractItemView::DragDropMode 的枚举值 QAbstractItemView::NoDragDrop0组件不支持拖放操作QAbstractItemView::DragOnly1组件只支持拖动操作QAbstractItemView::DropOnly 2组件只支持放置操作QAbstractItemView::DragDr…

UI Toolkit generateVisualContent的使用

方法描述: Called when the VisualElement visual contents need to be (re)generated. When this delegate is handled, you can generate custom geometry in the content region of the VisualElement. For an example, see the MeshGenerationContext documentation. This…

职业本科计算机网络实训室

一、职业本科计算机网络实训室建设的背景 随着数字化时代的深入发展&#xff0c;计算机网络技术已经渗透到社会的每一个角落&#xff0c;成为推动社会进步的重要力量。在《中华人民共和国国民经济和社会发展第十四个五年规划和2035年远景目标纲要》中&#xff0c;建设数字中国…

统信UOS软件包标识化工具deepin-sbom-tools使用

原文链接&#xff1a;统信UOS上使用软件包标识化工具deepin-sbom-tools Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在统信UOS上使用软件包标识化工具deepin-sbom-tools的文章。deepin-sbom-tools是一个强大的工具&#xff0c;可以帮助开发者和系统管理员更好…

保密U盘仍然存在数据安全危机?该怎么用才能规避?

保密U盘以前主要用于国家涉密单位或部门&#xff0c;但随着人们对于信息安全的重视越来越高&#xff0c;在民用企事业单位以及个人用户方面也应用得日益广泛。 使用保密U盘在安全性上比普通U盘具有优势&#xff0c;但却仍然存在安全危机&#xff0c;具体为&#xff1a; 病毒和…

Linux开发板(正点原子阿尔法_IMX6U)QT5.12.9交叉编译到ARM开发板(已解决)

问题记录&#xff1a;Qt下ctrlR直接构建项目&#xff0c;然后在build-01_led-Desktop_Qt_5_12_9_GCC_64bit-Debugz中将构建的执行文件&#xff0c;scp到ARM开发板下&#xff0c;发现通过指令./01_led后出现以下报错。 问题原因&#xff1a;因为Qt构建默认使用的是64bit的gcc&am…

【Linux】vim详解

1.什么是vi/vim? 简单来说&#xff0c;vi是老式的文本编辑器&#xff0c;不过功能已经很齐全了&#xff0c;但是还是有可以进步的地方。vim则可以说是程序开发者的一项很好用的工具&#xff0c;就连 vim的官方网站&#xff08; http://www.vim.org&#xff09;自己也说vim是一…

matlab 卷积和多项式乘法

目录 一、算法原理1、原理概述2、主要函数二、代码实现1、通过卷积计算多项式乘法2、向量卷积3、卷积的中心部分三、参考链接一、算法原理 1、原理概述 两个向量 u u u和 v v v的卷积,表示

前端面试题36(js栈和堆)

在JavaScript中&#xff0c;内存管理是自动进行的&#xff0c;主要通过栈(stack)和堆(heap)两种方式来分配和管理内存。理解这两者对于深入学习JavaScript以及优化代码性能非常关键。 栈 (Stack) 栈是一种后进先出&#xff08;Last In, First Out, LIFO&#xff09;的数据结构…

2024年【熔化焊接与热切割】考试报名及熔化焊接与热切割作业考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【熔化焊接与热切割】考试报名及熔化焊接与热切割作业考试题库&#xff0c;包含熔化焊接与热切割考试报名答案和解析及熔化焊接与热切割作业考试题库练习。安全生产模拟考试一点通结合国家熔化焊接与热切割考试…

确保智慧校园安全,充分利用操作日志功能

智慧校园基础平台系统的操作日志功能是确保整个平台运行透明、安全及可追溯的核心组件。它自动且详尽地记录下系统内的每一次关键操作细节&#xff0c;涵盖操作的具体时间、执行操作的用户账号、涉及的数据对象&#xff08;例如学生信息更新、课程调度变动等&#xff09;、操作…

关于Python的类的一些理解

才发现python的类对象只能调用类方法 我想使用对类对象a使用系统调用的len方法就会报错 2.类对象a是什么&#xff1f; 答&#xff1a;是所有的带有self的成员变量 举例说明&#xff1a;红色的就是a里面的东西 class A:def __init__(self,data):self.datadataself.b1self.d{a…

ipad怎样录屏?一看就会的详细步骤

随着iPad功能的日益强大&#xff0c;屏幕录制已成为许多用户在日常工作、学习和娱乐中的必备技能。无论是记录操作步骤、分享游戏精彩瞬间&#xff0c;还是制作教学视频&#xff0c;屏幕录制都发挥着不可或缺的作用。这时可能会有人疑问&#xff0c;ipad怎样录屏呢&#xff1f;…

利用SpringBoot+rabbitmq 实现邮件异步发送,保证100%投递成功

在之前的文章中&#xff0c;我们详细介绍了 SpringBoot 整合 mail 实现各类邮件的自动推送服务。 但是这类服务通常不稳定&#xff0c;当出现网络异常的时候&#xff0c;会导致邮件推送失败。 本篇文章将介绍另一种高可靠的服务架构&#xff0c;实现邮件 100% 被投递成功。类…

为什么要安装HTTPS证书?

安装HTTPS证书对于确保网站数据的安全性、增强用户信任度、提升品牌形象和优化搜索引擎排名至关重要。在互联网时代&#xff0c;信息传输的安全性和隐私保护已成为公众和企业最为关注的问题之一。HTTPS证书的引入&#xff0c;正是为了解决这些问题&#xff0c;为网站和用户提供…

git为文件添加可执行权限

查看文件权限 git ls-files --stage .\SecretFinder.py100644 表示文件的所有者有读取和写入权限 添加可执行权限 git update-index --chmod x .\SecretFinder.py再次查看文件权限 git ls-files --stage .\SecretFinder.py100755 表示文件的所有者有读取、写入和执行权限

第十六章 ValidationPipe验证post请求参数

在此之前我们用到的请求都是get请求&#xff0c;接下来我们使用post 请求 并接收参数&#xff0c;通过 Body 装饰器来取注意&#xff1a;post请求带参数 我们通过游览器路径是直接请求不了的 需要使用postman 来发 post 请求postman 下载网站 https://www.postman.com/download…

3D问界—ZBrush最新版本中的旋转Local按钮哪儿去哪儿?

问题提出&#xff1a;ZBrush最新版本中的Local按钮哪儿去哪儿&#xff1f; 目前我使用的是Zbrush2024.0.1版本&#xff0c;但是当我想要取消锁定局部旋转的时候死活找不到local功能。 1. 注意&#xff1a;Local功能挪到这里了 2. 关于local功能的使用&#xff08;Local Trans…