diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2025-12-18 17:23:24 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-12-18 17:23:24 +0000 |
| commit | 6175ecd4c4ba817c4620f66a75e1e11da7c7a8ca (patch) | |
| tree | cf73852f1fc08b1dcee5a3a7380f914aaad9c50a /src/debug/log | |
| parent | f88deb928a0f7dc02f427473f8c29e8f2bed14a3 (diff) | |
debug: move to hyprutils' logger (#12673)
Diffstat (limited to 'src/debug/log')
| -rw-r--r-- | src/debug/log/Logger.cpp | 64 | ||||
| -rw-r--r-- | src/debug/log/Logger.hpp | 61 | ||||
| -rw-r--r-- | src/debug/log/RollingLogFollow.hpp | 70 |
3 files changed, 195 insertions, 0 deletions
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<Hyprlang::INT>("debug:disable_logs"); + static auto PDISABLETIME = CConfigValue<Hyprlang::INT>("debug:disable_time"); + static auto PENABLESTDOUT = CConfigValue<Hyprlang::INT>("debug:enable_stdout_logs"); + static auto PENABLECOLOR = CConfigValue<Hyprlang::INT>("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 <hyprutils/cli/Logger.hpp> + +#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 <typename... Args> + //NOLINTNEXTLINE + void log(Hyprutils::CLI::eLogLevel level, std::format_string<Args...> 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<Args...> 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<CLogger> logger = makeUnique<CLogger>(); + + // + 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 <shared_mutex> +#include <unordered_map> +#include <format> +#include <vector> + +namespace Log { + struct SRollingLogFollow { + std::unordered_map<int, std::string> 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<std::shared_mutex> r(m_mutex); + return m_socketToRollingLogFollowQueue[socket].empty(); + } + + std::string debugInfo() { + std::shared_lock<std::shared_mutex> r(m_mutex); + return std::format("RollingLogFollow, got {} connections", m_socketToRollingLogFollowQueue.size()); + } + + std::string getLog(int socket) { + std::unique_lock<std::shared_mutex> 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<std::shared_mutex> w(m_mutex); + m_running = true; + std::vector<int> to_erase; + for (const auto& p : m_socketToRollingLogFollowQueue) { + m_socketToRollingLogFollowQueue[p.first] += log; + m_socketToRollingLogFollowQueue[p.first] += "\n"; + } + } + + bool isRunning() { + std::shared_lock<std::shared_mutex> r(m_mutex); + return m_running; + } + + void stopFor(int socket) { + std::unique_lock<std::shared_mutex> w(m_mutex); + m_socketToRollingLogFollowQueue.erase(socket); + if (m_socketToRollingLogFollowQueue.empty()) + m_running = false; + } + + void startFor(int socket) { + std::unique_lock<std::shared_mutex> 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<std::mutex> lock(gm); + return instance; + }; + }; +} |
