#include #include #include #include #include #include #include #include #include #include #include #if defined(OS_WINDOWS) #include #endif namespace hex::log { namespace { wolv::io::File s_loggerFile; bool s_colorOutputEnabled = false; std::recursive_mutex s_loggerMutex; bool s_loggingSuspended = false; bool s_debugLoggingEnabled = false; } void suspendLogging() { s_loggingSuspended = true; } void resumeLogging() { s_loggingSuspended = false; } void enableDebugLogging() { s_debugLoggingEnabled = true; } namespace impl { void lockLoggerMutex() { s_loggerMutex.lock(); } void unlockLoggerMutex() { s_loggerMutex.unlock(); } bool isLoggingSuspended() { return s_loggingSuspended; } bool isDebugLoggingEnabled() { #if defined(DEBUG) return true; #else return s_debugLoggingEnabled; #endif } FILE *getDestination() { if (s_loggerFile.isValid()) return s_loggerFile.getHandle(); else return stdout; } wolv::io::File& getFile() { return s_loggerFile; } bool isRedirected() { return s_loggerFile.isValid(); } void redirectToFile() { if (s_loggerFile.isValid()) return; for (const auto &path : paths::Logs.all()) { wolv::io::fs::createDirectories(path); time_t time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); s_loggerFile = wolv::io::File(path / fmt::format("{0:%Y%m%d_%H%M%S}.log", *std::localtime(&time)), wolv::io::File::Mode::Create); s_loggerFile.disableBuffering(); if (s_loggerFile.isValid()) { s_colorOutputEnabled = false; break; } } } void enableColorPrinting() { s_colorOutputEnabled = true; #if defined(OS_WINDOWS) auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE); if (hConsole != INVALID_HANDLE_VALUE) { DWORD mode = 0; if (::GetConsoleMode(hConsole, &mode) == TRUE) { mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT; ::SetConsoleMode(hConsole, mode); } } #endif } static AutoReset> s_logEntries; const std::vector& getLogEntries() { return s_logEntries; } void addLogEntry(std::string_view project, std::string_view level, std::string message) { s_logEntries->emplace_back( std::move(project), std::move(level), std::move(message) ); } void printPrefix(FILE *dest, fmt::text_style ts, std::string_view level, std::string_view projectName) { const auto time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); const auto now = *std::localtime(&time); auto threadName = TaskManager::getCurrentThreadName(); if (threadName.empty()) [[unlikely]] { threadName = "???"; } constexpr static auto MaxTagLength = 25; const auto totalLength = std::min(static_cast(MaxTagLength), projectName.length() + (threadName.empty() ? 0 : 3 + threadName.length())); const auto remainingSpace = MaxTagLength - projectName.length() - 3; fmt::print(dest, "[{0:%H:%M:%S}] {1} [{2} | {3}] {4: <{5}} ", now, s_colorOutputEnabled ? fmt::format(ts, "{}", level) : level, projectName.substr(0, std::min(projectName.length(), static_cast(MaxTagLength))), threadName.substr(0, remainingSpace), "", MaxTagLength - totalLength ); } namespace color { fmt::color debug() { return fmt::color::medium_sea_green; } fmt::color info() { return fmt::color::steel_blue; } fmt::color warn() { return fmt::color::orange; } fmt::color error() { return fmt::color::indian_red; } fmt::color fatal() { return fmt::color::medium_purple; } } } }