C++日志管理从基础到完善

C++日志管理从基础到完善
万古教员有名言,自信人生二百年。
个人主页:oioihoii
喜欢内容的话欢迎关注、点赞、收藏!感谢支持,祝大家祉猷并茂,顺遂无虞
在这里插入图片描述

版本一:基础日志代码

在设计C++日志系统时,我们需要考虑以下几个关键点:

  1. 易用性:日志系统应该易于使用,开发者应该能够轻松地添加日志条目。
  2. 性能:日志系统应该尽可能地减少对应用程序性能的影响。这意味着日志记录的过程应该尽可能地快速,以减少对应用程序的延迟。
  3. 灵活性:日志系统应该能够支持不同级别的日志(如错误、警告、信息、调试等),并能够在运行时动态地更改日志级别。
  4. 可配置性:日志系统应该允许开发者配置日志的各种参数,如日志文件的位置、日志的格式等。
  5. 线程安全:如果应用程序是多线程的,那么日志系统也必须是线程安全的。

下面是一个简单的C++日志系统的设计,它考虑了上述的所有因素:

#include<iostream>#include<fstream>#include<mutex>#include<memory>enumclassLogLevel{ ERROR, WARNING, INFO, DEBUG };classLogger{public:Logger(const std::string& file_name){ file_stream_.open(file_name, std::ios::out | std::ios::app);}~Logger(){ file_stream_.close();}voidLog(LogLevel level,const std::string& message){ std::lock_guard<std::mutex>lock(mutex_);switch(level){case LogLevel::ERROR: file_stream_ <<"[ERROR] ";break;case LogLevel::WARNING: file_stream_ <<"[WARNING] ";break;case LogLevel::INFO: file_stream_ <<"[INFO] ";break;case LogLevel::DEBUG: file_stream_ <<"[DEBUG] ";break;} file_stream_ << message << std::endl;}private: std::ofstream file_stream_; std::mutex mutex_;};intmain(){auto logger = std::make_shared<Logger>("log.txt"); logger->Log(LogLevel::INFO,"This is an info message"); logger->Log(LogLevel::ERROR,"This is an error message");return0;}

在这个设计中,我们使用了一个std::ofstream对象来写入日志文件,使用了一个std::mutex对象来确保线程安全,使用了一个枚举类LogLevel来表示不同的日志级别。我们的Log函数接受一个日志级别和一个消息,然后将它们写入日志文件。

这只是一个基础的日志系统设计,实际的日志系统可能会更复杂,例如,它可能会支持将日志发送到多个目的地(如文件、网络、控制台等),支持多种日志格式,支持日志轮转等。

版本二:考虑性能的进阶日志

对于大量日志的生成,确实需要考虑性能问题。频繁地打开和关闭文件会导致性能下降。在这种情况下,我们可以考虑以下优化:

  1. 缓冲日志消息:我们可以在内存中缓冲日志消息,然后在缓冲区满时一次性写入文件,而不是每次都打开和关闭文件。这可以大大提高性能,但是需要注意的是,如果程序崩溃,缓冲区中的日志消息可能会丢失。
  2. 异步写入:我们可以在一个单独的线程中写入日志文件,这样就不会阻塞主程序的执行。这需要更复杂的线程同步机制,但是可以进一步提高性能。

下面是一个改进的版本,使用了缓冲区和异步写入:

#include<iostream>#include<fstream>#include<mutex>#include<memory>#include<thread>#include<condition_variable>#include<queue>enumclassLogLevel{ ERROR, WARNING, INFO, DEBUG };classLogger{public:Logger(const std::string& file_name):exit_(false){ file_stream_.open(file_name, std::ios::out | std::ios::app); worker_ = std::thread(&Logger::writeLog,this);}~Logger(){ exit_ =true; cv_.notify_all(); worker_.join(); file_stream_.close();}voidLog(LogLevel level,const std::string& message){ std::lock_guard<std::mutex>lock(mutex_); log_queue_.push(std::make_pair(level, message)); cv_.notify_all();}private:voidwriteLog(){while(true){ std::unique_lock<std::mutex>lock(mutex_); cv_.wait(lock,[this]{return!log_queue_.empty()|| exit_;});while(!log_queue_.empty()){auto log = log_queue_.front(); log_queue_.pop();switch(log.first){case LogLevel::ERROR: file_stream_ <<"[ERROR] ";break;case LogLevel::WARNING: file_stream_ <<"[WARNING] ";break;case LogLevel::INFO: file_stream_ <<"[INFO] ";break;case LogLevel::DEBUG: file_stream_ <<"[DEBUG] ";break;} file_stream_ << log.second << std::endl;}if(exit_ && log_queue_.empty())break;}} std::ofstream file_stream_; std::mutex mutex_; std::condition_variable cv_; std::queue<std::pair<LogLevel, std::string>> log_queue_; std::thread worker_;bool exit_;};intmain(){auto logger = std::make_shared<Logger>("log.txt"); logger->Log(LogLevel::INFO,"This is an info message"); logger->Log(LogLevel::ERROR,"This is an error message");return0;}

