From 6175ecd4c4ba817c4620f66a75e1e11da7c7a8ca Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 18 Dec 2025 17:23:24 +0000 Subject: debug: move to hyprutils' logger (#12673) --- src/debug/HyprCtl.cpp | 43 ++++++++++----------- src/debug/Log.cpp | 78 -------------------------------------- src/debug/Log.hpp | 75 ------------------------------------ src/debug/RollingLogFollow.hpp | 66 -------------------------------- src/debug/TracyDefines.hpp | 2 +- src/debug/crash/CrashReporter.cpp | 2 +- src/debug/log/Logger.cpp | 64 +++++++++++++++++++++++++++++++ src/debug/log/Logger.hpp | 61 +++++++++++++++++++++++++++++ src/debug/log/RollingLogFollow.hpp | 70 ++++++++++++++++++++++++++++++++++ 9 files changed, 218 insertions(+), 243 deletions(-) delete mode 100644 src/debug/Log.cpp delete mode 100644 src/debug/Log.hpp delete mode 100644 src/debug/RollingLogFollow.hpp create mode 100644 src/debug/log/Logger.cpp create mode 100644 src/debug/log/Logger.hpp create mode 100644 src/debug/log/RollingLogFollow.hpp (limited to 'src/debug') diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 5e21d699..90adab91 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -40,7 +40,7 @@ using namespace Hyprutils::OS; #include "../devices/ITouch.hpp" #include "../devices/Tablet.hpp" #include "../protocols/GlobalShortcuts.hpp" -#include "debug/RollingLogFollow.hpp" +#include "debug/log/RollingLogFollow.hpp" #include "config/ConfigManager.hpp" #include "helpers/MiscFunctions.hpp" #include "../desktop/view/LayerSurface.hpp" @@ -957,11 +957,10 @@ static std::string rollinglogRequest(eHyprCtlOutputFormat format, std::string re if (format == eHyprCtlOutputFormat::FORMAT_JSON) { result += "[\n\"log\":\""; - result += escapeJSONStrings(Debug::m_rollingLog); + result += escapeJSONStrings(Log::logger->rolling()); result += "\"]"; - } else { - result = Debug::m_rollingLog; - } + } else + result = Log::logger->rolling(); return result; } @@ -1260,7 +1259,7 @@ static std::string dispatchRequest(eHyprCtlOutputFormat format, std::string in) SDispatchResult res = DISPATCHER->second(DISPATCHARG); - Debug::log(LOG, "Hyprctl: dispatcher {} : {}{}", DISPATCHSTR, DISPATCHARG, res.success ? "" : " -> " + res.error); + Log::logger->log(Log::DEBUG, "Hyprctl: dispatcher {} : {}{}", DISPATCHSTR, DISPATCHARG, res.success ? "" : " -> " + res.error); return res.success ? "ok" : res.error; } @@ -1340,7 +1339,7 @@ static std::string dispatchKeyword(eHyprCtlOutputFormat format, std::string in) if (COMMAND.contains("workspace")) g_pConfigManager->ensurePersistentWorkspacesPresent(); - Debug::log(LOG, "Hyprctl: keyword {} : {}", COMMAND, VALUE); + Log::logger->log(Log::DEBUG, "Hyprctl: keyword {} : {}", COMMAND, VALUE); if (retval.empty()) return "ok"; @@ -2223,23 +2222,23 @@ static bool successWrite(int fd, const std::string& data, bool needLog = true) { return true; if (needLog) - Debug::log(ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno))); + Log::logger->log(Log::ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno))); return false; } static void runWritingDebugLogThread(const int conn) { using namespace std::chrono_literals; - Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn); + Log::logger->log(Log::DEBUG, "In followlog thread, got connection, start writing: {}", conn); //will be finished, when reading side close connection std::thread([conn]() { - while (Debug::SRollingLogFollow::get().isRunning()) { - if (Debug::SRollingLogFollow::get().isEmpty(conn)) { + while (Log::SRollingLogFollow::get().isRunning()) { + if (Log::SRollingLogFollow::get().isEmpty(conn)) { std::this_thread::sleep_for(1000ms); continue; } - auto line = Debug::SRollingLogFollow::get().getLog(conn); + auto line = Log::SRollingLogFollow::get().getLog(conn); if (!successWrite(conn, line)) // We cannot write, when connection is closed. So thread will successfully exit by itself break; @@ -2247,7 +2246,7 @@ static void runWritingDebugLogThread(const int conn) { std::this_thread::sleep_for(100ms); } close(conn); - Debug::SRollingLogFollow::get().stopFor(conn); + Log::SRollingLogFollow::get().stopFor(conn); }).detach(); } @@ -2273,10 +2272,10 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { CRED_T creds; uint32_t len = sizeof(creds); if (getsockopt(ACCEPTEDCONNECTION, CRED_LVL, CRED_OPT, &creds, &len) == -1) - Debug::log(ERR, "Hyprctl: failed to get peer creds"); + Log::logger->log(Log::ERR, "Hyprctl: failed to get peer creds"); else { g_pHyprCtl->m_currentRequestParams.pid = creds.CRED_PID; - Debug::log(LOG, "Hyprctl: new connection from pid {}", creds.CRED_PID); + Log::logger->log(Log::DEBUG, "Hyprctl: new connection from pid {}", creds.CRED_PID); } // @@ -2311,7 +2310,7 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { try { reply = g_pHyprCtl->getReply(request); } catch (std::exception& e) { - Debug::log(ERR, "Error in request: {}", e.what()); + Log::logger->log(Log::ERR, "Error in request: {}", e.what()); reply = "Err: " + std::string(e.what()); } @@ -2331,10 +2330,10 @@ static int hyprCtlFDTick(int fd, uint32_t mask, void* data) { successWrite(ACCEPTEDCONNECTION, reply); if (isFollowUpRollingLogRequest(request)) { - Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket."); - Debug::SRollingLogFollow::get().startFor(ACCEPTEDCONNECTION); + Log::logger->log(Log::DEBUG, "Followup rollinglog request received. Starting thread to write to socket."); + Log::SRollingLogFollow::get().startFor(ACCEPTEDCONNECTION); runWritingDebugLogThread(ACCEPTEDCONNECTION); - Debug::log(LOG, Debug::SRollingLogFollow::get().debugInfo()); + Log::logger->log(Log::DEBUG, Log::SRollingLogFollow::get().debugInfo()); } else close(ACCEPTEDCONNECTION); @@ -2351,7 +2350,7 @@ void CHyprCtl::startHyprCtlSocket() { m_socketFD = CFileDescriptor{socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)}; if (!m_socketFD.isValid()) { - Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); + Log::logger->log(Log::ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); return; } @@ -2362,14 +2361,14 @@ void CHyprCtl::startHyprCtlSocket() { snprintf(SERVERADDRESS.sun_path, sizeof(SERVERADDRESS.sun_path), "%s", m_socketPath.c_str()); if (bind(m_socketFD.get(), rc(&SERVERADDRESS), SUN_LEN(&SERVERADDRESS)) < 0) { - Debug::log(ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); + Log::logger->log(Log::ERR, "Couldn't start the Hyprland Socket. (2) IPC will not work."); return; } // 10 max queued. listen(m_socketFD.get(), 10); - Debug::log(LOG, "Hypr socket started at {}", m_socketPath); + Log::logger->log(Log::DEBUG, "Hypr socket started at {}", m_socketPath); m_eventSource = wl_event_loop_add_fd(g_pCompositor->m_wlEventLoop, m_socketFD.get(), WL_EVENT_READABLE, hyprCtlFDTick, nullptr); } diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp deleted file mode 100644 index e70617d3..00000000 --- a/src/debug/Log.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "Log.hpp" -#include "../defines.hpp" -#include "RollingLogFollow.hpp" - -#include -#include -#include - -void Debug::init(const std::string& IS) { - m_logFile = IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log"); - m_logOfs.open(m_logFile, std::ios::out | std::ios::app); - auto handle = m_logOfs.native_handle(); - fcntl(handle, F_SETFD, FD_CLOEXEC); -} - -void Debug::close() { - m_logOfs.close(); -} - -void Debug::log(eLogLevel level, std::string str) { - if (level == TRACE && !m_trace) - return; - - if (m_shuttingDown) - return; - - std::lock_guard guard(m_logMutex); - - std::string coloredStr = str; - //NOLINTBEGIN - switch (level) { - case LOG: - str = "[LOG] " + str; - coloredStr = str; - break; - case WARN: - str = "[WARN] " + str; - coloredStr = "\033[1;33m" + str + "\033[0m"; // yellow - break; - case ERR: - str = "[ERR] " + str; - coloredStr = "\033[1;31m" + str + "\033[0m"; // red - break; - case CRIT: - str = "[CRITICAL] " + str; - coloredStr = "\033[1;35m" + str + "\033[0m"; // magenta - break; - case INFO: - str = "[INFO] " + str; - coloredStr = "\033[1;32m" + str + "\033[0m"; // green - break; - case TRACE: - str = "[TRACE] " + str; - coloredStr = "\033[1;34m" + str + "\033[0m"; // blue - break; - default: break; - } - //NOLINTEND - - m_rollingLog += str + "\n"; - if (m_rollingLog.size() > ROLLING_LOG_SIZE) - m_rollingLog = m_rollingLog.substr(m_rollingLog.size() - ROLLING_LOG_SIZE); - - if (SRollingLogFollow::get().isRunning()) - SRollingLogFollow::get().addLog(str); - - if (!m_disableLogs || !**m_disableLogs) { - // log to a file - m_logOfs << str << "\n"; - m_logOfs.flush(); - } - - // log it to the stdout too. - if (!m_disableStdout) { - std::println("{}", ((m_coloredLogs && !**m_coloredLogs) ? str : coloredStr)); - std::fflush(stdout); - } -} diff --git a/src/debug/Log.hpp b/src/debug/Log.hpp deleted file mode 100644 index c3146805..00000000 --- a/src/debug/Log.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -#define LOGMESSAGESIZE 1024 -#define ROLLING_LOG_SIZE 4096 - -enum eLogLevel : int8_t { - NONE = -1, - LOG = 0, - WARN, - ERR, - CRIT, - INFO, - TRACE -}; - -// NOLINTNEXTLINE(readability-identifier-naming) -namespace Debug { - inline std::string m_logFile; - inline std::ofstream m_logOfs; - inline int64_t* const* m_disableLogs = nullptr; - inline int64_t* const* m_disableTime = nullptr; - inline bool m_disableStdout = false; - inline bool m_trace = false; - inline bool m_shuttingDown = false; - inline int64_t* const* m_coloredLogs = nullptr; - - inline std::string m_rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log - inline std::mutex m_logMutex; - - void init(const std::string& IS); - void close(); - - // - void log(eLogLevel level, std::string str); - - template - //NOLINTNEXTLINE - void log(eLogLevel level, std::format_string fmt, Args&&... args) { - if (level == TRACE && !m_trace) - return; - - if (m_shuttingDown) - return; - - std::string logMsg = ""; - - // print date and time to the ofs - if (m_disableTime && !**m_disableTime) { -#ifndef _LIBCPP_VERSION - static auto current_zone = std::chrono::current_zone(); - const auto zt = std::chrono::zoned_time{current_zone, std::chrono::system_clock::now()}; - const auto hms = std::chrono::hh_mm_ss{zt.get_local_time() - std::chrono::floor(zt.get_local_time())}; -#else - // TODO: current clang 17 does not support `zoned_time`, remove this once clang 19 is ready - const auto hms = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor(std::chrono::system_clock::now())}; -#endif - logMsg += std::format("[{}] ", hms); - } - - // no need for try {} catch {} because std::format_string ensures that vformat never throw std::format_error - // because - // 1. any faulty format specifier that sucks will cause a compilation error. - // 2. and `std::bad_alloc` is catastrophic, (Almost any operation in stdlib could throw this.) - // 3. this is actually what std::format in stdlib does - logMsg += std::vformat(fmt.get(), std::make_format_args(args...)); - - log(level, logMsg); - } -}; diff --git a/src/debug/RollingLogFollow.hpp b/src/debug/RollingLogFollow.hpp deleted file mode 100644 index 07b4387d..00000000 --- a/src/debug/RollingLogFollow.hpp +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include - -// NOLINTNEXTLINE(readability-identifier-naming) -namespace Debug { - struct SRollingLogFollow { - std::unordered_map m_socketToRollingLogFollowQueue; - std::shared_mutex m_mutex; - bool m_running = false; - static constexpr size_t ROLLING_LOG_FOLLOW_TOO_BIG = 8192; - - // Returns true if the queue is empty for the given socket - bool isEmpty(int socket) { - std::shared_lock r(m_mutex); - return m_socketToRollingLogFollowQueue[socket].empty(); - } - - std::string debugInfo() { - std::shared_lock r(m_mutex); - return std::format("RollingLogFollow, got {} connections", m_socketToRollingLogFollowQueue.size()); - } - - std::string getLog(int socket) { - std::unique_lock w(m_mutex); - - const std::string ret = m_socketToRollingLogFollowQueue[socket]; - m_socketToRollingLogFollowQueue[socket] = ""; - - return ret; - }; - - void addLog(const std::string& log) { - std::unique_lock w(m_mutex); - m_running = true; - std::vector to_erase; - for (const auto& p : m_socketToRollingLogFollowQueue) - m_socketToRollingLogFollowQueue[p.first] += log + "\n"; - } - - bool isRunning() { - std::shared_lock r(m_mutex); - return m_running; - } - - void stopFor(int socket) { - std::unique_lock w(m_mutex); - m_socketToRollingLogFollowQueue.erase(socket); - if (m_socketToRollingLogFollowQueue.empty()) - m_running = false; - } - - void startFor(int socket) { - std::unique_lock w(m_mutex); - m_socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket); - m_running = true; - } - - static SRollingLogFollow& get() { - static SRollingLogFollow instance; - static std::mutex gm; - std::lock_guard lock(gm); - return instance; - }; - }; -} diff --git a/src/debug/TracyDefines.hpp b/src/debug/TracyDefines.hpp index 49d296f6..d06332f3 100644 --- a/src/debug/TracyDefines.hpp +++ b/src/debug/TracyDefines.hpp @@ -2,7 +2,7 @@ #ifdef USE_TRACY_GPU -#include "Log.hpp" +#include "log/Logger.hpp" #include #include diff --git a/src/debug/crash/CrashReporter.cpp b/src/debug/crash/CrashReporter.cpp index 1b18fce4..fad6ad21 100644 --- a/src/debug/crash/CrashReporter.cpp +++ b/src/debug/crash/CrashReporter.cpp @@ -248,5 +248,5 @@ void CrashReporter::createAndSaveCrash(int sig) { finalCrashReport += "\n\nLog tail:\n"; - finalCrashReport += std::string_view(Debug::m_rollingLog).substr(Debug::m_rollingLog.find('\n') + 1); + finalCrashReport += Log::logger->rolling(); } diff --git a/src/debug/log/Logger.cpp b/src/debug/log/Logger.cpp new file mode 100644 index 00000000..44b82a50 --- /dev/null +++ b/src/debug/log/Logger.cpp @@ -0,0 +1,64 @@ +#include "Logger.hpp" +#include "RollingLogFollow.hpp" + +#include "../../defines.hpp" + +#include "../../managers/HookSystemManager.hpp" +#include "../../config/ConfigValue.hpp" + +using namespace Log; + +CLogger::CLogger() { + const auto IS_TRACE = Env::isTrace(); + m_logger.setLogLevel(IS_TRACE ? Hyprutils::CLI::LOG_TRACE : Hyprutils::CLI::LOG_DEBUG); +} + +void CLogger::log(Hyprutils::CLI::eLogLevel level, const std::string_view& str) { + + static bool TRACE = Env::isTrace(); + + if (!m_logsEnabled) + return; + + if (level == Hyprutils::CLI::LOG_TRACE && !TRACE) + return; + + if (SRollingLogFollow::get().isRunning()) + SRollingLogFollow::get().addLog(str); + + m_logger.log(level, str); +} + +void CLogger::initIS(const std::string_view& IS) { + // NOLINTNEXTLINE + m_logger.setOutputFile(std::string{IS} + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log")); + m_logger.setEnableRolling(true); + m_logger.setEnableColor(false); + m_logger.setEnableStdout(true); + m_logger.setTime(false); +} + +void CLogger::initCallbacks() { + static auto P = g_pHookSystem->hookDynamic("configReloaded", [this](void* hk, SCallbackInfo& info, std::any param) { recheckCfg(); }); + recheckCfg(); +} + +void CLogger::recheckCfg() { + static auto PDISABLELOGS = CConfigValue("debug:disable_logs"); + static auto PDISABLETIME = CConfigValue("debug:disable_time"); + static auto PENABLESTDOUT = CConfigValue("debug:enable_stdout_logs"); + static auto PENABLECOLOR = CConfigValue("debug:colored_stdout_logs"); + + m_logger.setEnableStdout(!*PDISABLELOGS && *PENABLESTDOUT); + m_logsEnabled = !*PDISABLELOGS; + m_logger.setTime(!*PDISABLETIME); + m_logger.setEnableColor(*PENABLECOLOR); +} + +const std::string& CLogger::rolling() { + return m_logger.rollingLog(); +} + +Hyprutils::CLI::CLogger& CLogger::hu() { + return m_logger; +} diff --git a/src/debug/log/Logger.hpp b/src/debug/log/Logger.hpp new file mode 100644 index 00000000..d4e868de --- /dev/null +++ b/src/debug/log/Logger.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include + +#include "../../helpers/memory/Memory.hpp" +#include "../../helpers/env/Env.hpp" + +namespace Log { + class CLogger { + public: + CLogger(); + ~CLogger() = default; + + void initIS(const std::string_view& IS); + void initCallbacks(); + + void log(Hyprutils::CLI::eLogLevel level, const std::string_view& str); + + template + //NOLINTNEXTLINE + void log(Hyprutils::CLI::eLogLevel level, std::format_string fmt, Args&&... args) { + static bool TRACE = Env::isTrace(); + + if (!m_logsEnabled) + return; + + if (level == Hyprutils::CLI::LOG_TRACE && !TRACE) + return; + + std::string logMsg = ""; + + // no need for try {} catch {} because std::format_string ensures that vformat never throw std::format_error + // because + // 1. any faulty format specifier that sucks will cause a compilation error. + // 2. and `std::bad_alloc` is catastrophic, (Almost any operation in stdlib could throw this.) + // 3. this is actually what std::format in stdlib does + logMsg += std::vformat(fmt.get(), std::make_format_args(args...)); + + log(level, logMsg); + } + + const std::string& rolling(); + Hyprutils::CLI::CLogger& hu(); + + private: + void recheckCfg(); + + Hyprutils::CLI::CLogger m_logger; + bool m_logsEnabled = true; + }; + + inline UP logger = makeUnique(); + + // + inline constexpr const Hyprutils::CLI::eLogLevel DEBUG = Hyprutils::CLI::LOG_DEBUG; + inline constexpr const Hyprutils::CLI::eLogLevel WARN = Hyprutils::CLI::LOG_WARN; + inline constexpr const Hyprutils::CLI::eLogLevel ERR = Hyprutils::CLI::LOG_ERR; + inline constexpr const Hyprutils::CLI::eLogLevel CRIT = Hyprutils::CLI::LOG_CRIT; + inline constexpr const Hyprutils::CLI::eLogLevel INFO = Hyprutils::CLI::LOG_DEBUG; + inline constexpr const Hyprutils::CLI::eLogLevel TRACE = Hyprutils::CLI::LOG_TRACE; +}; diff --git a/src/debug/log/RollingLogFollow.hpp b/src/debug/log/RollingLogFollow.hpp new file mode 100644 index 00000000..c1cce9eb --- /dev/null +++ b/src/debug/log/RollingLogFollow.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include +#include +#include +#include + +namespace Log { + struct SRollingLogFollow { + std::unordered_map m_socketToRollingLogFollowQueue; + std::shared_mutex m_mutex; + bool m_running = false; + static constexpr size_t ROLLING_LOG_FOLLOW_TOO_BIG = 8192; + + // Returns true if the queue is empty for the given socket + bool isEmpty(int socket) { + std::shared_lock r(m_mutex); + return m_socketToRollingLogFollowQueue[socket].empty(); + } + + std::string debugInfo() { + std::shared_lock r(m_mutex); + return std::format("RollingLogFollow, got {} connections", m_socketToRollingLogFollowQueue.size()); + } + + std::string getLog(int socket) { + std::unique_lock w(m_mutex); + + const std::string ret = m_socketToRollingLogFollowQueue[socket]; + m_socketToRollingLogFollowQueue[socket] = ""; + + return ret; + }; + + void addLog(const std::string_view& log) { + std::unique_lock w(m_mutex); + m_running = true; + std::vector to_erase; + for (const auto& p : m_socketToRollingLogFollowQueue) { + m_socketToRollingLogFollowQueue[p.first] += log; + m_socketToRollingLogFollowQueue[p.first] += "\n"; + } + } + + bool isRunning() { + std::shared_lock r(m_mutex); + return m_running; + } + + void stopFor(int socket) { + std::unique_lock w(m_mutex); + m_socketToRollingLogFollowQueue.erase(socket); + if (m_socketToRollingLogFollowQueue.empty()) + m_running = false; + } + + void startFor(int socket) { + std::unique_lock w(m_mutex); + m_socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket); + m_running = true; + } + + static SRollingLogFollow& get() { + static SRollingLogFollow instance; + static std::mutex gm; + std::lock_guard lock(gm); + return instance; + }; + }; +} -- cgit v1.2.3