日志的编写与线程池的结合

目录

一、认识日志 

二、时间的等级划分 

三、日志的输出端 

3.1 保存至文件

 四、日志的部分信息

4.1 日志等级

4.2 日志时间 

五、加载日志

六、日志的宏编写 

七、ThreadPool + Log


一、认识日志 

  1. 记录事件: 日志用于记录系统运行过程中发生的各种事件,包括错误、警告、信息和调试信息等。通过这些记录,可以了解系统在某一时刻的具体状态和行为。

  2. 问题诊断: 当系统出现故障或异常时,通过查看日志可以追踪问题的发生原因、定位错误源头,从而快速解决问题。详细的日志信息能够帮助开发人员和运维人员理解问题的背景和上下文。

  3. 性能监控: 日志可以记录系统的性能数据,如处理时间、响应时间和资源使用情况等。这些信息对于监控系统性能和优化系统效率非常重要。

  4. 安全审计: 日志记录用户操作、系统访问和安全事件等信息,可以用于安全审计和合规性检查,确保系统的安全性和合规性。

  5. 运行分析: 通过分析日志数据,可以发现系统运行中的趋势、模式和潜在问题,从而做出更好的决策和改进系统设计。

  6. 调试和开发: 在开发和测试过程中,日志信息可以帮助开发人员了解代码执行流程和程序状态,便于调试和优化代码。

总之,日志在系统运行、维护、开发和安全等各个方面都起着非常重要的作用,是确保系统稳定性、可靠性和安全性的重要手段。

二、时间的等级划分 

后续通过日志的等级,就可以选择后续操作,例如直接退出、继续执行等。 

enum Level
{DEBUG = 0,INFO,WARNING,ERROR,FATAL
};

三、日志的输出端 

日志可以向显示器中输入,也可以向某文件中输入。

3.1 保存至文件

C++根据文件内容的数据格式分为二进制文件和文本文件。
采用文件流对象操作文件的一般步骤:
1. 定义一个文件流对象
        ifstream ifile(只输入用)
        ofstream ofile(只输出用)
        fstream iofile(既输入又输出用)
2. 使用文件流对象的成员函数打开一个磁盘文件,使得文件流对象和磁盘文件之间建立联系
3. 使用提取和插入运算符对文件进行读写操作,或使用成员函数进行读写
4. 关闭文件 

bool gIsSave = false;//后续通过IsSave选择是否保存到文件
const std::string logname = "log.txt";
void SaveFile(const std::string &filename, const std::string &message)
{std::ofstream out(filename, std::ios::app);if (!out.is_open())return;out << message;out.close();
}

 四、日志的部分信息

4.1 日志等级

首先要明确一点,日志是要输出给读者看的,我们枚举的日志等级毕竟还是整型,输出后也会导致读者看不懂的问题,所以就需要有一个函数将对应的枚举类型转化成字符串,以便于后续的输出:

std::string LevelToString(int level)
{switch (level){case DEBUG:return "Debug";case INFO:return "Info";case WARNING:return "Warning";case ERROR:return "Error";case FATAL:return "Fatal";default:return "Unknown";}
}

4.2 日志时间 

日志的名称也能看出其带有很强的时间属性,所以在日志中获取操作的时间也是必不可少的操作。

这里介绍几个C++中与时间有关的概念,包括数据类型、结构体、函数等:

time_t :表述时间的数据类型

struct tm : 包含时间的各个单位的结构体,如下图,第一列为结构体成员,第二列为成员的数据类型,第三列为成员的意义,第四列为成员的取值范围。
其中,特别说明的是 tm_year 与 tm_mon ,它们分别表示的是从1900年后到现在的年数与此时的月份数,但是是从零开始的,所以在输出时,tm_year一般+1900,tm_mon一般+1。

time : 输出型参数,获取当前时间赋值给传入的 time_t 类型的变量

localtime : 返回一个struct tm 的结构体,可以将传入的 time_t 类型变量的值,依次赋值给结构体成员。

下面附上我粗鄙的理解:定义了一个 time_t 类型的变量 curr_time ,使用 time 可以将当前时间赋值给 curr_time ,假设当前时间为2024/7/16 21:48,那么curr_time中可能是一系列连续的数字标识当前时间,例如是202407162148,这样比较粗鄙,猜想系统中的机制肯定更复杂,是很不适合读者去读的,localtime 就可以将该串转化成年=2024,月=7,日=16(事实肯定不是这样因为年是从1900开始,月从0开始,但是这样说比较好理解)......然后就比较方便读者阅读了。