在这个版本中,我们使用了一个std::queue来缓冲日志消息,使用了一个std::condition_variable来同步主线程和工作线程,使用了一个std::thread来执行日志写入。我们的Log函数将日志消息添加到队列中,然后通知工作线程。工作线程在收到通知后,会将队列中的所有日志消息写入文件。

版本三:添加定时删除的完整日志管理

要实现日志文件的定时清除功能,我们需要添加一些额外的代码来管理日志文件。以下是一个改进的版本,它会在每天的特定时间(例如午夜)创建一个新的日志文件,并删除30天前的日志文件:

#include<iostream>#include<fstream>#include<mutex>#include<memory>#include<thread>#include<condition_variable>#include<queue>#include<chrono>#include<filesystem>#include<iomanip>enumclassLogLevel{ ERROR, WARNING, INFO, DEBUG };classLogger{public:Logger(const std::string& dir,int days):exit_(false),dir_(dir),days_(days){ worker_ = std::thread(&Logger::writeLog,this);}~Logger(){ exit_ =true; cv_.notify_all(); worker_.join();}voidLog(LogLevel level,const std::string& message){ std::lock_guard<std::mutex>lock(mutex_); log_queue_.push(std::make_pair(level, message)); cv_.notify_all();}private:voidwriteLog(){while(true){ std::unique_lock<std::mutex>lock(mutex_); cv_.wait(lock,[this]{return!log_queue_.empty()|| exit_;});auto now = std::chrono::system_clock::now();auto date = std::chrono::system_clock::to_time_t(now); std::tm tm;localtime_s(&tm,&date); std::ostringstream oss; oss << dir_ <<"/"<< std::put_time(&tm,"%Y%m%d")<<".log";if(!file_stream_.is_open()|| oss.str()!= file_name_){ file_stream_.close(); file_name_ = oss.str(); file_stream_.open(file_name_, std::ios::out | std::ios::app);deleteOldLogs();}while(!log_queue_.empty()){auto log = log_queue_.front(); log_queue_.pop();switch(log.first){case LogLevel::ERROR: file_stream_ <<"[ERROR] ";break;case LogLevel::WARNING: file_stream_ <<"[WARNING] ";break;case LogLevel::INFO: file_stream_ <<"[INFO] ";break;case LogLevel::DEBUG: file_stream_ <<"[DEBUG] ";break;} file_stream_ << log.second << std::endl;}if(exit_ && log_queue_.empty())break;}}voiddeleteOldLogs(){auto now = std::chrono::system_clock::now();auto date = std::chrono::system_clock::to_time_t(now); std::tm tm;localtime_s(&tm,&date); tm.tm_mday -= days_;mktime(&tm); std::ostringstream oss; oss << dir_ <<"/"<< std::put_time(&tm,"%Y%m%d")<<".log"; std::filesystem::remove(oss.str());} std::ofstream file_stream_; std::mutex mutex_; std::condition_variable cv_; std::queue<std::pair<LogLevel, std::string>> log_queue_; std::thread worker_;bool exit_; std::string dir_; std::string file_name_;int days_;};intmain(){auto logger = std::make_shared<Logger>("logs",30); logger->Log(LogLevel::INFO,"This is an info message"); logger->Log(LogLevel::ERROR,"This is an error message");return0;}

在这个版本中,我们在writeLog函数中检查当前的日期,如果日期改变了,我们就创建一个新的日志文件,并删除30天前的日志文件。我们使用了C++17的std::filesystem库来删除文件。注意,这个代码只在支持C++17的编译器上有效。

这个代码的一个限制是,它假设日志文件的名字是按照"YYYYMMDD.log"的格式命名的。如果你的日志文件的命名规则不同,你需要修改writeLogdeleteOldLogs函数中的代码。

