6.8日志系统

当做大型项目的时候,出了bug可能需要借助于日志检查,小项目一般是打断点。

服务器是一直在运行的,不能停止,可以借助于日志检查错误。

日志分为两种:业务级别的日志(供用户分析业务过程),系统级别的日志(用来供程序员分析)

因为日志文件占据的存储空间很大,会打印很多的信息,难以检查错误信息,所以需要进行合理的设计。

本章节主要学习日志记录系统log4cpp。

日志系统包含四类信息:分别是:记录器、过滤器、格式化器、输出器四部分。

记录器:记录信息的来源,时间,优先级,位置。

过滤器:并不是把所有的        信息都保存下来。有时候把不重要的信息过滤掉。

格式化器:将日志信息设置布局,这样更方便查看。

输出器:设置日志目的地,例如存储到文件。

ostreamAppender是一个Appender的派生类

基类指针指向派生类对象

基类引用访问派生类对象(std::getline返回一个istream,使之与iftream绑定)

ostreamAppender的第一个参数只是给程序员一个提醒内容无关紧要,第二个参数是ostream* 这个地方就是使用了&cout,当然也可以绑定文件流也就是派生类。

basiclayout 将距离1970年。。有多少秒,所以说我们在自己用的时候不用这个。

root节点是通过单例模式进行创建在栈上的对象

当日志优先级比系统优先级要低就直接过滤掉。

然后就是创建叶子级别的catgr对象,继承父节点的优先级和目的地

如果没有创建根对象,直接使用getInstance创建叶对象,会先隐式地创建一个Root对象。

通过.来显示分级

后面的sub1代表日志的来源,也就是输出在终端的字符串内容

如果修改节点的写入目的地,那么会将信息写入到自定义的文件中。

如果是root对象调用的就只是保存到root的目的地,如果(子节点继承根节点目的地时)是sub子节点对象那么根节点和子节点的目的地都保存。

也可以设置不同目的地不同日志文件系统级别。

有四种形式可以写入终端

直接调用函数

//sub1.error()

函数+流的方式

#include "log4cpp/OstreamAppender.hh"
#include "log4cpp/Layout.hh"
#include "log4cpp/BasicLayout.hh"
#include "log4cpp/Priority.hh"//Category 日志记录器                                                                          
//Appender 表示输出器目的地
//Layout 表示显示格式格式化器
//Priority 表示优先级过滤器int main(int argc, char** argv) {log4cpp::Appender *appender1 = new log4cpp::OstreamAppender("console", &std::cout);//OstreamAppender 是Appender的派生类//其中的第一个参数只是给用户看的,内容是什么无关紧要,“console”表示控制台也就是屏幕终端显示//第二个参数很重要表示将打印信息输出到的位置appender1->setLayout(new log4cpp::BasicLayout());//本行命令表示的是输出格式BasicLayout表示的是将时间输出为从19701月1号开始的的秒数//一般我们不会使用这个,因为秒数不能很好的辨识时间log4cpp::Appender *appender2 = new log4cpp::FileAppender("default", "program.log");//同上只是表示将输出写到日志文件program.log中//注意这样是以追加的方式写入appender2->setLayout(new log4cpp::BasicLayout());log4cpp::Category& root = log4cpp::Category::getRoot();//创建category对象的时候首先先创建一个单例的root对象,//并在下面的语句中设置根对象的系统级别以及输出目的地root.setPriority(log4cpp::Priority::WARN);root.addAppender(appender1);//设置叶节点,前面的&引用sub1就是表示返回一个在栈上的这个节点,                        //后面的这个sub1就是用于打印的时候显示//并且设置目的输出地,当然也可以额外设置输出的系统等级,如果都不设置的话都是跟随根节点//当然可以不创建root节点直接创建叶节点,系统会自动隐式创建一个根节点log4cpp::Category& sub1 = log4cpp::Category::getInstance(std::string("sub1"));
//og4cpp::Category& sub1 = log4cpp::Category::getInstance(std::string("sub1.sub11"));
//这样就可以在sub1下面实现再连接一个sub11叶节点sub1.addAppender(appender2);// use of functions for logging messagesroot.error("root error");//ok等级大于warn会被输出到根节点设置的屏幕root.info("root info");//error等级低sub1.error("sub1 error");//ok等级足够,会被同时打印到根节点设置的屏幕和叶节点设置的文件sub1.warn("sub1 warn");//ok等级足够会被输出到文件中去和屏幕中// printf-style for logging variablesroot.warn("%d + %d == %s ?", 1, 1, "two");// use of streams for logging messagesroot << log4cpp::Priority::ERROR << "Streamed root error";root << log4cpp::Priority::INFO << "Streamed root info";sub1 << log4cpp::Priority::ERROR << "Streamed sub1 error";sub1 << log4cpp::Priority::WARN << "Streamed sub1 warn";// or this way:root.errorStream() << "Another streamed error";return 0;}

