赞
踩
默认保存到文件,并支持回调函数,比如显示到界面
#ifndef LOGGER_H #define LOGGER_H #include <iostream> #include <sstream> #include <mutex> #include <thread> #include <iomanip> #include <fstream> #include <string> #include <condition_variable> #include <thread> #include <queue> #include <chrono> #include <ctime> #include <functional> // 线程安全的日志组件 class Logger { public: enum class LogLevel { Unknown=0, //未知信息 Debug, //调试信息 Info, //普通信息 Trace, //详细信息 Warning, //警告信息 Error, //错误信息,但程序可以继续运行。 Fatal, //出现无法恢复的错误,可能导致程序崩溃。 Panic //出现严重错误,必须立即停止程序运行。 }; Logger(); Logger(const std::string& path); ~Logger(); void set_file_name(const std::string& path); //添加回调函数 void set_callback(const std::function<void(std::pair<LogLevel, std::string>)>& func); //输出日志 void add_log(LogLevel level, const std::string& message); //转字符串 static std::string level2string(LogLevel level); private: //工作线程 void worker(); //获取当前时间 std::string get_current_timestamp(); //结束线程 void stop(); private: std::mutex _mutex; std::condition_variable _condition; std::queue<std::pair<LogLevel, std::string>> _queue; std::thread _worker; std::string _path; std::ofstream _file; bool _stop; std::function<void(std::pair<LogLevel, std::string>)> _unction; }; #endif // LOGGER_H
#include "logger.h" Logger::Logger(){} Logger::Logger(const std::string& path) : _path(path),_stop(false), _worker(&Logger::worker, this) { _file.open(_path, std::ios_base::app); } void Logger::set_file_name(const std::string& path) { _path = path; _file.open(_path, std::ios_base::app); } Logger::~Logger() { stop(); _worker.join(); //关闭文件 if (_file.is_open()) { _file.close(); } } //添加回调函数 输出 void Logger::set_callback(const std::function<void(std::pair<LogLevel, std::string>)>& func) { _unction = func; } std::string Logger::level2string(LogLevel level) { switch (level) { case LogLevel::Debug: return "Debug"; case LogLevel::Info: return "Info"; case LogLevel::Trace: return "Trace"; case LogLevel::Warning: return "Warning"; case LogLevel::Error: return "Error"; case LogLevel::Fatal: return "Fatal"; case LogLevel::Panic: return "Panic"; default: return "Unknown"; } } //输出日志 void Logger::add_log(LogLevel level, const std::string& message) { std::lock_guard<std::mutex> lock(_mutex); _queue.emplace(level, message); _condition.notify_one(); } //工作线程 void Logger::worker() { for(;;) { std::pair<LogLevel, std::string> pair; { std::unique_lock<std::mutex> lock(_mutex); _condition.wait(lock, [this] { return _stop || !_queue.empty(); }); if (_stop && _queue.empty()) { break; } pair = _queue.front(); _queue.pop(); } // //输出到文件 // std::ofstream out(_path, std::ios_base::app); // if (!out.good()) // { // continue; // } // out << get_current_timestamp() <<" "<<level2string(pair.first) <<":"<< pair.second << std::endl; // out.close(); // 如果文件流不可用,则重新尝试打开 if (!_file.is_open()) { _file.open(_path, std::ios_base::app); if (!_file.is_open()) { // 打开文件失败,继续下一个循环 continue; } } // 输出日志消息到文件流 _file << get_current_timestamp() << " " << level2string(pair.first) << ":" << pair.second << std::endl; _file.flush(); // 刷新缓冲区 if(_unction) { _unction(pair); } } } //获取当前时间 std::string Logger::get_current_timestamp() { auto now = std::chrono::system_clock::now(); auto time = std::chrono::system_clock::to_time_t(now); auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000; std::stringstream ss; ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S") << '.' << std::setfill('0') << std::setw(3) << ms.count(); return ss.str(); } //结束线程 void Logger::stop() { std::lock_guard<std::mutex> lock(_mutex); _stop = true; _condition.notify_one(); }
比如:
使用qt界面,接收日志,,通过接收 logReceived 信号,获取日志信息显示。这里QtConcurrent::run 可以方便接收信息,触发异步信号,不阻塞界面。不然界面会卡死,更新UI只能在一个线程中
// 增加日志回调
void StreamManagerWidget::log_function(std::pair<Logger::LogLevel, std::string> pair)
{
// 在后台线程执行日志记录任务
QtConcurrent::run(&_threadPool,[this, pair](){
// 将日志信息格式化为 QString
QString logMessage = QString::fromStdString(Logger::level2string(pair.first) +": "+ pair.second);
// 发送信号,在主线程中更新 UI
emit logReceived(logMessage);
});
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。