进一步探讨交流以及更多惊喜关注公众号联系我!再次欢迎关注、点赞、收藏,系列内容可以点击专栏目录订阅,感谢支持,祝大家祉猷并茂,顺遂无虞
若将文章用作它处,请一定注明出处,商用请私信联系我!

Read more

Python 与数据科学工具链入门:NumPy、Pandas、Matplotlib 快速上手

Python 与数据科学工具链入门:NumPy、Pandas、Matplotlib 快速上手

Python 与数据科学工具链入门:NumPy、Pandas、Matplotlib 快速上手 “工欲善其事,必先利其器。” ——在机器学习的世界里,你的“器”就是 Python 数据科学工具链。 一、为什么工具链如此重要? 想象你要做一道菜。即使你背熟了所有食谱,如果厨房里只有生锈的刀、没校准的秤、漏底的锅,你依然做不出好菜。 机器学习也是如此。 算法是“菜谱”,而 NumPy、Pandas、Matplotlib 就是你的“刀、秤、锅”——它们构成了现代数据科学工作的基础设施。 很多初学者一上来就急着学“神经网络”“梯度提升”,却连如何读取一个 CSV 文件都磕磕绊绊。结果是:想法很丰满,代码跑不动。 本篇文章的目标很明确: ✅ 让你在 2 小时内掌握三大核心库的基础用法; ✅ 能独立完成 数据加载 → 清洗

By Ne0inhk
Python 列表内存存储本质:存储差异原因与优化建议

Python 列表内存存储本质:存储差异原因与优化建议

文章目录 * 1. 问题引入:列表存储的内存 "膨胀" * 2. 理论存储与实际存储的差异 * 2.1 64位整数的存储差异 * 2.2 短字符串的存储差异 * 3. 列表的内存存储本质 * 3.1 相同元素列表内存少的核心原因:对象复用 * 3.1.1 小整数的缓存复用机制 * 3.1.2 字符串的驻留(Intern)机制 * 3.2 不同元素列表内存高的原因:对象重复创建 * 3.2.1 不同整数的内存开销 * 3.2.2 不同字符串的内存开销 * 4. 内存占用对比分析 * 5. 优化建议:利用对象复用减少内存开销 * 6. 总结

By Ne0inhk
[特殊字符] Python在CentOS系统执行深度指南

[特殊字符] Python在CentOS系统执行深度指南

文章目录 * 1 Python环境安装与配置问题 * 1.1 系统自带Python的限制 * 1.2 安装Python 3的常见问题及解决方案 * 1.3 SSL模块问题解决方案 * 1.4 环境变量配置与管理 * 1.5 软件集合(SCL)替代方案 * 2 包管理与虚拟环境问题 * 2.1 pip包管理器问题与解决方案 * 2.2 虚拟环境的最佳实践 * 2.3 依赖兼容性问题解决 * 2.4 虚拟环境目录结构理解 * 3 模块导入与路径问题 * 3.1 Python模块搜索路径机制 * 3.2 常见模块导入错误与解决 * 3.3 路径配置最佳实践 * 3.4 特殊模块问题处理 * 3.

By Ne0inhk
基于Python大数据旅游数据分析与推荐系统的爬虫 数据分析可视化系统

基于Python大数据旅游数据分析与推荐系统的爬虫 数据分析可视化系统

文章目录 * 摘要 * 技术亮点 * 项目简介 * 大数据系统开发流程 * 主要运用技术介绍 * 爬虫核心代码展示 * 结论 * 源码文档获取定制开发/同行可拿货,招校园代理 :文章底部获取博主联系方式! 摘要 该系统基于Python技术栈构建,整合了网络爬虫、大数据分析、机器学习推荐算法及可视化技术,旨在为旅游行业提供数据驱动的决策支持与个性化服务。 数据采集层采用Scrapy框架爬取主流旅游平台(如携程、TripAdvisor)的多维数据,包括景点信息、用户评论、价格动态及地理位置,通过反爬策略(动态IP代理、请求头模拟)确保数据完整性。数据存储使用MongoDB处理非结构化文本,MySQL管理结构化属性字段。 数据分析层基于Pandas与NumPy进行数据清洗(缺失值填充、异常值剔除)和特征工程(情感分析、热度指数计算)。结合PySpark实现分布式处理,对海量用户行为日志进行聚类分析(K-Means)与关联规则挖掘(Apriori算法),识别游客偏好与消费模式。 推荐系统层采用协同过滤(Surprise库)与内容推荐(TF-IDF向

By Ne0inhk