std::string GetTimeString()
{time_t curr_time = time(nullptr);struct tm *format_time = localtime(&curr_time);if (format_time == nullptr)return "None";char time_buffer[1024];snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",format_time->tm_year + 1900, format_time->tm_mon + 1,format_time->tm_mday,format_time->tm_hour,format_time->tm_min,format_time->tm_sec);return time_buffer;
}

五、加载日志

这里采用的类似C语言 printf 的传入参数。

va_listva_startva_endvsnprintf:

  • 用于处理可变参数列表的 C 标准库函数。
  • va_list arg:声明一个可变参数列表变量。
  • va_start(arg, format):初始化可变参数列表,从 format 开始。
  • vsnprintf(buffer, sizeof(buffer), format, arg):将可变参数格式化为字符串并存储到 buffer 中。
  • va_end(arg):结束可变参数列表的处理。
void LogMessage(std::string filename, int line, bool issave, int level, const char *format, ...)
{std::string levelstr = LevelToString(level);std::string timestr = GetTimeString();pid_t selfid = getpid();char buffer[1024];va_list arg;va_start(arg, format);vsnprintf(buffer, sizeof(buffer), format, arg);va_end(arg);std::string message = "[" + timestr + "]" + "[" + levelstr + "]" +"[" + std::to_string(selfid) + "]" +"[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer;LockGuard lockguard(&lock);if (!issave)std::cout << message;elseSaveFile(logname, message);
}

六、日志的宏编写 

do while(0)常用于宏定义中代码块的定义,__FILE__, __LINE__都是系统提供的,可以输出当前文件与当前行,此时再使用宏调用日志就简单多了。

#define LOG(level, format, ...)                                                \do                                                                         \{                                                                          \LogMessage(__FILE__, __LINE__, gIsSave, level, format, ##__VA_ARGS__); \} while (0)#define EnableFile()    \do                  \{                   \gIsSave = true; \} while (0)
#define EnableScreen()   \do                   \{                    \gIsSave = false; \} while (0)
LOG(INFO, "%s is quit...\n", thread.name().c_str());

七、ThreadPool + Log

注意,这里日志打印形式纯属个人意愿,而且需要打印出线程名的话,ThreadPool 的相关函数的传参也会进行修改,请注意甄别。

#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <unistd.h>
#include <pthread.h>
#include "Thread.hpp"
#include "Log.hpp"
using namespace ThreadModule;
const static int gdefaultthreadnum = 3;template <typename T>
class ThreadPool
{
private:void LockQueue(){pthread_mutex_lock(&_mutex);}void UnlockQueue(){pthread_mutex_unlock(&_mutex);}void ThreadSleep(){pthread_cond_wait(&_cond, &_mutex);}void ThreadWakeup(){pthread_cond_signal(&_cond);}void ThreadWakeupAll(){pthread_cond_broadcast(&_cond);}
public:ThreadPool(int threadnum = gdefaultthreadnum) : _threadnum(threadnum), _waitnum(0), _isrunning(false){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_cond, nullptr);LOG(INFO, "ThreadPool Construct()\n");}void HandlerTask(std::string name){LOG(INFO, "%s is running...\n", name.c_str());while (true){LockQueue();while (_task_queue.empty() && _isrunning){_waitnum++;ThreadSleep();_waitnum--;}if (_task_queue.empty() && !_isrunning){UnlockQueue();break;}T task = _task_queue.front();_task_queue.pop();UnlockQueue();LOG(DEBUG, "%s get a task", name.c_str());task();LOG(DEBUG, "%s handler a task, result is: %s\n", name.c_str(), t.ResultToString().c_str());}}void InitThreadPool(){for (int num = 0; num < _threadnum; num++){std::string name = "thread- " + std::to_string(num + 1);_threads.emplace_back(std::bind(&ThreadPool::HandlerTask, this, std::placeholders::_1), name);LOG(INFO, "init thread %s done\n", name.c_str());}_isrunning = true;}void Start(){for (auto &thread : _threads){thread.Start();}}void Stop(){LockQueue();_isrunning = false; // 线程池退出ThreadWakeupAll();UnlockQueue();}void Wait(){for (auto &thread : _threads){thread.Join();LOG(INFO, "%s is quit...\n", thread.name().c_str());}}bool Enqueue(const T &task){bool ret = false;LockQueue();if (_isrunning){_task_queue.push(task);if (_waitnum > 0){ThreadWakeup();}LOG(DEBUG, "enqueue task success\n");ret = true;}UnlockQueue();return ret;}~ThreadPool(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_cond);}private:int _threadnum;std::vector<Thread> _threads;std::queue<T> _task_queue;pthread_mutex_t _mutex;pthread_cond_t _cond;int _waitnum;bool _isrunning;
};

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

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

