//--------------------------------------------------------------------------- #include "logger.h" #include "stdTools.h" #include #include #include #include #include #include #include //--------------------------------------------------------------------------- Logger::Logger(std::string fileName){ this->fileName = fileName; this->stop = false; std::string folder = Utility::BeforeLast(fileName,Utility::separator()); if (!Utility::createFolder(folder)) { std::cerr << "Error create folder: " << folder << std::endl; } openLogFile(); logThread = std::thread(&Logger::processQueue, this); }; //--------------------------------------------------------------------------- Logger::~Logger() { { std::unique_lock lock(queueMutex); stop = true; } queueCondition.notify_all(); logThread.join(); }; //--------------------------------------------------------------------------- //Сервисная функция std::string Logger::getCurrentDateTime() { std::time_t now = std::time(nullptr); std::tm* nowTm = std::localtime(&now); std::ostringstream timeStream; timeStream << std::put_time(nowTm, "%Y-%m-%dT%H:%M:%S"); return timeStream.str(); } //--------------------------------------------------------------------------- void Logger::log(std::string thread, std::string level, std::string data, bool cout) { { std::unique_lock lock(queueMutex); LogRec rec; rec.thread = thread; rec.level = level; rec.data = data; rec.cout = cout; logQueue.push(rec); } queueCondition.notify_one(); } //--------------------------------------------------------------------------- void Logger::processQueue() { while (true) { { std::unique_lock lock(queueMutex); // Ждем до 1 минуты или пока условие не выполнится queueCondition.wait_for(lock, std::chrono::minutes(1), [this] { return !logQueue.empty() || stop; }); if (stop && logQueue.empty()){ break; } if(!logQueue.empty()){ LogRec rec = std::move(logQueue.front()); logQueue.pop(); writeLog(rec.thread,rec.level,rec.data,rec.cout); } //Всё что ниже для переименовывания старого файла if(!std::filesystem::exists(fileName)){ continue; } // Получаем время создания файла (st_ctime) struct stat fileInfo; if (stat(fileName.c_str(), &fileInfo) != 0) { std::cerr << "Error getting file info: " << fileName << std::endl; continue; } std::time_t creationTime = fileInfo.st_ctime; std::tm* creation_tm = std::localtime(&creationTime); // Получаем текущее время auto now = std::chrono::system_clock::now(); std::time_t now_c = std::chrono::system_clock::to_time_t(now); std::tm* now_tm = std::localtime(&now_c); //Если даты не совпадают то переименовываю файл в с датой создания и переоткрываю новый файл if( (now_tm->tm_year != creation_tm->tm_year) || (now_tm->tm_mon != creation_tm->tm_mon) || (now_tm->tm_mday != creation_tm->tm_mday)){ if(file.is_open()) { file.close(); } char buffer[11]; // Длина строки "YYYY-MM-DD" + '\0' std::memset(buffer, 0, sizeof(buffer)); std::strftime(buffer, sizeof(buffer), "%Y-%m-%d", creation_tm); std::ostringstream newFileName; newFileName << Utility::BeforeLast(fileName,'.') << "_" << buffer << "." << Utility::AfterLast(fileName,'.'); std::string newName = newFileName.str(); try { std::filesystem::rename(fileName, newName); } catch (const std::filesystem::filesystem_error& e) { std::cerr << "Error renaming file: " << e.what() << std::endl; } //Удаляю старые файлы std::string folder = Utility::BeforeLast(fileName,Utility::separator()); Utility::deleteOldFiles(folder,10); } } } } //--------------------------------------------------------------------------- void Logger::openLogFile() { file.open(fileName, std::ios::out | std::ios::app); if (!file.is_open()) { std::cerr << "Error open file: " << fileName << std::endl; } } //--------------------------------------------------------------------------- void Logger::writeLog(std::string thread, std::string level, std::string data, bool cout) { if (!file.is_open()){ openLogFile(); } //Записываем лог if (file.is_open()) { std::stringstream str(std::stringstream::out | std::stringstream::binary); std::string dateTime = getCurrentDateTime(); thread = Utility::escape_json(thread); level = Utility::escape_json(level); data = Utility::escape_json(data); str << "{\"timestamp\":\"" << dateTime << "\", \"thread\":\"" <