summaryrefslogtreecommitdiff
path: root/src/debug/log
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2025-12-18 17:23:24 +0000
committerGitHub <noreply@github.com>2025-12-18 17:23:24 +0000
commit6175ecd4c4ba817c4620f66a75e1e11da7c7a8ca (patch)
treecf73852f1fc08b1dcee5a3a7380f914aaad9c50a /src/debug/log
parentf88deb928a0f7dc02f427473f8c29e8f2bed14a3 (diff)
debug: move to hyprutils' logger (#12673)
Diffstat (limited to 'src/debug/log')
-rw-r--r--src/debug/log/Logger.cpp64
-rw-r--r--src/debug/log/Logger.hpp61
-rw-r--r--src/debug/log/RollingLogFollow.hpp70
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;
+ };
+ };
+}