debug: move to hyprutils' logger (#12673)

This commit is contained in:
Vaxry 2025-12-18 17:23:24 +00:00 committed by GitHub
parent f88deb928a
commit 6175ecd4c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
147 changed files with 1696 additions and 1709 deletions

View file

@ -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<sockaddr*>(&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);
}

View file

@ -1,78 +0,0 @@
#include "Log.hpp"
#include "../defines.hpp"
#include "RollingLogFollow.hpp"
#include <fstream>
#include <print>
#include <fcntl.h>
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<std::mutex> 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);
}
}

View file

@ -1,75 +0,0 @@
#pragma once
#include <string>
#include <format>
#include <iostream>
#include <fstream>
#include <chrono>
#include <mutex>
#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 <typename... Args>
//NOLINTNEXTLINE
void log(eLogLevel level, std::format_string<Args...> 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<std::chrono::days>(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::days>(std::chrono::system_clock::now())};
#endif
logMsg += std::format("[{}] ", hms);
}
// 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);
}
};

View file

@ -2,7 +2,7 @@
#ifdef USE_TRACY_GPU
#include "Log.hpp"
#include "log/Logger.hpp"
#include <GL/gl.h>
#include <GLES2/gl2ext.h>

View file

@ -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();
}

64
src/debug/log/Logger.cpp Normal file
View file

@ -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;
}

61
src/debug/log/Logger.hpp Normal file
View file

@ -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;
};

View file

@ -1,9 +1,11 @@
#pragma once
#include <shared_mutex>
#include <unordered_map>
#include <format>
#include <vector>
// NOLINTNEXTLINE(readability-identifier-naming)
namespace Debug {
namespace Log {
struct SRollingLogFollow {
std::unordered_map<int, std::string> m_socketToRollingLogFollowQueue;
std::shared_mutex m_mutex;
@ -30,12 +32,14 @@ namespace Debug {
return ret;
};
void addLog(const std::string& log) {
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 + "\n";
for (const auto& p : m_socketToRollingLogFollowQueue) {
m_socketToRollingLogFollowQueue[p.first] += log;
m_socketToRollingLogFollowQueue[p.first] += "\n";
}
}
bool isRunning() {