C++ 日志系统实战第一步:项目功能与技术架构详解

C++ 日志系统实战第一步:项目功能与技术架构详解

C++-基于多设计模式下的同步&异步日志系统

全是通俗易懂的讲解,如果你本节之前的知识都掌握清楚,那就速速来看我的项目笔记吧~   

(全文手敲,受益良多) 本人也是做到项目了,后面会日更项目笔记。 


我们要实现日志系统,先了解

什么是日志?

   程序运行过程中所记录的程序运行的状态信息。为什么要这些信息呢?便于程序员对程序运行状况判断,进而分析,修改代码子类的。所以

日志作用:记录了程序运行状态信息,便于程序员能够随时根据状态信息,对系统的运行状态,进行分析

项目功能:能够让用户非常简便的进行日志的输出,及其控制。

一.项目介绍

本项目主要实现一个日志系统,其主要支持以下功能:

支持多级别日志消息:(级别有:调试,提示,警告,错误,致命,不同级别对应不同场景:例如调试级别的日志不输出…)
 支持同步日志和异步日志:(同步指的是该工作由自己干,异步指的是该工作由别人干,自己等结果就行)同步日志指的是将日志写入到文件或数据库中去,这个操作由业务线程自己完成。异步日志指的是,将日志放到内存中去,由于担心磁盘满了,或者数据库有问题导致程序卡住,业务无法做了,所以自己并不写入到文件或数据库中。而是让其他工作线程专门把日志进行实际输出。
 支持可靠写入日志到控制台、文件以及滚动文件中:(也就是支持日志的不同落地方向,除了将日志标准输出打印,还支持将日志写入指定文件中去。还有一种叫滚动文件:如果我们将日志一直向一个文件写入,文件将变得很大,会占用大量的磁盘空间,把该文件删除又担心有重要信息。所以提出一种思想:文件的切换输入,具体实现例子:如果一个文件大小达到 1GB,就切换下一个文件,根据大小区分文件,当然,也可以根据日期进行切换。这样清理起来就方便多了 (可以支持控制台、文件以及滚动文件三种同时进行,落地方向提供给你,想怎么输出,由用户自己决定)
 支持多线程程序并发写日志:(线程安全的日志系统,当多个线程同时向同一个文件进行写入的时候,会引发线程安全问题,我们的项目解决了这个问题)
 支持扩展不同的日志落地目的地:(如果你想让日志写入数据库,服务器都是可以的,支持扩展,进行创建)

开发环境

  • CentOS7
  • vscode/vim
  • g++/gdb
  • Makefile

核心技术

  • 类层次设计 (继承和多态的应用)
  • C++11 (多线程、auto、智能指针、右值引用等)
  • 双缓冲区
  • 生产消费模型
  • 多线程
  • 设计模式 (单例、工厂、代理、建造者等)

我们的项目是功能型的,而不是业务型的。我们来看看性能:

,云服务器问题,实际更高

详细了解日志系统能干什么?为什么要有日志系统?实现日志系统的技术?思想有何不同?

为什么需要日志系统?当出现以下情况时

   日志指的是系统在运行过程中所记录的状态信息,日志系统则把日志信息记录到指定的位置。生产环境的产品为了保证其稳定性及安全性是不允许开发人员附加调试器去排查问题,(在实际开发环境中,我们调试的时候,不可能整天去看运行信息,而且信息刷新的很快,根本看不过来。所以我们不能通过打印来调试,其次 gdb 调试是不被允许的,任何的产品都有隐私的,gdb 调试会看到所有的东西,没有安全。所有我们只能借助日志系统,将关键节点的状态记录在日志系统里面去,如果项目出问题了,打开文件分析哪些文件导致的(从普通错误变为了致命错误)可以借助日志系统来打印一些日志帮助开发人员解决问题。上线客户端的产品出现 bug 无法复现并解决,可以借助日志系统打印日志并上传到服务端帮助开发人员进行分析。对于一些高频操作(如定时器、心跳包)在少量调试次数下可能无法触发我们想要的行为,通过断点的暂停方式,我们不得不重复操作几十次、上百次甚至更多,导致排查问题效率是非常低下,可以借助打印日志的方式查问题。在分布式、多线程 / 多进程代码中,出现 bug 比较难以定位,可以借助日志系统打印 log 帮助定位 bug。帮助首次接触项目代码的新开发人员理解代码的运行流程。

日志系统的实现思想有哪些?

日志系统的技术实现主要包括三种类型:

利用 printf、std::cout 等输出函数将日志信息打印到控制台。(学习阶段的使用方式)对于大型商业化项目,为了方便排查问题,我们一般会将日志输出到文件或者是数据库系统方便查询和分析日志,主要分为同步日志和异步日志方式同步写日志异步写日志

同步写日志

同步日志是指当输出日志时,必须等待日志输出语句执行完毕后,才能执行后面的业务逻辑语句(必须完成了,才可以进行下一步),日志输出语句与程序的业务逻辑语句将在同一个线程运行。每次调用一次打印日志 API 就对应一次系统调用 write 写日志文件。

缺陷:在高并发场景下,随着日志数量不断增加,同步日志系统容易产生系统瓶颈:
(写给文件时可能会有阻塞,发送给服务器可能有拥塞,这是会卡在写日志这里,无法向后运行啦)

  • 一方面,大量的日志打印陷入等量的 write 系统调用,有一定系统开销.
  • 另一方面,使得打印日志的进程附带了大量同步的磁盘 IO,影响程序性能

异步写日志

异步日志是指在进行日志输出时,日志输出语句与业务逻辑语句并不是在同一个线程中运行,而是有专门的线程用于进行日志输出操作。

在上述关于异步日志的描述中,以下方面体现了生产消费者模型:
 

生产者角色:业务线程在执行过程中产生需要记录的日志信息,它将这些日志信息放到内存缓冲区中。就如同生产线上制造产品的环节,业务线程不断 “生产” 出日志数据,而不需要等待日志落地等后续操作,直接继续执行后续业务逻辑,所以业务线程充当了生产者的角色。消费者角色:有专门的日志线程负责从内存缓冲区中读取日志信息,并将其进行落地操作(比如写入文件等)。这类似于在生产消费体系中,消费者从特定的存储区域获取产品并进行使用或处理,日志线程在这里就是消费者,它从内存缓冲区(相当于存储区域)中获取日志数据(产品)并进行处理(落地操作)。缓冲区:内存缓冲区起到了类似于生产消费者模型中产品暂存区域的作用。业务线程生产的日志数据先放到这里,日志线程再从这里获取数据,它解耦了生产者(业务线程)和消费者(日志线程)的直接联系,使得两者可以以不同的速度和节奏工作,符合生产消费者模型中通过缓冲区协调生产和消费速度差异的特点。

综上所述,通过业务线程、日志线程以及内存缓冲区之间的这种关系,清晰地体现了生产消费者模型。

这样做的好处是即使日志没有真的地完成输出也不会影响程序的主业务,可以提高程序的性能:

主线程调用日志打印接口成为非阻塞操作同步的磁盘 IO 从主线程中剥离出来交给单独的线程完成

如果你对日志系统感到兴趣,欢迎关注我👉【A charmer】

后续我将继续带你实现日志系统~

Read more

华为OD机试双机位C卷:日志解析(C/C++/Java/Python/Go/JS)

华为OD机试双机位C卷:日志解析(C/C++/Java/Python/Go/JS)

日志解析 2026华为OD机试双机位C卷 - 华为OD上机考试双机位C卷 200分题型 华为OD机试双机位C卷真题目录点击查看: 华为OD机试双机位C卷真题题库目录|机考题库 + 算法考点详解 题目描述 你是一个运维工程师,你同时负责n个系统的运维工作,已知每个系统每天会都从现场采集大量的现网运行日志(错误日志、接口日志等)下来生成一个日志文件,每个系统采集下来的日志文件大小均不相同。为了解析这些日志,你给每个系统配备了一台默认服务器进行日志解析,且此台服务器只能给本系统使用,由于所配置的服务器规则均相同,因为解析日志的速度也是相同的,即每秒钟可以解析defaultCnt条日志。 现在你发现解析的速度达不到预期,但你手头上还有一部分额外的资源可以使用,这些资源可以在任意时刻配置给任意一台服务器。但有个限制,那就是同一时刻只能配给其中一台服务器器,且服务器器是能整合全部额外资源,当然在下一秒钟即可配备给另外一台服务器。某一台服务器配备了额外资源以后,则每秒钟会增加解析extraCnt条日志,即每秒可解析(defaultCnt+extraCnt)条日志。 输入描述 输入一

By Ne0inhk
【C++初阶】:C++入门相关知识(3):引用 & inline内联函数 & nullptr相关概念

【C++初阶】:C++入门相关知识(3):引用 & inline内联函数 & nullptr相关概念

🎈主页传送门:良木生香 🔥个人专栏:《C语言》 《数据结构-初阶》 《程序设计》《鼠鼠的C++学习之路》 🌟人为善,福随未至,祸已远行;人为恶,祸虽未至,福已远离 前言:在上一篇文章中,我们学习了C++的输入输出,缺省参数以及函数重载,这些都是C++入门必备的基础知识,那么在这篇文章中,我们就要来学习剩下C++其他的基础知识,那就是引用、inline、以及nullptr这些知识。 一、引用 1.1、引用的概念和定义 引用不是定义一个新变量,而是给已经存在的变量起一个别名,那么编译器就不会为别名重新开辟空间,它和引用变量共同使用同一块空间。就好比我们把土豆称为马铃薯,番茄称为西红柿一样,都是取了一个新的别名,但是东西是同一个东西,所以引用的语法如下: 类型& 别名 = 变量 使用方法如下: int a = 10; int&

By Ne0inhk
【C++】priority_queue和deque的使用与实现

【C++】priority_queue和deque的使用与实现

priority_queue与deque的使用与模拟实现 ✨前言:在C++ STL中,priority_queue和deque是两个重要的容器适配器,它们分别基于堆和双端队列的概念,为不同的应用场景提供了高效的解决方案。本文将深入探讨它们的使用方法、底层实现原理以及在实际开发中的应用选择。 📖专栏:【C++成长之旅】 目录 * priority_queue与deque的使用与模拟实现 * 一、priority_queue * 1.1 介绍 * 1.2 使用 * 1.3 模拟实现 * 二、deque * 2.1 介绍 * 2.2 缺陷 * 三、STL标准库中对于stack和queue的模拟实现 * 3.1 为什么选择deque作为stack和queue的底层默认容器 * 3.2 stack的模拟实现 * 3.3 queue的模拟实现 一、priority_

By Ne0inhk
计算机毕设java电子商务网站的设计与实现 基于Spring Boot的在线购物平台开发与实现 Java技术驱动的B2C网络商城系统构建

计算机毕设java电子商务网站的设计与实现 基于Spring Boot的在线购物平台开发与实现 Java技术驱动的B2C网络商城系统构建

计算机毕设java电子商务网站的设计与实现4940z9(配套有源码 程序 mysql数据库 论文) 本套源码可以在文本联xi,先看具体系统功能演示视频领取,可分享源码参考。 随着互联网技术的飞速发展和移动支付的普及,电子商务已成为推动经济增长的重要引擎。传统零售模式面临渠道单一、运营成本高昂、客户触达受限等困境,而线上购物以其便捷性、多样性和价格优势赢得了消费者的青睐。与此同时,中小企业数字化转型需求迫切,亟需低成本、高效率的电商解决方案来拓展销售渠道、提升品牌影响力。然而,市面上成熟的电商平台往往存在入驻费用高、数据归属不清、功能同质化等问题,难以满足个性化运营需求。基于此,采用Java语言结合Spring Boot框架,开发一套电子商务网站,通过B/S架构实现商品展示、在线交易、订单管理、用户互动等核心功能,旨在为商家提供自主可控的线上销售平台,为消费者打造安全便捷的购物体验,助力数字经济的普惠发展。 系统功能模块 本系统采用Spring Boot作为后端开发框架,数据库选用MySQL进行数据存储,基于B/S架构设计。系统涵盖以下核心功能模块: 用户管理模块:实现用户基

By Ne0inhk