hyprctl: added --follow option to rolliglog (#6325)

Co-authored-by: Крылов Александр <aleksandr.krylov@hyperus.team>
This commit is contained in:
Alexander 2024-06-14 13:11:40 +03:00 committed by GitHub
parent 9cd5b3587c
commit b2590b58c5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 185 additions and 13 deletions

View file

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

View file

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

View file

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