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

news2025/4/22 10:09:35

同步异步日志系统

  • 一、日志系统框架设计
    • 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位置,需要加1
                return 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://www.coloradmin.cn/o/1914052.html

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

相关文章

Coze API接口实战应用

Coze API介绍 概述 Coze API作为Coze平台对外的桥梁&#xff0c;让开发者能够灵活地利用Coze的功能和服务&#xff0c;促进业务流程自动化和系统集成。它覆盖了从数据获取到智能交互的全方位功能&#xff0c;旨在提升工作效率和创造更多可能。 Coze API申请接入流程 1. 发现…

python--实验8 函数(2)

知识点 变量的作用域 定义&#xff1a;解释了局部变量和全局变量的概念。局部变量&#xff1a; 局部变量是在函数内部定义的变量。它们只在该函数内部可见&#xff0c;一旦函数执行完毕&#xff0c;这些变量就会被销毁。例子&#xff1a;在函数内部通过赋值创建的变量。全局…

【卡尔曼滤波】高斯白噪声

生成高斯白噪声并将其应用于信号处理 生成高斯白噪声并将其应用于信号处理 #以下是一个生成高斯白噪声并将其应用于信号处理的示例代码:import numpy as np import matplotlib.pyplot as plt import matplotlib.font_manager ## not work#notice matplotlibrc is a file, not…

hf-mirror (huggingface 的国内镜像)

官网&#xff1a; https://hf-mirror.com/ 网站域名 hf-mirror.com&#xff0c;用于镜像 huggingface.co 域名。作为一个公益项目&#xff0c;致力于帮助国内AI开发者快速、稳定的下载模型、数据集。 如何使用HF-Mirror 方法一&#xff1a;网页下载 在https://hf-mirror.com/…

ubuntu笔记本X86安装nomachine客户端

资源下载: 链接: link 一、首先下载文件 nomachine_8.2.3_4_x86_64.tar.gz到桌面。 二、打开终端,依次输入 进入root模式,需要输入密码,密码不可见。 sudu su复制nomachine_8.2.3_4_x86_64.tar.gz粘贴到/usr目录: cp -r nomachine_8.2.3_4_x86_64.tar.gz /usr进入

使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-敌机配置(五)

文章目录 开发思路敌人节点场景绿色敌人制作 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击&#xff08;一&#xff09; 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-激光组件&#xff08;二&#xff09; 使用Godot4组件制作竖版太空射击游戏_2D卷轴飞机射击-飞船…

强化学习总结(有具体代码实现)

文章目录 第一部分 强化学习基础第1章 强化学习概述1.1 强化学习概念1.2 强化学习的环境1.3 强化学习的目标1.4 强化学习的数据 第2章 多臂老虎机问题&#xff08;MAB问题&#xff09;2.1 问题描述2.1.1 问题定义2.1.2 形式化描述2.1.3 累积懊悔2.1.4 估计期望奖励 2.2 解决方法…

(自用)gtest单元测试

gtest是Google的一套用于编写C测试的框架&#xff0c;可以运行在很多平台上&#xff08;包括Linux、Mac OS X、Windows、Cygwin等等&#xff09;。基于xUnit架构。支持很多好用的特性&#xff0c;包括自动识别测试、丰富的断言、断言自定义、死亡测试、非终止的失败、生成XML报…

跑GCN收敛实验时遇到的Python环境问题

错误1&#xff1a; 报错提示&#xff1a;No module named sklearn.utils.linear_assignment_ 原因&#xff1a;linear_assignment 函数从0.21开始被弃用了&#xff0c;并且将在0.23版本中移除。 解决方法&#xff1a;降低scikit-learn版本&#xff08;本人通过该方法解决&#…

从零开始开发视频美颜SDK:实现直播美颜效果

因此&#xff0c;开发一款从零开始的视频美颜SDK&#xff0c;不仅可以节省成本&#xff0c;还能根据具体需求进行个性化调整。本文将介绍从零开始开发视频美颜SDK的关键步骤和实现思路。 一、需求分析与技术选型 在开发一款视频美颜SDK之前&#xff0c;首先需要进行详细的需求…

