aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/debug
diff options
context:
space:
mode:
authorAlexander <[email protected]>2024-06-14 13:11:40 +0300
committerGitHub <[email protected]>2024-06-14 12:11:40 +0200
commitb2590b58c51094424a9651d8df37dfab838b5bbb (patch)
treedfd12a27cddd7b19de2eec4415630db1bd5b3c84 /src/debug
parent9cd5b3587cb1e3d42b647fa230024cd0153ea9cb (diff)
downloadHyprland-b2590b58c51094424a9651d8df37dfab838b5bbb.tar.gz
Hyprland-b2590b58c51094424a9651d8df37dfab838b5bbb.zip
hyprctl: added --follow option to rolliglog (#6325)
Co-authored-by: Крылов Александр <[email protected]>
Diffstat (limited to 'src/debug')
-rw-r--r--src/debug/HyprCtl.cpp51
-rw-r--r--src/debug/Log.cpp4
-rw-r--r--src/debug/RollingLogFollow.hpp65
3 files changed, 118 insertions, 2 deletions
diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index a7e714bd..70b886f2 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -28,6 +28,7 @@ using namespace Hyprutils::String;
#include "../devices/IKeyboard.hpp"
#include "../devices/ITouch.hpp"
#include "../devices/Tablet.hpp"
+#include "debug/RollingLogFollow.hpp"
#include "config/ConfigManager.hpp"
#include "helpers/MiscFunctions.hpp"
@@ -1732,6 +1733,46 @@ std::string CHyprCtl::makeDynamicCall(const std::string& input) {
return getReply(input);
}
+bool successWrite(int fd, const std::string& data, bool needLog = true) {
+ if (write(fd, data.c_str(), data.length()) > 0)
+ return true;
+
+ if (errno == EAGAIN)
+ return true;
+
+ if (needLog)
+ Debug::log(ERR, "Couldn't write to socket. Error: " + std::string(strerror(errno)));
+
+ return false;
+}
+
+void runWritingDebugLogThread(const int conn) {
+ using namespace std::chrono_literals;
+ Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn);
+ //will be finished, when reading side close connection
+ std::thread([conn]() {
+ while (Debug::RollingLogFollow::Get().IsRunning()) {
+ if (Debug::RollingLogFollow::Get().isEmpty(conn)) {
+ std::this_thread::sleep_for(1000ms);
+ continue;
+ }
+
+ auto line = Debug::RollingLogFollow::Get().GetLog(conn);
+ if (!successWrite(conn, line))
+ // We cannot write, when connection is closed. So thread will successfully exit by itself
+ break;
+
+ std::this_thread::sleep_for(100ms);
+ }
+ close(conn);
+ Debug::RollingLogFollow::Get().StopFor(conn);
+ }).detach();
+}
+
+bool isFollowUpRollingLogRequest(const std::string& request) {
+ return request.contains("rollinglog") && request.contains("f");
+}
+
int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
return 0;
@@ -1775,9 +1816,15 @@ int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
reply = "Err: " + std::string(e.what());
}
- write(ACCEPTEDCONNECTION, reply.c_str(), reply.length());
+ successWrite(ACCEPTEDCONNECTION, reply);
- close(ACCEPTEDCONNECTION);
+ if (isFollowUpRollingLogRequest(request)) {
+ Debug::log(LOG, "Followup rollinglog request received. Starting thread to write to socket.");
+ Debug::RollingLogFollow::Get().StartFor(ACCEPTEDCONNECTION);
+ runWritingDebugLogThread(ACCEPTEDCONNECTION);
+ Debug::log(LOG, Debug::RollingLogFollow::Get().DebugInfo());
+ } else
+ close(ACCEPTEDCONNECTION);
if (g_pConfigManager->m_bWantsMonitorReload)
g_pConfigManager->ensureMonitorStatus();
diff --git a/src/debug/Log.cpp b/src/debug/Log.cpp
index 8b82c852..7547204a 100644
--- a/src/debug/Log.cpp
+++ b/src/debug/Log.cpp
@@ -1,6 +1,7 @@
#include "Log.hpp"
#include "../defines.hpp"
#include "../Compositor.hpp"
+#include "RollingLogFollow.hpp"
#include <fstream>
#include <iostream>
@@ -73,6 +74,9 @@ void Debug::log(LogLevel level, std::string str) {
if (rollingLog.size() > ROLLING_LOG_SIZE)
rollingLog = rollingLog.substr(rollingLog.size() - ROLLING_LOG_SIZE);
+ if (RollingLogFollow::Get().IsRunning())
+ RollingLogFollow::Get().AddLog(str);
+
if (!disableLogs || !**disableLogs) {
// log to a file
std::ofstream ofs;
diff --git a/src/debug/RollingLogFollow.hpp b/src/debug/RollingLogFollow.hpp
new file mode 100644
index 00000000..5ff018af
--- /dev/null
+++ b/src/debug/RollingLogFollow.hpp
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <shared_mutex>
+
+namespace Debug {
+ struct RollingLogFollow {
+ std::unordered_map<int, std::string> socketToRollingLogFollowQueue;
+ std::shared_mutex m;
+ bool 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);
+ return socketToRollingLogFollowQueue[socket].empty();
+ }
+
+ std::string DebugInfo() {
+ std::shared_lock<std::shared_mutex> r(m);
+ return std::format("RollingLogFollow, got {} connections", socketToRollingLogFollowQueue.size());
+ }
+
+ std::string GetLog(int socket) {
+ std::unique_lock<std::shared_mutex> w(m);
+
+ const std::string ret = socketToRollingLogFollowQueue[socket];
+ socketToRollingLogFollowQueue[socket] = "";
+
+ return ret;
+ };
+
+ void AddLog(std::string log) {
+ std::unique_lock<std::shared_mutex> w(m);
+ running = true;
+ std::vector<int> to_erase;
+ for (const auto& p : socketToRollingLogFollowQueue)
+ socketToRollingLogFollowQueue[p.first] += log + "\n";
+ }
+
+ bool IsRunning() {
+ std::shared_lock<std::shared_mutex> r(m);
+ return running;
+ }
+
+ void StopFor(int socket) {
+ std::unique_lock<std::shared_mutex> w(m);
+ socketToRollingLogFollowQueue.erase(socket);
+ if (socketToRollingLogFollowQueue.empty())
+ running = false;
+ }
+
+ void StartFor(int socket) {
+ std::unique_lock<std::shared_mutex> w(m);
+ socketToRollingLogFollowQueue[socket] = std::format("[LOG] Following log to socket: {} started\n", socket);
+ running = true;
+ }
+
+ static RollingLogFollow& Get() {
+ static RollingLogFollow instance;
+ static std::mutex gm;
+ std::lock_guard<std::mutex> lock(gm);
+ return instance;
+ };
+ };
+}