#include "LogL.h" #include #include #include #include #include #include #ifdef __linux__ #include #endif using namespace std; LogL::LogL(LogType logType, bool isSync, std::string logPath) : m_isSync(isSync), m_logType(logType), m_logPath(std::move(logPath)), m_file(nullptr), m_thread(nullptr), m_sender(nullptr) { switch (m_logType) { case LTStd: { break; } case LTTxt: { //创建文件 myDateTime now; std::string dirName; if (m_logPath.empty()) { dirName = "logs"; } else { dirName = m_logPath; } myMkdir(dirName.c_str()); std::string fileName = dirName + "/" + now.toDate() + ".txt"; m_file = new std::ofstream(fileName, std::ios::app); m_today = now.day; break; } case LTUdp: { m_sender = new UDPSender; std::vector parts; std::stringstream ss(m_logPath); std::string part; // 按逗号分割字符串 while (std::getline(ss, part, ',')) { parts.push_back(part); } if (parts.size() == 3) { m_sender->set_destination(parts[0], stoi(parts[1])); m_sender->set_source(parts[0], stoi(parts[2])); } else if (parts.size() == 2) { m_sender->set_destination(parts[0], stoi(parts[1])); } else { throw std::runtime_error("UDP Path Error"); } break; } case LTTcp: { break; } } if (!m_isSync) { //运行日志线程 m_thread_run = true; m_thread = new std::thread(&LogL::logThread, this); } } LogL::~LogL() { //停止线程 while (m_thread) { if (m_log_queue.empty()) { cout << "已清空日志队列" << endl; break; } cout << "正在写入剩余日志:" << m_log_queue.size() << endl; this_thread::sleep_for(chrono::milliseconds(300)); } if (m_thread) { //设置结束并等待线程结束 m_thread_run = false; m_cond_empty.notify_all(); if (m_thread->joinable()) { m_thread->join(); } delete m_thread; m_thread = nullptr; } //关闭文件 m_mtx.lock(); if (m_file) { m_file->flush(); m_file->close(); delete m_file; m_file = nullptr; } m_mtx.unlock(); cout << "日志析构函数完成" << endl; } void LogL::logThread() { std::string str; while (m_thread_run) { //如果队列为空,等待 if (m_log_queue.empty()) { std::unique_lock lock(m_mtx); m_cond_empty.wait(lock); continue; } //取出队列头并出栈 str = m_log_queue.front(); m_log_queue.pop(); m_cond_full.notify_one(); switch (m_logType) { case LTStd: cout << str << endl; break; case LTTxt: { if (m_file == nullptr) { std::cerr << "logThread():日志文件打开失败" << endl; break; } *m_file << str << endl; break; } case LTUdp: try { m_sender->send(str); } catch (const std::runtime_error &e) { std::cerr << e.what() << endl; } break; case LTTcp: break; } } } void LogL::debug(const std::string &str) { log(str, LLDebug); } void LogL::info(const std::string &str) { log(str, LLInfo); } void LogL::warn(const std::string &str) { log(str, LLWarn); } void LogL::error(const std::string &str) { log(str, LLError); } void LogL::log(const std::string &str, LogLevel level) { string tmpLever; switch (level) { case LLDebug: tmpLever = " [debug]:"; break; case LLInfo: tmpLever = " [info]:"; break; case LLWarn: tmpLever = " [warn]:"; break; case LLError: tmpLever = " [error]:"; break; } myDateTime now; if (m_logType == LTTxt) { //逾期更新日志文件 m_mtx.lock(); if (now.day != m_today) { if (m_file) { m_file->flush(); m_file->close(); delete m_file; m_file = nullptr; } std::string dirName; if (m_logPath.empty()) { dirName = "log"; } else { dirName = m_logPath; } myMkdir(dirName.c_str()); std::string fileName = dirName + "/" + now.toDate() + ".txt"; m_file = new std::ofstream(fileName, std::ios::app); } m_mtx.unlock(); } std::string logInfo = now.toDateTime() + tmpLever + str; if (m_isSync) { switch (m_logType) { case LTStd: cout << logInfo << endl; break; case LTTxt: { if (m_file == nullptr) { std::cerr << "日志文件打开失败" << endl; break; } *m_file << logInfo << endl; break; } case LTUdp: try { m_sender->send(logInfo); } catch (const std::runtime_error &e) { std::cerr << e.what() << endl; } break; case LTTcp: break; } } else { if (m_log_queue.size() >= 4096) { std::unique_lock lock(m_mtx); m_cond_full.wait(lock); } m_mtx.lock(); m_log_queue.push(logInfo); m_mtx.unlock(); m_cond_empty.notify_all(); } } bool createPath(const char *path) { struct stat st = {0}; if (stat(path, &st) == -1) { #if WIN32 if (mkdir(path) == 0) { #else if (mkdir(path,0777) == 0) { #endif return true; } else { std::cerr << "Failed to create directory: " << path << std::endl; return false; } } return true; // Directory already exists } bool myMkdir(const char *path) { char buffer[1024]; char *p = buffer; const char *sep = "/"; strcpy(buffer, path); while ((p = strchr(p, *sep)) != nullptr) { *p = '\0'; if (!createPath(buffer)) { return false; } *p = *sep; p++; } createPath(buffer); return true; } myDateTime::myDateTime() { auto now = std::chrono::system_clock::now(); std::time_t time1 = std::chrono::system_clock::to_time_t(now); std::tm *tm1 = std::localtime(&time1); year = tm1->tm_year + 1900; month = tm1->tm_mon + 1; day = tm1->tm_mday; hour = tm1->tm_hour; minute = tm1->tm_min; second = tm1->tm_sec; } std::string myDateTime::toDate() const { string date = to_string(year) + "-"; if (month < 10) { date += "0" + to_string(month) + "-"; } else { date += to_string(month) + "-"; } if (day < 10) { date += "0" + to_string(day); } else { date += to_string(day); } return date; } std::string myDateTime::toTime() const { string time; if (hour < 10) { time += "0" + to_string(hour) + ":"; } else { time += to_string(hour) + ":"; } if (minute < 10) { time += "0" + to_string(minute) + ":"; } else { time += to_string(minute) + ":"; } if (second < 10) { time += "0" + to_string(second); } else { time += to_string(second); } return time; } std::string myDateTime::toDateTime() const { string dateTime = toDate() + " " + toTime(); return dateTime; }