3Logger* Logger::instance =
nullptr;
6 if (!Logger::instance) {
7 Logger::instance =
new Logger();
9 return Logger::instance;
12Logger::Logger() : exitFlag(false) {
13 if (!std::filesystem::exists(this->logDirectory)) {
14 if(std::filesystem::create_directories(this->logDirectory)) {
18 std::cerr <<
"Error during logDirectory creation. " << std::endl;
21 loggingThread = std::thread(&Logger::processQueue,
this);
22 this->
threadId = loggingThread.get_id();
27 std::unique_lock<std::mutex> lock(queueMutex);
30 conditionVar.notify_all();
33 for (
auto& logFilePair : logFiles) {
34 logFilePair.second.close();
43 logDirectory = directory;
44 maxFileSize = maxSize;
45 if (!std::filesystem::exists(logDirectory)) {
46 std::filesystem::create_directories(logDirectory);
51 this->enabled = enabled;
54std::string Logger::toString(LogLevel level) {
62 default:
return "UNKNOWN";
67std::string Logger::currentDateTime() {
68 std::time_t now = std::time(
nullptr);
70 std::strftime(buf,
sizeof(buf),
"%Y-%m-%d_%H", std::localtime(&now));
71 return std::string(buf);
75 std::ostringstream filename;
76 filename << baseName <<
"_" << suffix <<
".log";
77 return filename.str();
81 std::ostringstream filename;
82 filename << logDirectory <<
"/log_" << currentDateTime() <<
"_thread_" <<
threadId;
83 return filename.str();
86std::ofstream& Logger::getLogFile(std::thread::id threadId) {
87 std::lock_guard<std::mutex> lock(logFileMutex);
90 if (it == logFiles.end()) {
92 logFiles[
threadId].open(filepath, std::ios_base::app);
94 throw std::runtime_error(
"Cannot open log file for thread");
100void Logger::rotateLogFile(std::thread::id threadId) {
101 std::lock_guard<std::mutex> lock(logFileMutex);
107 std::string oldFilepath = baseFilepath +
".log";
111 while (std::filesystem::exists(newFilename)) {
115 std::filesystem::rename(oldFilepath, newFilename);
117 logFiles[
threadId].open(oldFilepath, std::ios_base::app);
118 if (!logFiles[
threadId].is_open()) {
119 throw std::runtime_error(
"Cannot open new log file for thread");
123void Logger::processQueue() {
125 std::unique_lock<std::mutex> lock(queueMutex);
126 conditionVar.wait(lock, [
this] {
return !logQueue.empty() || exitFlag; });
128 while (!logQueue.empty()) {
129 std::string logEntry = logQueue.front();
135 if (std::filesystem::exists(logFilePath) && std::filesystem::file_size(logFilePath) >= maxFileSize) {
137 std::cout << logFilePath <<
" " << std::filesystem::file_size(logFilePath) << std::endl;
141 std::ofstream& logFile = getLogFile(this->threadId);
142 logFile << logEntry << std::endl;
148 while (!logQueue.empty()) {
149 std::string logEntry = logQueue.front();
154 if (std::filesystem::exists(logFilePath) && std::filesystem::file_size(logFilePath) >= maxFileSize) {
159 std::ofstream& logFile = getLogFile(
threadId);
160 logFile << logEntry << std::endl;
A singleton logging utility supporting multiple logging levels and concurrent logging to file and ter...
void setEnabled(bool enabled)
Enables or disables the Logger.
std::string getLogFilenameWithSuffix(const std::string &baseName, int suffix)
Retrieves a log filename with a suffix.
void setLevel(LogLevel level)
Sets the logging level.
LogLevel
Logging levels supported by the Logger.
void setLogDirectory(const std::string &directory, std::size_t maxSize=10048576)
Sets the directory for storing log files.
~Logger()
Destructor for Logger, ensures graceful shutdown of logging.
std::string getLogFilenameForThread(std::thread::id threadId)
Retrieves the log filename for the specified thread.
static Logger * getInstance()
Retrieves the singleton instance of the Logger.