【注意】这个地方可以将前面的一大长串的变量设置为auto类型。这个地方更加深入了解auto,auto是可以推导出变量类型,也可以推导出指针类型。但是auto不能推导出引用类型。

log4cpp官网 Log for C++ Project

日志目的地

主要关注三个目的地类分别是

• OstreamAppender C++通用输出流(如 cout)

• FileAppender 写到本地文件中

• RollingFileAppender 写到回卷文件中

  • OstreamAppender的构造函数传入两个参数:目的地名(随便写)、输出流指针
  • FileAppender的构造函数传入两个参数:目的地名、保存日志的文件名(后面两个参数使用默认值即可,分别表示以结尾附加的方式的保存日志,当前用户读写-其他用户只读)

RollingFileAppender使用场景就是比如说是因为系统不断产生文件,如果对于存储空间不加限制会大量的占用空间,所以说划分一块区域保存最新的一部分日志文件

【注意】RollingFileAppender构造函数的参数如上图,其中要注意的是回卷文件个数,如果这一位传入的参数是9,那么实际上会有10个文件保存日志。

回卷的机制是:先生成一个wd.log文件,该文件存满后接着写入日志,那么wd.log文件改名为wd.log.1,然后再创建一个wd.log文件,将日志内容写入其中,wd.log文件存满后接着写入日志,wd.log.1文件改名为wd.log.2,wd.log改名为wd.log.1,再创建一个wd.log文件,将最新的日志内容写入。以此类推,直到wd.log和wd.log.1、wd.log.2、... wd.log.9全都存满后再写入日志,wd.log.9(其中实际上保存着最早的日志内容)会被舍弃,编号在前的回卷文件一一进行改名,再创建新的wd.log文件保存最新的日志信息。

日志布局

本来的默认布局时BasicLayout,这种方式是表示距离1970.1.1的秒数不方便观察。

因此调用的时候可以使用PatrrenLayout对象来定制化格式

设置日志布局的方式

PatternLayout * ptn1 = new PatternLayout();
ptn1->setConversionPattern("%d %c [%p] %m%n"); 

该字符串的含义:

%d %c [%p] %m%n

时间 模块名 优先级 消息本身 换行符

【注意】日志系统有多个日志目的地的时候,每一个目的地Appender都需要设置一个布局Layout(一对一的关系)

日志记录器

创建category对象时,可以先使用getRoot创建root模块对象,对于root模块对象设置优先级和目的地。

再用getInstance创建叶模块,叶模块会继承root模块的优先级和目的地,当然也可以重新设置

如果没有创建根对象直接使用getInstance创建叶对象,会隐式创建一个跟对象

//官网示例分开创建的方式
log4cpp::Category& root = log4cpp::Category::getRoot();
root.setPriority(log4cpp::Priority::WARN);
root.addAppender(appender1);log4cpp::Category& sub1 = log4cpp::Category::getInstance(std::string("sub1")); //传入的字符串sub1就会是日志中记录下的日志来源
sub1.addAppender(appender2);
//直接创建叶对象的方式
log4cpp::Category& sub1 = log4cpp::Category::getRoot().getInstance("salesDepart"); //记录的日志来源会是salesDepart
sub1.setPriority(log4cpp::Priority::WARN);
sub1.addAppender(appender1);

前面的sub1本质是绑定到category的引用,在代码中可以使用sub1设置优先级添加目的地以及记录日志。

getIInstance中的参数salesDepart表示的是日志信息中记录的category的名称,也就是打印信息中的日志来源对应%c

在使用的时候这两者的名称取同一个名称,可以清楚该日志是来自于salesDepart这个模块

日志优先级

主要注意两个优先级分别是日志记录器的优先级(即系统优先级)和日志的优先级(某一条日志信息的优先级)。

只有当日志信息的优先级高于等于系统的优先级的时候,这一条日志信息才会被打印出来,否则这条日志会被过滤掉。

class LOG4CPP_EXPORT Priority {
public:typedef enum {EMERG = 0,FATAL = 0,ALERT = 100,CRIT = 200,ERROR = 300,WARN = 400,NOTICE = 500,INFO = 600,DEBUG = 700,NOTSET = 800 //这个不代表可以使用的优先级} PriorityLevel;//......
};  //数值越小,优先级越高;数值越大,优先级越低

日志布局:

PatternLayout * ptn1 = new PatternLayout();
ptn1->setConversionPattern("%d %c [%p] %m%n"); 

%d %c [%p] %m%n

时间 模块名 优先级 消息本身 换行符

%d设置时间地格式

头文件:输出到终端

使用自定义格式地头文件

记录器,过滤器

【了解】如果是使用根节点的话那么在布局中%c位置就不会有打印信息。

【重点】前面的sub1是用来进行使用接下来的绑定操作,在后面的sub1用来显示打印信息,同时还有显示父子叶节点关系“(后面的)sub1.sub11”。注意这个地方是用的后面的sub1!!子节点的信息不仅会打印到自己的输出位置中,还需要输出到父节点的输出目的地中。

表示通过getRoot创建根节点,通过getInstance创建叶节点。

也可以不加上getroot这样的话就就隐式的创建根节点。

这样做的话可能需要再额外定义一个root节点才能再继续进行操作根节点,

3.结束以后基本就将所有的信息绑定在一起

【了解】1.log4cpp在设计的时候有一个bug就是enum设计两个类型都是一个0表示都会视为下面那个fatal,反正这两种都是需要立即进行执行

2. 了解官网给的版本就是没有shutdown函数,但是可能也不会有内存泄漏,也有可能泄漏进行了优化。

日志目的地

【注意】shutdown回收资源,对于delete的封装,无论在日志系统中前面new多少次的话。

【重点】需要将目的地和格式绑定,然后将记录器和目的地绑定,记得两次绑定

布局对象和目的地对象需要一一对应,这样的话不会出现段错误

创建目的地的对象是文件对象的时候,可以有两种方式:

一种是通过oftream ofs。绑定在原本的&cout位置。当然也可以使用fileAppender,直接相应的位置输入文件名字符串

【注意】日志文件在fileAppender方式下,是以追加的方式进行添加

日志文件在OstreamAppender方式下,是以截断添加的方式添加

还有一种文件目的地,就是回卷文件

就是将空间分为几个文件,然后不断循环保存最新的内容

例如:下例中就是最新的文件一直都是wd.log

先生成一个wd.log文件,该文件存满后接着写入日志,那么wd.log文件改名为wd.log.1,然后再创建一个wd.log文件,将日志内容写入其中,wd.log文件存满后接着写入日志,wd.log.1文件改名为wd.log.2,wd.log改名为wd.log.1,再创建一个wd.log文件,将最新的日志内容写入。以此类推,直到wd.log和wd.log.1、wd.log.2、... wd.log.9全都存满后再写入日志,wd.log.9(其中实际上保存着最早的日志内容)会被舍弃,编号在前的回卷文件一一进行改名,再创建新的wd.log文件保存最新的日志信息。

【注意】回卷文件的个数如果是是5,实际的文件的个数就是6

log4cpp主要是使用category这个引用对象,所以说在private的位置保存一个category的引用。

【重点】获取文件名称和调用函数以及所在的列数的时候,使用的时候c的宏,这个处理是是在预处理阶段来实现的,所以说这个拼接字符串的操作是不能使用普通的函数的这样的话只会显示这个定义拼接字符串函数的文件和行号。可能会想到inline进行替换但是是在编译阶段实现使用的_FILE_是在,

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BarTender软件下载附加详细安装教程

BarTender是美国海鸥科技推出的一款优秀的条码打印软件&#xff0c;应用于 WINDOWS95 、 98 、 NT 、 XP 、 2000 、 2003 和 3.1 版本&#xff0c; 产品支持广泛的条形码码制和条形码打印机&#xff0c; 不但支持条形码打印机而且支持激光打印机&#xff0c;还为世界知名品牌条…

C语言 指针——字符数组与字符指针:字符串的表示与存储

目录 字符串常量 字符串变量&#xff1f; 字符数组的定义和初始化 字符指针的定义和初始化 将字符指针指向一个字符串 用字符数组保存一个字符串 将字符指针指向一个字符数组 使用字符指针的基本原则 使用指针的基本原则 字符串常量 字符串变量&#xff1f;  C 语言…

Steam下载游戏很慢?一个设置解决!

博主今天重装系统后&#xff0c;用steam下载发现巨慢 500MB&#xff0c;都要下载半小时。 平时下载软件&#xff0c;一般1分钟就搞定了&#xff0c;于是大致就知道&#xff0c;设置应该出问题了 于是修改了&#xff0c;如下设置之后&#xff0c;速度翻了10倍。 另外&#x…

神经网络 torch.nn---Convolution Layers

torch.nn — PyTorch 2.3 documentation torch.nn - PyTorch中文文档 (pytorch-cn.readthedocs.io) torch.nn和torch.nn.functional的区别 torch.nn是对torch.nn.functional的一个封装&#xff0c;让使用torch.nn.functional里面的包的时候更加方便 torch.nn包含了torch.nn.…

随心笔记,第六更

目录 一、 三步构建 XML转成java bean 1.XML转XSD 2.XSD转JavaBean 3.jaxb 工具类 4.测试 &#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是「Leen」。刚工作几年&#xff0c;想和大家一同进步&am…

从零开始手把手Vue3+TypeScript+ElementPlus管理后台项目实战十(整体布局03之界面美化)

删除style.css 删除style.css(和main.ts同级) 并且注释掉main.ts中对style.css的导入。 修改App.vue 添加样式设置高度100% 安装sass pnpm install -D sass修改PageSidebar.vue 修改index.vue 修改src/layout/index.vue src/layout/index.vue添加样式 <style lang&quo…

pyinstaller打包exe多种失败原因解决方法

pyinstaller打包exe多种失败原因解决方法 目录 pyinstaller打包exe多种失败原因解决方法1、pyinstaller安装有问题1.1 安装pyinstaller1.2 采用anconda的环境启动 2、pyqt5与pyside6冲突2.1 打包生成.spec文件2.2 编辑spec文件 3、打包成功后打不开exe&#xff0c;exe闪退3.1 s…

用表头设置控制表格内列的排序和显示隐藏

项目背景 : react ant 需求 : 点击表头设置弹窗 , 拖拽可控制外部表格列的排序 , 开关可控制外部表格列的显示和隐藏 实现效果如下 :注意 : 1. 拖拽效果参考了ant-table中的拖拽效果(这块代码放最后) 2. 后台反了json格式(用is_show控制显示和隐藏 , 我给他传…

把Vue文件转至树莓派上遇到的问题和解决方案

把整个文件夹复制进树莓派后&#xff0c;运行 npm run dev ,报错sh: 1: vite: Permission denied 解决方案&#xff1a;删除项目里的 node_modules 重新 npm install 再运行即可 rm -rf node_modules/ npm install 在安装过程中&#xff0c;遇到下图问题&#xff0c;vulnerabi…

一二三应用开发平台应用开发示例(2)——创建应用、模块、实体及配置模型

创建应用 文档管理系统对于开发平台是一个业务应用。 业务应用是通过平台内置的数据字典来维护的&#xff0c;因此访问系统管理模块下的数据字典管理功能&#xff0c;在实体配置分组下找到“应用编码”&#xff0c;点击行记录上的“字典项”。 在打开的新窗口中&#xff0c;在…

CTFHUB-SQL注入-MySQL结构

目录 sqlmap工具夺flag 查看数据库名 查看数据库中表名 查看第一个表中数据 查看第二个表的数据 手动注入 判断是否存在注入 判断字段数量 查询注入点 查询数据库版本 查询数据库名 查看所有数据库 查看表名 查看表中字段 查看表中数据 本题用到sqlmap工具&…

采用ava+B/S架构开发的工业级UWB(Ultra-Wideband)室内定系统源码UWB定位系统技术接口及技术特点

采用avaB/S架构开发的工业级UWB&#xff08;Ultra-Wideband&#xff09;室内定系统源码UWB定位系统技术接口及技术特点 UWB&#xff08;Ultra-Wideband&#xff09;定位技术本身并不直接连接蓝牙或其他无线通信技术进行定位。然而&#xff0c;在实际应用中&#xff0c;UWB定位技…

鸿蒙轻内核A核源码分析系列五 虚实映射(5)虚实映射解除

虚实映射解除函数LOS_ArchMmuUnmap解除进程空间虚拟地址区间与物理地址区间的映射关系&#xff0c;其中参数包含MMU结构体、解除映射的虚拟地址和解除映射的数量count,数量的单位是内存页数。 ⑴处函数OsGetPte1用于获取指定虚拟地址对应的L1页表项数据。⑵处计算需要解除的无效…

使用MATLAB对地铁站、公交站等求解最短路径

使用MATLAB对城市的地铁站、公交站等站点&#xff0c;根据站点的经纬度坐标和彼此之间的权重&#xff0c;求解其最短路径、途径站点和路程 已知的数据如图&#xff0c;是西安市地铁站点的数据&#xff0c;保存在一个Excel里 如图&#xff0c;每列的内容都在上面&#xff0c;不…

Go singlefight 源码详解|图解

写在前面 通俗的来说就是 singleflight 将相同的并发请求合并成一个请求&#xff0c;进而减少对下层服务的压力&#xff0c;通常用于解决缓存击穿的问题。 详解 基础结构 golang.org/x/sync/singleflight singleflight结构体&#xff1a; type call struct {wg sync.WaitGro…

Tabby:一款革新的Mac/Win现代化终端模拟器

在信息技术日新月异的今天&#xff0c;终端操作已成为众多开发者、系统管理员和技术爱好者的日常必备工具。然而&#xff0c;传统的终端模拟器往往功能单一、界面陈旧&#xff0c;无法满足用户对于高效、便捷操作体验的追求。Tabby应运而生&#xff0c;作为一款现代化、功能强大…

基于多传感器数据和周期性采样的滚动轴承故障诊断方法(Python)

代码较为简单&#xff0c;算法结构如下&#xff1a; from scipy.io import loadmat import numpy as np import os from sklearn import preprocessing # 0-1编码 import torch from torch.utils import data as da# 用训练集标准差标准化训练集以及测试集 def scalar_stand(d…

【Android面试八股文】1. 你说一说Handler机制吧 2. 你知道Handler的同步屏障吗? 3. Looper一直在循环,会造成阻塞吗?为什么?

文章目录 一. 你说一说Handler机制吧二、你知道Handler的同步屏障吗&#xff1f;2.1 Handler消息的分类2.2 什么是同步屏障2.3 为什么要设计同步屏障2.4 同步屏障的用法 三、Looper一直在循环&#xff0c;会造成阻塞吗&#xff1f;为什么&#xff1f;扩展阅读 一. 你说一说Hand…

现货黄金交易多少克一手?国内外情况大不同

如果大家想参与国际市场上的现货黄金交易&#xff0c;就应该从它交易细则的入手&#xff0c;先彻底认识这个品种&#xff0c;因为它是来自欧美市场的投资方式&#xff0c;所以无论是从合约的计的单位&#xff0c;计价的货币&#xff0c;交易的具体时间&#xff0c;以及买卖过程…

AI大模型在健康睡眠监测中的深度融合与实践案例

文章目录 1. 应用方案2. 技术实现2.1 数据采集与预处理2.2 构建与训练模型2.3 个性化建议生成 3. 优化策略4. 应用示例&#xff1a;多模态数据融合与实时监测4.1 数据采集4.2 实时监测与反馈 5. 深入分析模型选择和优化5.1 LSTM模型的优势和优化策略5.2 CNN模型的优势和优化策略…