From 622ea5d83ddb2b6fb9d72c9a8eb3feb9ce00838d Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 1 Sep 2025 20:05:35 +1200 Subject: [PATCH] feat: Update 4 files --- source/src/config.cpp | 34 ++++++++++++++++++++++++- source/src/config.hpp | 3 +++ source/src/utils/output.cpp | 51 ++++++++++++++++++++++++++++++++----- source/src/utils/output.hpp | 3 +++ 4 files changed, 84 insertions(+), 7 deletions(-) diff --git a/source/src/config.cpp b/source/src/config.cpp index 5d31bea..49e3092 100644 --- a/source/src/config.cpp +++ b/source/src/config.cpp @@ -47,7 +47,8 @@ bool config::load_config() { // load json config file. "server_definition_paths", "template_local_paths", "template_registries", - "backups_path" + "backups_path", + "log_level" }; std::set deprecated_fields = { @@ -107,8 +108,24 @@ bool config::load_config() { // load json config file. } } } + + // Validate log_level if present + if (mConfig.contains("log_level")) { + if (!mConfig["log_level"].is_string()) { + error << "'log_level' must be a string" << std::endl; + return false; + } + std::string log_level = mConfig["log_level"]; + std::set valid_levels = {"debug", "info", "warning", "error"}; + if (valid_levels.find(log_level) == valid_levels.end()) { + error << "Invalid log_level '" << log_level << "'" << std::endl; + error << "Valid levels are: debug, info, warning, error" << std::endl; + return false; + } + } mIsConfigSet = true; + apply_log_level(); // Apply the log level from config return true; } @@ -154,6 +171,7 @@ bool config::save_config(bool create_aux_directories) mConfig["backups_path"] = { dropshell_base + "/backups" }; + mConfig["log_level"] = "info"; // Default log level } config_file << mConfig.dump(4); @@ -275,4 +293,18 @@ tRegistryEntry::~tRegistryEntry() { } +std::string config::get_log_level() const +{ + if (!mIsConfigSet || !mConfig.contains("log_level")) + return "info"; // Default log level + + return mConfig["log_level"]; +} + +void config::apply_log_level() +{ + std::string level = get_log_level(); + set_log_level(level); +} + } // namespace dropshell \ No newline at end of file diff --git a/source/src/config.hpp b/source/src/config.hpp index 62bce98..5f8021b 100644 --- a/source/src/config.hpp +++ b/source/src/config.hpp @@ -39,6 +39,9 @@ class config { std::string get_server_create_path(); std::string get_template_create_path(); std::string get_backups_path(); + + std::string get_log_level() const; + void apply_log_level(); private: nlohmann::json mConfig; diff --git a/source/src/utils/output.cpp b/source/src/utils/output.cpp index 35eb7e2..efaf422 100644 --- a/source/src/utils/output.cpp +++ b/source/src/utils/output.cpp @@ -6,6 +6,16 @@ namespace dropshell { // Mutex to synchronize output std::mutex output_mutex; + + // Global log level + enum class LogLevel { + DEBUG = 0, + INFO = 1, + WARNING = 2, + ERROR = 3 + }; + + static LogLevel current_log_level = LogLevel::INFO; // ANSI colour codes constexpr const char *GREY = "\033[90m"; @@ -29,16 +39,30 @@ namespace dropshell {"[WRN]", WARNING_COLOUR}, {"[ERR]", ERROR_COLOUR}}; + // Null streambuf that discards all output + class NullStreambuf : public std::streambuf + { + protected: + int overflow(int c) override + { + return c; // Just discard the character + } + }; + // Custom streambuf to prefix and colour each line class PrefixStreambuf : public std::streambuf { public: - PrefixStreambuf(std::ostream &dest, const char *tag, const char *colour) - : dest_(dest), tag_(tag), colour_(colour), at_line_start_(true) {} + PrefixStreambuf(std::ostream &dest, const char *tag, const char *colour, LogLevel level) + : dest_(dest), tag_(tag), colour_(colour), level_(level), at_line_start_(true) {} protected: int overflow(int c) override { + // Check if this log level should be output + if (level_ < current_log_level) + return c; // Discard if below current log level + std::lock_guard lock(output_mutex); if (c == EOF) return !EOF; @@ -60,13 +84,14 @@ namespace dropshell std::ostream &dest_; const char *tag_; const char *colour_; + LogLevel level_; bool at_line_start_; }; - PrefixStreambuf debug_buf(std::clog, stream_infos[0].tag, stream_infos[0].colour); - PrefixStreambuf info_buf(std::clog, stream_infos[1].tag, stream_infos[1].colour); - PrefixStreambuf warning_buf(std::clog, stream_infos[2].tag, stream_infos[2].colour); - PrefixStreambuf error_buf(std::cerr, stream_infos[3].tag, stream_infos[3].colour); + PrefixStreambuf debug_buf(std::clog, stream_infos[0].tag, stream_infos[0].colour, LogLevel::DEBUG); + PrefixStreambuf info_buf(std::clog, stream_infos[1].tag, stream_infos[1].colour, LogLevel::INFO); + PrefixStreambuf warning_buf(std::clog, stream_infos[2].tag, stream_infos[2].colour, LogLevel::WARNING); + PrefixStreambuf error_buf(std::cerr, stream_infos[3].tag, stream_infos[3].colour, LogLevel::ERROR); std::ostream debug_stream(&debug_buf); std::ostream info_stream(&info_buf); @@ -130,4 +155,18 @@ namespace dropshell SetColour(sColour::RESET, os_); } + void set_log_level(const std::string& level) + { + if (level == "debug") + current_log_level = LogLevel::DEBUG; + else if (level == "info") + current_log_level = LogLevel::INFO; + else if (level == "warning") + current_log_level = LogLevel::WARNING; + else if (level == "error") + current_log_level = LogLevel::ERROR; + else + current_log_level = LogLevel::INFO; // Default to info if unknown + } + } // namespace dropshell \ No newline at end of file diff --git a/source/src/utils/output.hpp b/source/src/utils/output.hpp index f2c66d5..7071441 100644 --- a/source/src/utils/output.hpp +++ b/source/src/utils/output.hpp @@ -72,6 +72,9 @@ std::ostream& colourstream(sColour colour); // Set colour for a stream void SetColour(sColour colour, std::ostream& os = std::cerr); +// Set the global log level +void set_log_level(const std::string& level); + class SwitchColour { public: