Skip to content

Commit

Permalink
feat: [hyprctl, core] added --follow option to rolliglog
Browse files Browse the repository at this point in the history
  • Loading branch information
Крылов Александр committed Jun 3, 2024
1 parent 0ebb43c commit f5417f9
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 11 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ uninstall:
pluginenv:
@echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n"
@exit 1

installheaders:
@if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi

Expand Down Expand Up @@ -105,3 +105,6 @@ asan:
@echo "Hyprland done"

ASAN_OPTIONS="detect_odr_violation=0,log_path=asan.log" HYPRLAND_NO_CRASHREPORTER=1 ./build/Hyprland -c ~/.config/hypr/hyprland.conf

onlybuild:
cmake --build ./build --config Debug --target all
74 changes: 66 additions & 8 deletions hyprctl/main.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include <ctype.h>
#include <cctype>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
Expand All @@ -12,7 +12,7 @@
#include <unistd.h>
#include <ranges>
#include <algorithm>
#include <signal.h>
#include <csignal>
#include <format>

#include <iostream>
Expand All @@ -22,8 +22,9 @@
#include <vector>
#include <deque>
#include <filesystem>
#include <stdarg.h>
#include <cstdarg>
#include <regex>
#include <sys/socket.h>

#include "Strings.hpp"

Expand Down Expand Up @@ -90,13 +91,55 @@ std::vector<SInstanceData> instances() {
return result;
}

int request(std::string arg, int minArgs = 0) {
static volatile bool sigintReceived = false;
void intHandler(int sig) {
sigintReceived = true;
std::cout << "[hyprctl] SIGINT received, closing connection" << std::endl;
}

int rollingRead(const int socket) {
sigintReceived = false;
signal(SIGINT, intHandler);

constexpr size_t BUFFER_SIZE = 8192;
char buffer[BUFFER_SIZE] = {0};
int sizeWritten = 0;
std::cout << "[hyprctl] reading from socket following up log:" << std::endl;
while (!sigintReceived) {
sizeWritten = read(socket, buffer, BUFFER_SIZE);
if (sizeWritten < 0 && errno != EAGAIN) {
if (errno != EINTR) {
std::cout << "Couldn't read (5) " << strerror(errno) <<":"<< errno << std::endl;
}
close(socket);
return 5;
}

if (sizeWritten == 0)
break;

if (sizeWritten > 0) {
std::cout << std::string(buffer, sizeWritten);
memset(buffer, 0, BUFFER_SIZE);
}

usleep(100000);
}
close(socket);
return 0;
}


int request(std::string arg, int minArgs = 0, bool needRoll = false) {
const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);

auto t = timeval{.tv_sec = 0, .tv_usec = 100000};
setsockopt(SERVERSOCKET, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(struct timeval));

const auto ARGS = std::count(arg.begin(), arg.end(), ' ');

if (ARGS < minArgs) {
std::cout << "Not enough arguments, expected at least " << minArgs;
std::cout << "Not enough arguments in '"<< arg << "', expected at least " << minArgs;
return -1;
}

Expand Down Expand Up @@ -131,6 +174,10 @@ int request(std::string arg, int minArgs = 0) {
return 4;
}

if (needRoll){
return rollingRead(SERVERSOCKET);
}

std::string reply = "";
char buffer[8192] = {0};

Expand Down Expand Up @@ -280,6 +327,7 @@ int main(int argc, char** argv) {
std::string fullArgs = "";
const auto ARGS = splitArgs(argc, argv);
bool json = false;
bool needRoll = false;
std::string overrideInstance = "";

for (std::size_t i = 0; i < ARGS.size(); ++i) {
Expand All @@ -299,6 +347,9 @@ int main(int argc, char** argv) {
fullArgs += "a";
} else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) {
fullArgs += "c";
} else if ((ARGS[i] == "-f" || ARGS[i] == "--follow") && !fullArgs.contains("f")) {
fullArgs += "f";
needRoll = true;
} else if (ARGS[i] == "--batch") {
fullRequest = "--batch ";
} else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
Expand Down Expand Up @@ -356,6 +407,11 @@ int main(int argc, char** argv) {
return 0;
}

if (needRoll && !fullRequest.contains("/rollinglog")) {
std::cout << "only 'rollinglog' command supports '--follow' option" << std::endl;
return 1;
}

if (overrideInstance.contains("_"))
instanceSignature = overrideInstance;
else if (!overrideInstance.empty()) {
Expand Down Expand Up @@ -415,6 +471,8 @@ int main(int argc, char** argv) {
exitStatus = request(fullRequest, 1);
else if (fullRequest.contains("/--help"))
std::cout << USAGE << std::endl;
else if (fullRequest.contains("/rollinglog") && needRoll)
exitStatus = request(fullRequest, 0, true);
else {
exitStatus = request(fullRequest);
}
Expand Down
59 changes: 57 additions & 2 deletions src/debug/HyprCtl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "../devices/IKeyboard.hpp"
#include "../devices/ITouch.hpp"
#include "../devices/Tablet.hpp"
#include "debug/RollingLogFollow.hpp"
#include "config/ConfigManager.hpp"

static void trimTrailingComma(std::string& str) {
Expand Down Expand Up @@ -1727,6 +1728,53 @@ 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) {
Debug::log(LOG, "In followlog thread, got connection, start writing: {}", conn);
constexpr uint MAX_RETRY = 10;
//will be finished, when reading side close connection
std::thread([conn]() {
uint retries = 0;
while (Debug::RollingLogFollow::Get().IsRunning()) {
if (Debug::RollingLogFollow::Get().isEmpty(conn) && retries < MAX_RETRY) {
retries++;
sleep(1);
continue;
}

auto line = Debug::RollingLogFollow::Get().GetLog(conn);
if (!successWrite(conn, line) && retries < MAX_RETRY) {
retries++;
// We cannot write, when connection is closed. So thread will successfully exit by himself
break;
}

retries = 0;
usleep(100000);
}
close(conn);
Debug::RollingLogFollow::Get().StopFor(conn);
}).detach();
}

bool isFollowUpRollingLogRequest(const std::string& request) {
return request.contains("rollinglog") && request.find_first_of('f') != std::string::npos ;
}

int hyprCtlFDTick(int fd, uint32_t mask, void* data) {
if (mask & WL_EVENT_ERROR || mask & WL_EVENT_HANGUP)
return 0;
Expand Down Expand Up @@ -1770,9 +1818,16 @@ 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();
Expand Down
5 changes: 5 additions & 0 deletions src/debug/Log.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "Log.hpp"
#include "../defines.hpp"
#include "../Compositor.hpp"
#include "RollingLogFollow.hpp"

#include <fstream>
#include <iostream>
Expand Down Expand Up @@ -73,6 +74,10 @@ 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;
Expand Down
63 changes: 63 additions & 0 deletions src/debug/RollingLogFollow.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#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;

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 "RollingLogFollow, got " + std::to_string(socketToRollingLogFollowQueue.size()) + " connections";
}

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] = "[LOG] Following log to socket: " + std::to_string(socket) + " started"+ "\n";
running = true;
}
static RollingLogFollow& Get() {
static RollingLogFollow instance;
static std::mutex gm;
std::lock_guard<std::mutex> lock(gm);
return instance;
};
};
}

0 comments on commit f5417f9

Please sign in to comment.