// // Created by 张衡 on 25-7-8. // #ifndef LOGGER_H #define LOGGER_H #include #include #include #include #include #include #include #include #include #include #include #include //辅助函数,多个参数转化字符串 template std::string to_string_helper(T&& arg) { std::ostringstream oss; oss << std::forward(arg); return oss.str(); } class LogQueue { public: void push(const std::string& msg) { std::lock_guard lock(mutex_); queue_.push(msg); //构造好自动加锁,析构自动解锁 cond_var_.notify_all(); }; //字符串放队列中 bool pop(std::string& msg) { std::unique_lock lock(mutex_); //条件变量唤醒之后直接加锁 cond_var_.wait(lock, [this]() { return !queue_.empty() || is_shutdown_; //返回true就继续往下走 }); //消费逻辑 //队列不为空or已经关闭 if (is_shutdown_ && queue_.empty()) { return false; } //保证队列的数据被清空掉 // while (is_shutdown_ && !queue_.empty()) { // msg = queue_.front(); // queue_.pop(); // return false; // } msg = queue_.front(); //返回消息给msg指针 queue_.pop(); return true; }; void shutdown() { std::lock_guard lock(mutex_); is_shutdown_ = true; cond_var_.notify_all(); }; private: std::queue queue_; std::mutex mutex_; std::condition_variable cond_var_; bool is_shutdown_ = false; }; enum class Loglevel { INFO, DEBUG, WARNING, ERROR }; // 日志输出抽象基类 class LogOutput { public: virtual ~LogOutput() = default; virtual void write(const std::string& msg) = 0; }; // 文件输出 class FileOutput : public LogOutput { public: FileOutput(const std::string& filename) : file_(filename, std::ios::out | std::ios::app) { if (!file_.is_open()) { throw std::runtime_error("Failed to open log file"); } } void write(const std::string& msg) override { file_ << msg << std::endl; } ~FileOutput() { if (file_.is_open()) file_.close(); } private: std::ofstream file_; }; // 控制台输出 class ConsoleOutput : public LogOutput { public: void write(const std::string& msg) override { std::cout << msg << std::endl; } }; // 网络输出(示例,实际实现需补充) class NetworkOutput : public LogOutput { public: void write(const std::string& msg) override { // 这里可以实现网络发送逻辑 // 示例:std::cout << "[Network] " << msg << std::endl; } }; class Logger { public: // 通过unique_ptr传入多态输出对象 Logger(std::unique_ptr output_obj) : output_obj_(std::move(output_obj)), exit_flag_(false) { worker_thread_ = std::thread([this]() { std::string msg; while (log_queue_.pop(msg)) { output_obj_->write(msg); } }); } ~Logger() { exit_flag_ = true; log_queue_.shutdown(); if (worker_thread_.joinable()) { worker_thread_.join(); } } template void log(Loglevel loglevel, const std::string& format, Args&& ...args) { std::string level_str; switch (loglevel) { case Loglevel::INFO: level_str = "[INFO] "; break; case Loglevel::DEBUG: level_str = "[DEBUG] "; break; case Loglevel::WARNING: level_str = "[WARNING] "; break; case Loglevel::ERROR: level_str = "[ERROR] "; break; } log_queue_.push(level_str + formatMessage(format, std::forward(args)...)); } private: static std::string GetTimeStamp() { std::time_t now = std::time(nullptr); std::tm* local_time = std::localtime(&now); char buffer[80]; std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", local_time); return std::string(buffer); } template std::string formatMessage(const std::string& format, Args&&...args) { std::vector arg_strings = {to_string_helper(std::forward(args))...}; std::ostringstream oss; size_t arg_index = 0; size_t pos = 0; size_t placeholder = format.find("{}", pos); oss << GetTimeStamp() << " "; while (placeholder != std::string::npos) { oss << format.substr(pos, placeholder - pos); if (arg_index < arg_strings.size()) { oss << arg_strings[arg_index]; } else { oss << "{}"; } arg_strings[arg_index++]; pos = placeholder + 2; placeholder = format.find("{}", pos); } oss << format.substr(pos); while (arg_index < arg_strings.size()) { oss << arg_strings[arg_index++]; } return oss.str(); } LogQueue log_queue_; std::thread worker_thread_; std::unique_ptr output_obj_; // 多态输出对象 std::atomic exit_flag_; }; #endif //LOGGER_H