自定义指令实现Element Plus分页组件内容样式修改

改之前是这样的 改之后是这样的 因为之前我也有写过文章讲解Vue2-ElementUI分页组件的样式修改。 ElementUI 分页组件内容样式修改https://blog.csdn.net/qq_54548545/article/details/139728064且通常情况下&#xff0c;一个项目若是大量使用到分页组件&#xff0c;咱们也不可…

MySQL语法笔记(补充版)

补充上一篇博客没涉及到的实用语法 MySQL语法笔记&#xff08;温习版&#xff09; 查看正在使用的数据库 SELECT DATABASE()查看时区 show VARIABLES like time_zone修改时区 timestamp类型存储的时间与MySQL数据库系统安装时所选的时区有关&#xff0c;在不同时区下查看的同…

【SVN的使用- SVN的基本命令-SVN命令简写-注意事项-解决冲突 Objective-C语言】

一、SVN的更新命令:update 1.服务器如果新建了一个文件夹,yuanxing,版本变成6了, 我现在本地还只有三个文件夹,版本5, 终端里边,我们敲一个svn update, 我这儿就多了一个yuanxing文件夹, 这个就是更新,就是把服务器最新的代码下载下来, 假设服务器上大家提交了这…

[CTF]-PWN:House of Cat堆题型综合解析

原理&#xff1a; 调用顺序&#xff1a; exit->_IO_wfile_jumps->_IO_wfile_seekoff->_IO_switch_to_wget_mode _IO_wfile_seekoff源码&#xff1a; off64_t _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode) {off64_t result;off64_t delta, new…

基于ARM Cortex-M3单片机研发的国产指纹芯片 - P1032BF1

智能指纹锁的核心部件&#xff1a;主板、离合器、指纹采集器、密码技术、微处理器&#xff08;CPU&#xff09;、智能应急钥匙。作为指纹锁来说&#xff0c;重要的应该是指纹芯片。指纹锁是通过电子部件及机械部件的精密组合而生产出的安全产品。指纹锁的本质无非是安全、便捷、…

man手册的安装和使用

man手册 - HQ 文章目录 man手册 - HQ[toc]man手册的使用Linux man中文手册安装man中文手册通过安装包安装通过apt安装 配置man中文手册README使用说明配置步骤 man手册的使用 首先man分为八个目录&#xff0c;每个目录用一个数字表示 1.可执行程序2.系统调用3.库函数4.特殊文…

7.深度学习概述

深度学习概述 1. 线性回归1.1 线性回归一般表达式1.2 线性回归内积表达方式&#xff1a;1.3 多个样本时&#xff0c;线性回归的进一步表达&#xff1a;1.4 线性回归方程的解析1.5 线性回归就是求loss函数的最小值 2. 如何求函数最小值2.1 一个例子2.2 求导法——求最小值2.3 求…

CVE-2024-34351 漏洞复现

CVE-2024-34351&#xff0c;由Next.js异步函数createRedirectRenderResult导致的SSRF。 影响版本&#xff1a;13.4.0< Next.js < 14.1.1 参考文章&#xff1a; Next.js Server-Side Request Forgery in Server Actions CVE-2024-34351 GitHub Advisory Database Gi…

Ubuntu22.04.4 LTS系统/安装Anaconda【GPU版】

安装过程 1.wget命令行下载 下载Anaconda并保存文件至本地指定目录 wget -c https://repo.anaconda.com/archive/Anaconda3-2023.09-0-Linux-x86_64.sh -P ~/Downloads/anaconda3 查看是否下载好了 2.安装Anaconda 2.1 bash命令安装 bash后面是anaconda3下载好的路径 bash …

节点的真相:纠正大众对区块链安全概念的误解

​​发表时间&#xff1a;2024年4月25日 长期以来&#xff0c;人们都在对区块链及其基本原则进行讨论&#xff0c;但是只有“节点”这个概念被精准地定义&#xff0c;才能让我们穿越“去中心化”这个复杂概念的迷雾。在网络学的理论中&#xff0c;节点代表网络或图形中的一个实…