/
Dengit-man
/
CustomLocaleKeyShortcut
Обзор
Документация
Войти
/
Dengit-man
/
CustomLocaleKeyShortcut
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
7
CI/CD
Аналитика
Безопасность
AddMacOS
Classes/C_Logger.cpp
616 строк
22 KB
Dengit-man
Поправлен `LICENSE.md` и соответствующие упоминания в нужных файлах.
25 май 2026, 23:32
Верифицирован
25 май 2026, 23:32
79c96dd
Код
Авторство
О чём код?
// // Created by Dengit-man on 26.02.2026. // Правообладатель (c) 2026 Пользователь GitVerse "Dengit-man" // #include "C_Logger.h" #include <atomic> #include <chrono> #include <iostream> #include <sstream> #include <thread> #include <utility> #include "C_Exceptions.h" #include "C_MainContext.h" #include "S_Utilities.h" std::atomic_bool C_Logger::initialized = ATOMIC_VAR_INIT(0); std::atomic_bool C_Logger::initializing = ATOMIC_VAR_INIT(0); std::atomic< std::shared_ptr<C_Logger> > C_Logger::_instance{nullptr}; std::mutex C_Logger::init_mutex{}; std::mutex C_Logger::print_mutex{}; std::mutex C_Logger::localtime_mutex{}; bool C_Logger::logsOff = false; std::string C_Logger::getLogPrefix(MsgType type) { switch (type) { case MsgType::CriticalMsg: return {"[CRITICAL]"}; case MsgType::WarningMsg: return {"[WARNING] "}; case MsgType::InfoMsg: return {"[INFO] "}; case MsgType::DebugMsg: return {"[DEBUG] "}; case MsgType::FatalMsg: return {"[FATAL] "}; default: return {"[UNKNOWN] "}; } } std::string C_Logger::format(const std::string &message, const MsgType type, const char* file, const char* function, const int lineNum, std::string thId) { constexpr auto fmt = R"([{0}] {1} [ "{2}":{3:4d}, '{4: <12}'] [{5: ^3}] "{6}")"; std::string line = std::format(fmt, C_Logger::currTime(), C_Logger::getLogPrefix(type), file, lineNum, function, thId, message); return line; } std::wstring C_Logger::format(const std::wstring &message, const MsgType type, const char* file, const char* function, const int lineNum, std::string thId) { constexpr auto fmt = LR"([{0}] {1} [ "{2}":{3:4d}, '{4: <12}'] [{5: ^3}] "{6}")"; std::wstring line = std::format(fmt, C_Logger::wcurrTime(), S_Utilities::to_wstring(C_Logger::getLogPrefix(type)), S_Utilities::to_wstring(file), lineNum, S_Utilities::to_wstring(function), S_Utilities::str_to_wstr_digits(thId), message); return line; } void C_Logger::recheckLogFile() { if (C_Logger::logsOff) { return; } #if defined(DEBUG_OUT_ON) std::cout << C_Logger::getLogColor< decltype(std::cout)::char_type >(MsgType::DebugMsg) << DebugLine( "Check open log file") << C_Logger::getLogColor< decltype(std::cout)::char_type >(static_cast< MsgType >(-1)) << std::endl; #endif if (this->logstream.is_open()) { #if defined(DEBUG_OUT_ON) std::cout << C_Logger::getLogColor< decltype(std::cout)::char_type >(MsgType::DebugMsg) << DebugLine( "Closing log file") << C_Logger::getLogColor< decltype(std::cout)::char_type >(static_cast< MsgType >(-1)) << std::endl; #endif this->logstream.close(); } if (!this->GetLogFileName().empty()) { #if defined(DEBUG_OUT_ON) std::cout << C_Logger::getLogColor< decltype(std::cout)::char_type >(MsgType::DebugMsg) << DebugLine( "Opening log file") << C_Logger::getLogColor< decltype(std::cout)::char_type >(static_cast< MsgType >(-1)) << std::endl; #endif auto rslt = S_Utilities::ensureDirectoryExists(this->GetLogFileName().parent_path()); if (!rslt) { std::cerr << C_Logger::getLogColor< decltype(std::cerr)::char_type >(MsgType::WarningMsg) << CriticalLine(std::format("[-] There is problem with path: \"{}\"; Path: '{}'", rslt.message, this->GetLogFileName().string())) << C_Logger::getLogColor< decltype(std::cerr)::char_type >(static_cast< MsgType >(-1)) << std::endl; } this->logstream.open(this->GetLogFileName(), std::ofstream::out | std::ofstream::app); if (!this->logstream.is_open()) { std::cerr << C_Logger::getLogColor< decltype(std::cerr)::char_type >(MsgType::WarningMsg) << WarnLine( std::format("[-] Failed to open log file '{}'", this->GetLogFileName().string())) << C_Logger::getLogColor< decltype(std::cerr)::char_type >(static_cast< MsgType >(-1)) << std::endl; } else { std::cout << C_Logger::getLogColor< decltype(std::cout)::char_type >(MsgType::InfoMsg) << InfoLine( std::format("[+] Log file opened successful: '{}'", this->GetLogFileName().string())) << C_Logger::getLogColor< decltype(std::cout)::char_type >(static_cast< MsgType >(-1)) << std::endl; this->logstream << C_Logger::getLogColor< decltype(std::cout)::char_type >(MsgType::InfoMsg) << InfoLine( std::format("[+] Log file opened successful: '{}'", this->GetLogFileName().string())) << C_Logger::getLogColor< decltype(std::cout)::char_type >(static_cast< MsgType >(-1)) << std::endl; } this->logstream.close(); this->logstream_ok = true; this->wlogstream.open(this->GetLogFileName(), std::wofstream::out | std::wofstream::app); if (!this->wlogstream.is_open()) { std::cerr << C_Logger::getLogColor< decltype(std::cerr)::char_type >(MsgType::WarningMsg) << WarnLine( std::format("[-] Failed to open wide log file '{}'", this->GetLogFileName().string())) << C_Logger::getLogColor< decltype(std::cerr)::char_type >(static_cast< MsgType >(-1)) << std::endl; } else { std::wcout << C_Logger::getLogColor< decltype(std::wcout)::char_type >(MsgType::InfoMsg) << InfoLine( std::format(L"[+] Wide Log file opened successful: '{}'", this->GetLogFileName().wstring())) << C_Logger::getLogColor< decltype(std::wcout)::char_type >(static_cast< MsgType >(-1)) << std::endl; this->wlogstream << C_Logger::getLogColor< decltype(std::wcout)::char_type >(MsgType::InfoMsg) << InfoLine( std::format(L"[+] Wide Log file opened successful: '{}'", this->GetLogFileName().wstring())) << C_Logger::getLogColor< decltype(std::wcout)::char_type >(static_cast< MsgType >(-1)) << std::endl; } this->wlogstream.close(); this->wlogstream_ok = true; } } bool C_Logger::openLogFile(bool wide/* = false*/) { if (this->GetLogFileName().empty()) { return false; } if (!wide) { if (this->logstream_ok) { this->logstream.open(this->GetLogFileName(), std::ofstream::out | std::ofstream::app); if (!this->logstream.is_open()) { if (!C_Logger::logsOff) { std::cerr << C_Logger::getLogColor<decltype(std::cerr)::char_type>(MsgType::WarningMsg) << \ WarnLine(std::format("[-] Failed to open log file '{}'", this->GetLogFileName().string())) << \ C_Logger::getLogColor<decltype(std::cerr)::char_type>(static_cast<MsgType>(-1)) << std::endl; } return false; } return true; } } else { if (this->wlogstream_ok) { this->wlogstream.open(this->GetLogFileName(), std::wofstream::out | std::wofstream::app); if (!this->wlogstream.is_open()) { if (!C_Logger::logsOff) { std::cerr << C_Logger::getLogColor<decltype(std::cerr)::char_type>(MsgType::WarningMsg) << \ WarnLine(std::format("[-] Failed to open wide log file '{}'", this->GetLogFileName().string())) << \ C_Logger::getLogColor<decltype(std::cerr)::char_type>(static_cast<MsgType>(-1)) << std::endl; } return false; } return true; } } return false; } void C_Logger::closeLogFile() { // std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(MsgType::DebugMsg) << DebugLine("Closing log file") << \ // C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << std::endl; if (this->logstream.is_open()) { this->logstream.close(); } if (this->wlogstream.is_open()) { this->wlogstream.close(); } } C_Logger::C_Logger() : f_logFileNameRefreshed(true), logstream_ok(false), wlogstream_ok(false) { #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(MsgType::DebugMsg) << DebugLine("C_Logger creating...") << \ C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << std::endl; } #endif static bool initialized = false; if (!initialized) { #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(MsgType::DebugMsg) << DebugLine("C_Logger initializing...") << \ C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << std::endl; } #endif initialized = true; } else { LogCritical("Instance already initialized. You can't construct new object. " \ "If you need to add tags. You should use \"addTag(QString tag)\".", false); throw EObjectIsAlreadyInitialized("Instance already initialized. You can't construct new object. " \ "If you need to add tags. You should use \"addTag(QString tag)\"."); // static_assert(false, "Can't add tags. You should use \"obj->addTag(QString tag)\"."); } #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(MsgType::DebugMsg) << DebugLine("C_Logger created.") << \ C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << std::endl; } #endif } std::filesystem::path C_Logger::GetLogFileName() { if (this->f_logFileNameRefreshed) { constexpr auto date_var = "{DATE}"; const auto old = this->f_logFileName; auto filename = this->f_logFileName.filename().string(); auto pos = filename.find(date_var); if (pos >= 0 && pos < filename.length()) //Сравнение беззнакового с нулём на случай, если size_t когда-нибудь, где-нибудь окажется знаковым. { filename.replace(pos, strlen(date_var), C_Logger::currDate()); this->f_logFileName = this->f_logFileName.parent_path() / filename; } constexpr auto cwd = "./"; auto fullpath = this->f_logFileName.string(); if (fullpath[0] == cwd[0] && fullpath[1] == cwd[1]) { this->f_logFileName = std::filesystem::current_path() / std::string_view(fullpath).substr(2); } this->f_logFileNameRefreshed = false; if (old != this->f_logFileName) { #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { // std::lock_guard const lock(C_Logger::print_mutex); std::cout << C_Logger::getLogColor< decltype(std::cout)::char_type >(MsgType::DebugMsg) << DebugLine( std::format("Set new logging filename '{}'; old: '{}'", this->f_logFileName.string(), old.string())) << C_Logger::getLogColor< decltype(std::cout)::char_type >(static_cast< MsgType >(-1)) << std::endl; } #endif } } return this->f_logFileName; } bool C_Logger::freeInstance() { #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(MsgType::DebugMsg) << DebugLine("C_Logger::freeInstance() called") << \ C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << std::endl; } #endif std::lock_guard const lock(C_Logger::init_mutex); auto last_chance = C_Logger::_instance.exchange(nullptr, std::memory_order_acq_rel); if (last_chance != nullptr) { last_chance.reset(); #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(MsgType::DebugMsg) << DebugLine("C_Logger instance released") << \ C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << std::endl; } #endif return true; } else { #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(MsgType::DebugMsg) << DebugLine("C_Logger instance already nullptr") << \ C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << std::endl; } #endif return false; } } void C_Logger::_log(const std::string &message, const MsgType type, const char* file, const char* function, const int line, std::string thId) { if (C_Logger::logsOff) { return; } std::lock_guard const lock(C_Logger::print_mutex); const auto msg = C_Logger::format(message, type, file, function, line, std::move(thId)); switch (type) { case MsgType::CriticalMsg: case MsgType::FatalMsg: { std::cerr << C_Logger::getLogColor<decltype(std::cerr)::char_type>(type) << msg << termcolor::reset << \ C_Logger::getLogColor<decltype(std::cerr)::char_type>(static_cast<MsgType>(-1)) << "\n"; } break; default: { std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(type) << msg << termcolor::reset << \ C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << "\n"; } break; } if (this->openLogFile()) { this->logstream << msg << '\n'; this->logstream.flush(); this->closeLogFile(); } } void C_Logger::_log(const std::wstring &message, const MsgType type, const char* file, const char* function, const int line, std::string thId) { if (C_Logger::logsOff) { return; } std::lock_guard const lock(C_Logger::print_mutex); const auto msg = C_Logger::format(message, type, file, function, line, std::move(thId)); switch (type) { case MsgType::CriticalMsg: case MsgType::FatalMsg: { std::wcerr << C_Logger::getLogColor<decltype(std::wcerr)::char_type>(type) << msg << termcolor::reset << \ C_Logger::getLogColor<decltype(std::wcout)::char_type>(static_cast<MsgType>(-1)) << L"\n"; } break; default: { std::wcout << C_Logger::getLogColor<decltype(std::wcout)::char_type>(type) << msg << termcolor::reset << \ C_Logger::getLogColor<decltype(std::wcout)::char_type>(static_cast<MsgType>(-1)) << L"\n"; } break; } if (this->openLogFile(true)) { this->wlogstream << msg << '\n'; this->wlogstream.flush(); this->closeLogFile(); } } std::string C_Logger::currTime() { const auto now = std::chrono::system_clock::now(); const auto time_t = std::chrono::system_clock::to_time_t(now); constexpr unsigned short one_second_ms = 1000; auto ms = std::chrono::duration_cast<std::chrono::milliseconds>( now.time_since_epoch() ) % one_second_ms; std::ostringstream oss; { std::unique_lock lock(C_Logger::localtime_mutex); oss << std::put_time(localtime(&time_t), "%Y-%m-%d %H:%M:%S") << '.' << std::setfill('0') << std::setw(3) << ms.count(); } return oss.str(); } std::string C_Logger::currDate() { const auto now = std::chrono::system_clock::now(); const auto time_t = std::chrono::system_clock::to_time_t(now); std::ostringstream oss; { std::unique_lock lock(C_Logger::localtime_mutex); oss << std::put_time(localtime(&time_t), "%Y-%m-%d"); } return oss.str(); } std::wstring C_Logger::wcurrDate() { const auto now = std::chrono::system_clock::now(); const auto time_t = std::chrono::system_clock::to_time_t(now); std::wostringstream oss; { std::unique_lock lock(C_Logger::localtime_mutex); oss << std::put_time(localtime(&time_t), L"%Y-%m-%d"); } return oss.str(); } std::wstring C_Logger::wcurrTime() { const auto now = std::chrono::system_clock::now(); const auto time_t = std::chrono::system_clock::to_time_t(now); constexpr unsigned short one_second_ms = 1000; auto ms = std::chrono::duration_cast<std::chrono::milliseconds>( now.time_since_epoch() ) % one_second_ms; std::wostringstream oss; { std::unique_lock lock(C_Logger::localtime_mutex); oss << std::put_time(localtime(&time_t), L"%Y-%m-%d %H:%M:%S") << '.' << std::setfill(L'0') << std::setw(3) << ms.count(); } return oss.str(); } void C_Logger::SetLogsOn(bool logsOn) { C_Logger::logsOff = !logsOn; } void C_Logger::setLogFileName(const std::string &logFileName) { #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::lock_guard const lock(C_Logger::print_mutex); std::cout << C_Logger::getLogColor< decltype(std::cout)::char_type >(MsgType::DebugMsg) << DebugLine( std::format("Set new logging filename '{}'; old: '{}'", logFileName, this->GetLogFileName().string() )) << C_Logger::getLogColor< decltype(std::cout)::char_type >(static_cast< MsgType >(-1)) << std::endl; } #endif this->f_logFileName = logFileName; this->f_logFileNameRefreshed = true; this->recheckLogFile(); } std::shared_ptr<C_Logger> C_Logger::instance() { auto ptr = C_Logger::_instance.load(std::memory_order_acquire); if (ptr != nullptr) { return ptr; } #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::lock_guard const lock(C_Logger::init_mutex); std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(MsgType::DebugMsg) << DebugLine("Double-Checked Locking: C_Logger::init_mutex become locked.") << \ C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << std::endl; } #endif ptr = C_Logger::_instance.load(std::memory_order_acquire); if (ptr == nullptr) { try { auto fresh = std::shared_ptr<C_Logger>(new C_Logger()); #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(MsgType::DebugMsg) << DebugLine("C_Logger instance created.") << \ C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << std::endl; } #endif C_Logger::_instance.store(fresh, std::memory_order_release); #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::cout << C_Logger::getLogColor<decltype(std::cout)::char_type>(MsgType::DebugMsg) << DebugLine("C_Logger instance stored successfully..") << \ C_Logger::getLogColor<decltype(std::cout)::char_type>(static_cast<MsgType>(-1)) << std::endl; } #endif ptr = C_Logger::_instance.load(std::memory_order_acquire); // emit fresh } catch (...) { #if defined(DEBUG_OUT_ON) if (!C_Logger::logsOff) { std::cerr << C_Logger::getLogColor<decltype(std::cerr)::char_type>(MsgType::CriticalMsg) << CriticalLine("[!] C_Logger::instance() failed.") << \ C_Logger::getLogColor<decltype(std::cerr)::char_type>(static_cast<MsgType>(-1)) << std::endl; } #endif throw std::runtime_error(CriticalLine("[!] C_Logger::instance() failed.")); } } // else // { // LogWarn("C_Logger instance already initialized."); // } return ptr; } std::mutex & C_Logger::getPrintMutex() { return C_Logger::print_mutex; } void C_Logger::Log(const std::string &message, const MsgType type, const char* file, const char* function, const int line, std::string thId) { auto instance = C_Logger::instance(); instance->_log(message, type, file, function, line, thId); } void C_Logger::Log(const std::wstring &message, const MsgType type, const char* file, const char* function, const int line, std::string thId) { auto instance = C_Logger::instance(); instance->_log(message, type, file, function, line, thId); } void C_Logger::Log(const std::string &message, bool async, const MsgType type, const char *file, const char *function, const int line, std::string thId ) { if (async) { std::thread([this, message, type, file, function, line, thId]() { this->Log(message, type, file, function, line, thId); }).detach(); } else { this->Log(message, type, file, function, line, thId); } } void C_Logger::Log(const std::wstring &message, bool async, const MsgType type, const char *file, const char *function, const int line, std::string thId ) { if (async) { std::thread([this, message, type, file, function, line, thId]() { this->Log(message, type, file, function, line, thId); }).detach(); } else { this->Log(message, type, file, function, line, thId); } }