相关文章

elementui 日历组件el-calendar使用总结

功能&#xff1a; 1.日历可以周视图、月视图切换&#xff1b; 2.点击月视图中日期可以切换到对应周视图&#xff1b; 3.点击周视图查看当日对应数据&#xff1b; 4.周、月视图状态下&#xff0c;点击前后按钮&#xff0c;分别切换对应上下的周、月&#xff1b; 5.点击回到…

算法 —— 高精度(模拟)

目录 加法高精度 两个正整数相加 两个正小数相加 两正数相加 减法高精度 两个正整数相减 两个正小数相减 两正数相减 加减法总结 乘法高精度 两个正整数相乘 两个正小数相乘 乘法总结 加法高精度 题目来源洛谷&#xff1a;P1601 AB Problem&#xff08;高精&#x…

如何PR到别人仓库(指定分支,无废话)

如何PR到别人仓库&#xff08;指定分支&#xff09; 记录一下&#xff0c;之前都是直接master分支&#xff0c;现在记录如何pr到别人仓库的其他分支 首先进入别人仓库然后点击fork到自己仓库 步骤&#xff08;以博主自己一个例子为例&#xff09; &#xff08;1&#xff09;…

c++ primer plus 第16章string 类和标准模板库,16.1.3 使用字符串

c primer plus 第16章string 类和标准模板库,16.1.3 使用字符串 c primer plus 第16章string 类和标准模板库,16.1.3 使用字符串 文章目录 c primer plus 第16章string 类和标准模板库,16.1.3 使用字符串16.1.3 使用字符串程序清单16.3 hangman.cpp 16.1.3 使用字符串 现在&a…

【题目/训练】二叉树的创建遍历(递归非递归)

一、根据二叉树创建字符串 思路&#xff1a;在正常前序递归遍历的基础上&#xff0c;单独加上一个考虑到右子树为空的情况&#xff0c;如下&#xff1a;其结果为 1&#xff08;2&#xff08;4&#xff08;5&#xff09;&#xff08;6&#xff09;&#xff09;&#xff09;&…

馥郁珍藏:品味红酒的层次与细腻

在生活的点滴中&#xff0c;总有一些事物以其不同的魅力&#xff0c;让我们为之驻足&#xff0c;为之沉醉。红酒&#xff0c;便是其中之一。它不仅仅是一种饮品&#xff0c;更是一种情感的寄托&#xff0c;一种生活的艺术。今天&#xff0c;就让我们一起走进红酒的世界&#xf…

工控主板:搭载海光3300处理器的全国产化工控主板

最近为客户定做了一款全国产化的工控机主板。搭载海光3300核心板的含有丰富接口的工控主板。

一张图生成绘画全过程,这下人人都成“原画师”了

玩过SD的应该都知道ControlNet吧&#xff0c;最近ControlNet的作者Lvmin Zhang 又搞了一个开源项目PaintsUndo&#xff0c;在Github刚上线就收获了2.7k Star。 只需要上传一张静态图像&#xff0c;PaintsUndo就可以根据提供的图像自动生成对应的绘画全过程视频。 展示从一张白…

linux中关于环境变量的常用的设置方法

一. linux中设置环境变量的方式 1.使用/etc/environment, 是一个全局的环境变量设置文件&#xff0c;它会影响到所有用户和所有进程。当你需要设置一个全局的环境变量时&#xff0c;应该使用这个文件。这个文件的格式是 KEYvalue&#xff0c;每行一个环境变量。 2. 使用/etc/…

