C++日志管理从基础到完善
C++日志管理从基础到完善
万古教员有名言,自信人生二百年。 个人主页:oioihoii 喜欢内容的话欢迎关注、点赞、收藏!感谢支持,祝大家祉猷并茂,顺遂无虞!
在设计C++日志系统时,我们需要考虑以下几个关键点:
- 易用性:日志系统应该易于使用,开发者应该能够轻松地添加日志条目。
- 性能:日志系统应该尽可能地减少对应用程序性能的影响。这意味着日志记录的过程应该尽可能地快速,以减少对应用程序的延迟。
- 灵活性:日志系统应该能够支持不同级别的日志(如错误、警告、信息、调试等),并能够在运行时动态地更改日志级别。
- 可配置性:日志系统应该允许开发者配置日志的各种参数,如日志文件的位置、日志的格式等。
- 线程安全:如果应用程序是多线程的,那么日志系统也必须是线程安全的。
下面是一个简单的C++日志系统的设计,它考虑了上述的所有因素:
代码语言:javascript代码运行次数:0运行复制#include <iostream>
#include <fstream>
#include <mutex>
#include <memory>
enum class LogLevel {
ERROR,
WARIG,
IFO,
DEBUG
};
class Logger {
public:
Logger(ct std::string& file_name) {
file_stream_.open(file_name, std::ios::out | std::ios::app);
}
~Logger() {
file_stream_.close();
}
void Log(LogLevel level, ct std::string& message) {
std::lock_guard<std::mutex> lock(mutex_);
switch(level) {
case LogLevel::ERROR:
file_stream_ << "[ERROR] ";
break;
case LogLevel::WARIG:
file_stream_ << "[WARIG] ";
break;
case LogLevel::IFO:
file_stream_ << "[IFO] ";
break;
case LogLevel::DEBUG:
file_stream_ << "[DEBUG] ";
break;
}
file_stream_ << message << std::endl;
}
private:
std::ofstream file_stream_;
std::mutex mutex_;
};
int main() {
auto logger = std::make_shared<Logger>("");
logger->Log(LogLevel::IFO, "This is an info message");
logger->Log(LogLevel::ERROR, "This is an error message");
return 0;
}
在这个设计中,我们使用了一个std::ofstream
对象来写入日志文件,使用了一个std::mutex
对象来确保线程安全,使用了一个枚举类LogLevel
来表示不同的日志级别。我们的Log
函数接受一个日志级别和一个消息,然后将它们写入日志文件。
这只是一个基础的日志系统设计,实际的日志系统可能会更复杂,例如,它可能会支持将日志发送到多个目的地(如文件、网络、控制台等),支持多种日志格式,支持日志轮转等。
对于大量日志的生成,确实需要考虑性能问题。频繁地打开和关闭文件会导致性能下降。在这种情况下,我们可以考虑以下优化:
- 缓冲日志消息:我们可以在内存中缓冲日志消息,然后在缓冲区满时一次性写入文件,而不是每次都打开和关闭文件。这可以大大提高性能,但是需要注意的是,如果程序崩溃,缓冲区中的日志消息可能会丢失。
- 异步写入:我们可以在一个单独的线程中写入日志文件,这样就不会阻塞主程序的执行。这需要更复杂的线程同步机制,但是可以进一步提高性能。
下面是一个改进的版本,使用了缓冲区和异步写入:
代码语言:javascript代码运行次数:0运行复制#include <iostream>
#include <fstream>
#include <mutex>
#include <memory>
#include <thread>
#include <condition_variable>
#include <queue>
enum class LogLevel {
ERROR,
WARIG,
IFO,
DEBUG
};
class Logger {
public:
Logger(ct 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();
}
void Log(LogLevel level, ct std::string& message) {
std::lock_guard<std::mutex> lock(mutex_);
log_queue_.push(std::make_pair(level, message));
cv_.notify_all();
}
private:
void writeLog() {
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::WARIG:
file_stream_ << "[WARIG] ";
break;
case LogLevel::IFO:
file_stream_ << "[IFO] ";
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_;
};
int main() {
auto logger = std::make_shared<Logger>("");
logger->Log(LogLevel::IFO, "This is an info message");
logger->Log(LogLevel::ERROR, "This is an error message");
return 0;
}
在这个版本中,我们使用了一个std::queue
来缓冲日志消息,使用了一个std::condition_variable
来同步主线程和工作线程,使用了一个std::thread
来执行日志写入。我们的Log
函数将日志消息添加到队列中,然后通知工作线程。工作线程在收到通知后,会将队列中的所有日志消息写入文件。
要实现日志文件的定时清除功能,我们需要添加一些额外的代码来管理日志文件。以下是一个改进的版本,它会在每天的特定时间(例如午夜)创建一个新的日志文件,并删除0天前的日志文件:
代码语言:javascript代码运行次数:0运行复制#include <iostream>
#include <fstream>
#include <mutex>
#include <memory>
#include <thread>
#include <condition_variable>
#include <queue>
#include <chrono>
#include <filesystem>
#include <iomanip>
enum class LogLevel {
ERROR,
WARIG,
IFO,
DEBUG
};
class Logger {
public:
Logger(ct 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();
}
void Log(LogLevel level, ct std::string& message) {
std::lock_guard<std::mutex> lock(mutex_);
log_queue_.push(std::make_pair(level, message));
cv_.notify_all();
}
private:
void writeLog() {
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::WARIG:
file_stream_ << "[WARIG] ";
break;
case LogLevel::IFO:
file_stream_ << "[IFO] ";
break;
case LogLevel::DEBUG:
file_stream_ << "[DEBUG] ";
break;
}
file_stream_ << log.second << std::endl;
}
if (exit_ && log_queue_.empty()) break;
}
}
void deleteOldLogs() {
auto now = std::chrono::system_clock::now();
auto date = std::chrono::system_clock::to_time_t(now);
std::tm tm;
localtime_s(&tm, &date);
_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_;
};
int main() {
auto logger = std::make_shared<Logger>("logs", 0);
logger->Log(LogLevel::IFO, "This is an info message");
logger->Log(LogLevel::ERROR, "This is an error message");
return 0;
}
在这个版本中,我们在writeLog
函数中检查当前的日期,如果日期改变了,我们就创建一个新的日志文件,并删除0天前的日志文件。我们使用了C++17的std::filesystem
库来删除文件。注意,这个代码只在支持C++17的编译器上有效。
这个代码的一个限制是,它假设日志文件的名字是按照"YYYYMMDD.log"的格式命名的。如果你的日志文件的命名规则不同,你需要修改writeLog
和deleteOldLogs
函数中的代码。
#感谢您对电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格的认可,转载请说明来源于"电脑配置推荐网 - 最新i3 i5 i7组装电脑配置单推荐报价格
推荐阅读
留言与评论(共有 17 条评论) |
本站网友 治疗卵巢囊肿 | 27分钟前 发表 |
mutex> lock(mutex_); log_queue_.push(std | |
本站网友 夷陵区 | 30分钟前 发表 |
0); logger->Log(LogLevel | |
本站网友 初期症状 | 20分钟前 发表 |
remove(oss.str()); } std | |
本站网友 许豪杰 | 12分钟前 发表 |
性能:日志系统应该尽可能地减少对应用程序性能的影响 | |
本站网友 爱财经网 | 22分钟前 发表 |
DEBUG | |
本站网友 北京二手房出售信息 | 18分钟前 发表 |
这个代码的一个限制是 | |
本站网友 kimkar | 12分钟前 发表 |
string& message) { std | |
本站网友 田阳新闻 | 8分钟前 发表 |
本站网友 做包皮 | 4分钟前 发表 |
版本二:考虑性能的进阶日志对于大量日志的生成 | |
本站网友 天津美食网 | 3分钟前 发表 |
message)); cv_.notify_all(); } private | |
本站网友 唐山房屋出租 | 16分钟前 发表 |
本站网友 美国网站 | 4分钟前 发表 |
本站网友 蛋壳网 | 11分钟前 发表 |
本站网友 非法批地 | 28分钟前 发表 |
然后通知工作线程 | |
本站网友 南京洗头房 | 6分钟前 发表 |
file_stream_ << "[ERROR] "; break; case LogLevel | |
本站网友 温岭租房 | 9分钟前 发表 |
ios |