P11 如何写一个C++类 Log日志基础

2023-11-25 16:30
文章标签 基础 c++ 日志 log p11

本文主要是介绍P11 如何写一个C++类 Log日志基础,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

01 前言

到目前为止,我们学了类 class,本期我们要尝试着从头开始写一个类。

本期不会讲的太深。我们不会写非常复杂的类,我们要会完成一个基本的 log 类

02 为什么使用 log

首先我们先分析一下我们的需求,这个 log 类到底是什么?具体要完成什么功能?

这个 log 类是我们管理日志信息的一种方式,换句话说我们想要我们的程序打印消息或信息到控制台。这个通常对调试代码非常有帮助。

比如,在游戏或应用中,如果我们想知道发生了什么,你只需将事务的状态打印到控制台,因为应用程序中的控制台就像一个展示信息的地方,我们可以用它来打印出发生了什么。这也是几乎可以保证代码在正确工作的东西。

控制台基本上是内置在操作系统中的东西,所以我们几乎可以保证它不会出问题。

我很喜欢用 log 类作为例子,

  1. 因为日志系统可以根据您的需要从简单的或复杂的都行,——有些日志系统非常复杂,甚至有可能有几千行代码,而这些仅仅是为了把东西打印到控制台。但它们对调试和开发非常重要,所以花点时间在这上面是值得的。
  2. log 日志系统不仅可以做简单将信息打印到控制台这样的事情,也可以用不同颜色打印或是通过网络输出日志消息到一个文件,你可以做很多事情,你最终完成的 log 类十行到一万行代码都行。就是这样。

这就是为什么我会说 log 是一个很好的例子的原因。

03 log 需要包括哪些参数

log 类开始的时候非常简单,它提供向控制台写入文本的能力并保持某种日志级别,也就是我们真正想要发送给控制台的日志信息的级别,开始我们有三个层次

  • 错误 eror
  • 警告 warning
  • 信息 information

我们将来可能我们的日志系统级别设置为警告 warning。这意味着只会打印警告和错误而不会打印跟踪消息。这是非常有用的。如果你不想看到一堆信息,你只想知道哪里出了问题或者你的警告是什么,同样通过过滤实际发送和打印的内容。控制台也会很清爽

我们首先肯定是先实例化一个 log。然后,我们可能指定某种日志级别作为一个实际参数,暂且先跳过它。

log 肯定会设置一个 log 级别, SetLevel 方法的参数 WarnLevel就是指 warning 级别,这意味着只有警告或更重要的信息,比如警告或错误,才会被打印出来。但不跟踪消息。

然后我可能想要打印一个警告信号。

通过以上模拟操作,现在我知道了我的 log 类大概是什么样子了,我们可以直接回去类中开始填空。

这两个函数都是需要能够在外部访问的,所以我们设置它的可见性为 public。

首先是 SetLevel 函数,将 log 级别也就是 level 作为函数的整型参数,这样比较简单。然后这个函数会做一些事情。

然后还有一个 Warnint 函数,它有一个 const char 的参数,是我们的 message。const char 就是字符串的意思,后面我们会专门有一期介绍字符串的内容,现在先知道这些就可以了。

我们现在还有一个问题,这几个函数都已经存在了,可是 lWarningLevel 不存在,让我们开始声明 log 的级别变量。

我们创建一个私有的成员变量来保存我们的 log 级别的设定,它是一个整形,我把它叫做 M_Level,——按照惯例我使用了M_作为前缀,这样可以提示我们这是一个私有的类成员变量,通过这样的方式当我在函数内部写代码时,我就能知道在类代码中哪些是成员变量哪些只是局部变量,当然这样的写法约定不是必须的,但是它确实对整理你的代码并保持代码干净很有帮助。特别是当你处理大型代码库和复杂类这样的东西时。所以我建议大家遵循这样的惯例。

顺便,我们快速地将 SetLevel 函数设置完成。在它里面将参数值赋值给成员变量 M_Level。

让我们回到 main中,处理 LogLevelWarning 这个地方。

我们前面已经规划好了,设为 2 的意思是信息(或者跟踪),1的意思是警告,0的意思是错误,直接这样设置的话,代码读起来有点困难,如果我写的代码是那样的话,读代码的时候会有很多疑问,什么是1?1是个啥?我会不知道它是什么意思,只能靠记忆来记住它代表什么意思,我不想这样处理这个问题。因此我们要创建一些变量,当它的值是某些值的时候表示我们想要表示的东西。

我们在这里将它们设为公共 public 变量,你可以看到我在 log 类中用了两次 public,我喜欢把类中不同的部分分开来写,换句话说,public 方法可能在一个部分,然后 public 变量可以放在另一部分, public 静态变量可能会放在另一块中,这就是我的风格,你可以参考。

这些都是参数,所以我将它设置为 const int ,然后将 LogLevelWarning 设为1,我们还需要为错误写一个日志级别,LogLevelError 设置为零,然后我要为日志的信息跟踪再写一个 LogLevelInfo,让它等于2。

因此我们有三种类型的日志消息,我们有错误 Error、警告 warning、还有信息 information,默认情况下我会把我的日志级别设置为 LogLevelInfo,意思是把所有的东西都应该打印出来。

以上。

最后我们完善一下类里面的方法

我们现在有个问题。

我们当前的代码没有办法做到这个需求:如果日志级别设置成了 warning,就不要打印所有的 Info 消息。

我们可以通过添加 if 语句来搞定这个。

如果日志级别大于或等于这个特定的消息级别,那么就继续,Warn 和 Info方法也是一样的。然后我们将main函数中的 LogLevelWarning 调整为 log.LogLevelWarning。我们已经将 log 设置为警告级别。

04 运行log代码

运行我们的代码,看看具体的效果。我们试试打印 warning信息和 Error信息。

没有问题,就是我们想的那样。

后话

我们实现了所有的目标,创造了一个非常基本的 log 类。

但是我想说这绝对不是我自己写 log 类的方式,因为有一些问题需要解决,一个经验丰富的程序员是不会这样写的,这不是特别完整的代码,但它是比较基础的代码

#include <iostream> class Log
{
public:const int LogLevelError = 0; //日志级别Error = 0const int LogLevelWarning = 1; //const int LogLevelInfo = 2; //private:int m_level;  //私有的变量,用于类的内部public:void setLevel(int level)   //设置日志级别{m_level = level;    //}void Error (const char* messge)   //打印警告级别的日志信息{if(m_level >= LogLevelError)std::cout << messge << std::endl;}void warning(const char* messge)   //打印警告级别的日志信息{if(m_level >= LogLevelWarning)std::cout << messge << std::endl;}void Info(const char* messge)   //打印警告级别的日志信息{if(m_level >= LogLevelInfo)std::cout << messge << std::endl;}};int main()
{Log log;log.setLevel(log.LogLevelWarning);   //日志级别设为warning 1log.warning("hello ,this is warning");log.Error("hello,this is Error"); //log.Info("this is Info"); //return  0;
}

这篇关于P11 如何写一个C++类 Log日志基础的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/424134

相关文章

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

内核启动时减少log的方式

内核引导选项 内核引导选项大体上可以分为两类:一类与设备无关、另一类与设备有关。与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项。比如,如果你想知道可以向 AHA1542 SCSI 驱动程序传递哪些引导选项,那么就查看 drivers/scsi/aha1542.c 文件,一般在前面 100 行注释里就可以找到所接受的引导选项说明。大多数选项是通过"_

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念