mirror of
https://github.com/hyprwm/hyprutils.git
synced 2024-11-17 02:35:58 +01:00
debug: init
This commit is contained in:
parent
8976e3f6a5
commit
0db21e96de
3 changed files with 213 additions and 0 deletions
76
include/hyprutils/debug/Log.hpp
Normal file
76
include/hyprutils/debug/Log.hpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <format>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
#include "RollingLogFollow.hpp"
|
||||||
|
|
||||||
|
#define LOGMESSAGESIZE 1024
|
||||||
|
#define ROLLING_LOG_SIZE 4096
|
||||||
|
|
||||||
|
enum LogLevel {
|
||||||
|
NONE = -1,
|
||||||
|
LOG = 0,
|
||||||
|
WARN,
|
||||||
|
ERR,
|
||||||
|
CRIT,
|
||||||
|
INFO,
|
||||||
|
TRACE
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Debug {
|
||||||
|
inline std::string logFile;
|
||||||
|
inline std::ofstream logOfs;
|
||||||
|
inline int64_t* const* disableLogs = nullptr;
|
||||||
|
inline int64_t* const* disableTime = nullptr;
|
||||||
|
inline bool disableStdout = false;
|
||||||
|
inline bool trace = false;
|
||||||
|
inline bool shuttingDown = false;
|
||||||
|
inline int64_t* const* coloredLogs = nullptr;
|
||||||
|
|
||||||
|
inline std::string rollingLog = ""; // rolling log contains the ROLLING_LOG_SIZE tail of the log
|
||||||
|
inline std::mutex logMutex;
|
||||||
|
|
||||||
|
void init(const std::string& IS, const std::string& name);
|
||||||
|
void close();
|
||||||
|
|
||||||
|
//
|
||||||
|
void log(LogLevel level, std::string str);
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void log(LogLevel level, std::format_string<Args...> fmt, Args&&... args) {
|
||||||
|
std::lock_guard<std::mutex> guard(logMutex);
|
||||||
|
|
||||||
|
if (level == TRACE && !trace)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (shuttingDown)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string logMsg = "";
|
||||||
|
|
||||||
|
// print date and time to the ofs
|
||||||
|
if (disableTime && !**disableTime) {
|
||||||
|
#ifndef _LIBCPP_VERSION
|
||||||
|
const auto zt = std::chrono::zoned_time{std::chrono::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);
|
||||||
|
logMutex.unlock();
|
||||||
|
}
|
||||||
|
};
|
70
include/hyprutils/debug/RollingLogFollow.hpp
Normal file
70
include/hyprutils/debug/RollingLogFollow.hpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <format>
|
||||||
|
#include <mutex>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
67
src/debug/Log.cpp
Normal file
67
src/debug/Log.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include <hyprutils/debug/Log.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
void Debug::init(const std::string& IS, const std::string& name) {
|
||||||
|
logFile = IS + "/" + name + ".log";
|
||||||
|
logOfs.open(logFile, std::ios::out | std::ios::app);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Debug::close() {
|
||||||
|
logOfs.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Debug::log(LogLevel level, std::string str) {
|
||||||
|
if (level == TRACE && !trace)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (shuttingDown)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string coloredStr = str;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
rollingLog += str + "\n";
|
||||||
|
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
|
||||||
|
logOfs << str << "\n";
|
||||||
|
logOfs.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// log it to the stdout too.
|
||||||
|
if (!disableStdout)
|
||||||
|
std::cout << ((coloredLogs && !**coloredLogs) ? str : coloredStr) << "\n";
|
||||||
|
}
|
Loading…
Reference in a new issue