C# Winform的三态CheckBox,以及批量修改Panel中的控件

在C# WinForms中&#xff0c;如果你想批量修改一个Panel容器内的所有CheckBox控件的状态&#xff0c;你可以使用foreach循环来遍历Panel的Controls集合。下面是一个示例&#xff0c;展示了如何将一个Panel内所有的CheckBox控件设为选中状态&#xff08;Checked true&#xff0…

昇思25天学习打卡营第13天|munger85

文本解码原理–以MindNLP为例 重要的就是怎么样把数字最后转化成真正的文字。而且自回归模型它会一个字给一个字的预测&#xff0c;下一个字应该是什么&#xff1f; 如果这个模型下载很慢&#xff0c;你就可以通过这种方式从摩大社区进行下载。 这种方式&#xff0c; 每一次候…

如何让LabVIEW程序框图的图标简化,从而节省空间?

再点击选项 取消掉箭头所示的√即可。 这样就可以将生成的图标从下面所示&#xff1a; 变成简化的图标&#xff0c;如下所示&#xff1a;

【Pytorch】数据集的加载和处理(一)

Pytorch torchvision 包提供了很多常用数据集 数据按照用途一般分为三组&#xff1a;训练&#xff08;train&#xff09;、验证&#xff08;validation&#xff09;和测试&#xff08;test&#xff09;。使用训练数据集来训练模型&#xff0c;使用验证数据集跟踪模型在训练期间…

安全防御拓扑1

目录 实验的拓扑&#xff1a; 要求&#xff1a; 我搭建的实验拓扑 步骤&#xff1a; 创建vlan&#xff1a; 接口配置&#xff1a; 防火墙&#xff1a; 防火墙配置&#xff1a; 建立安全策略&#xff1a; 防火墙的用户&#xff1a; 办公区的市场部和研发部用户 市场部…

杰发科技AC7801 —— __attribute__指定地址存储常量

const uint8_t usFlashInitVal[] __attribute__((at(0x08002800))) {0x55,0x55,0x55,0x55,0x55};//定位在flash中&#xff0c;0x00030000开始的6个字节信息固定 注意7801的地址在8000000之后 如地址选0x00000800烧录时候报错 不知道是不是atclinktool的bug&#xff0c;使用_…

勒索防御第一关 亚信安全AE防毒墙全面升级 勒索检出率提升150%

亚信安全信舷AE高性能防毒墙完成能力升级&#xff0c;全面完善勒索边界“全生命周期”防御体系&#xff0c;筑造边界勒索防御第一关&#xff01; 勒索之殇&#xff0c;银狐当先 当前勒索病毒卷携着AI技术&#xff0c;融合“数字化”的运营模式&#xff0c;形成了肆虐全球的网…

数据结构(4.4)——求next数组

next数组的作用:当模式串的第j个字符失配时&#xff0c;从模式串的第next[j]的继续往后匹配 求模式串的next数组(手算) next[1] 任何模式串都一样&#xff0c;第一个字符不匹配时&#xff0c;只能匹配下一个子串&#xff0c;因此&#xff0c;往后&#xff0c;next[1]都无脑写…

Classifier-Free Guidance (CFG) Scale in Stable Diffusion

1.Classifier-Free Guidance Scale in Stable Diffusion 笔记来源&#xff1a; 1.How does Stable Diffusion work? 2.Classifier-Free Diffusion Guidance 3.Guide to Stable Diffusion CFG scale (guidance scale) parameter 1.1 Classifier Guidance Scale 分类器引导是…

达梦数据库的系统视图v$dict_cache_item

达梦数据库的系统视图v$dict_cache_item 在达梦数据库&#xff08;DM Database&#xff09;中&#xff0c;V$DICT_CACHE_ITEM 是一个系统视图&#xff0c;用于显示字典缓存&#xff08;Dictionary Cache&#xff09;中的项信息。字典缓存是数据库中的一个重要组件&#xff0c;…

RepLKNet(CVPR 2022, MEGVII)

paper&#xff1a;Scaling Up Your Kernels to 31x31: Revisiting Large Kernel Design in CNNs official implementation&#xff1a;https://github.com/DingXiaoH/RepLKNet-pytorch 背景 卷积神经网络&#xff08;CNN&#xff09;曾经是现代计算机视觉系统中的常见选择。…