161 lines
5.6 KiB
C++
161 lines
5.6 KiB
C++
//---------------------------------------------------------------------------
|
||
#include "logger.h"
|
||
|
||
#include "stdTools.h"
|
||
#include <cstring>
|
||
#include <iomanip>
|
||
#include <ctime>
|
||
#include <iostream>
|
||
#include <sstream>
|
||
#include <filesystem>
|
||
#include <sys/stat.h>
|
||
|
||
//---------------------------------------------------------------------------
|
||
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<std::mutex> 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<std::mutex> 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<std::mutex> 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\":\"" <<thread<<"\", \"level\":\""<<level<<"\", \"message\":\"" << data <<"\"}" << std::endl;
|
||
|
||
if (cout)
|
||
std::cout << "[" << dateTime << "] " << data << std::endl; //Повтор лога в консоль
|
||
|
||
file.write(str.str().c_str(), str.str().length());
|
||
file.flush();
|
||
}
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
//std::string Logger::getCurrentDate() {
|
||
// std::time_t now = std::time(nullptr);
|
||
// std::tm* nowTm = std::localtime(&now);
|
||
// std::ostringstream timeStream;
|
||
// timeStream << std::put_time(nowTm, "%Y-%m-%d");
|
||
// return timeStream.str();
|
||
//}
|
||
//---------------------------------------------------------------------------
|