From 07a11656fadf32e6e4749e87b86683305f93cfd8 Mon Sep 17 00:00:00 2001 From: Brett Laptop Date: Fri, 7 Mar 2025 18:40:43 -0500 Subject: [PATCH] config works --- CMakeLists.txt | 2 +- include/blt/fs/stream_wrappers.h | 2 +- include/blt/logging/logging.h | 306 +++++++++++++-------------- include/blt/logging/logging_config.h | 78 ++++++- src/blt/logging/logging.cpp | 32 ++- src/blt/logging/logging_config.cpp | 90 +++++++- tests/logger_tests.cpp | 4 +- 7 files changed, 343 insertions(+), 171 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0effd4..5bc147a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.20) include(cmake/color.cmake) -set(BLT_VERSION 5.2.1) +set(BLT_VERSION 5.2.2) set(BLT_TARGET BLT) diff --git a/include/blt/fs/stream_wrappers.h b/include/blt/fs/stream_wrappers.h index 2a5094d..dff7024 100644 --- a/include/blt/fs/stream_wrappers.h +++ b/include/blt/fs/stream_wrappers.h @@ -99,7 +99,7 @@ namespace blt::fs void write(const T& t) { static_assert(std::is_trivially_copyable_v); - m_writer->write(reinterpret_cast(&t), sizeof(T)); + m_writer->write(reinterpret_cast(&t), sizeof(T)); } template diff --git a/include/blt/logging/logging.h b/include/blt/logging/logging.h index 2c5441a..35db5bc 100644 --- a/include/blt/logging/logging.h +++ b/include/blt/logging/logging.h @@ -25,181 +25,181 @@ #include #include #include +#include #include #include namespace blt::logging { - namespace detail - { - } + namespace detail + {} - struct logger_t - { - explicit logger_t(std::ostream& stream): m_stream(stream) - { - } + struct logger_t + { + explicit logger_t(std::ostream& stream): m_stream(stream) + {} - template - std::string log(std::string fmt, Args&&... args) - { - auto sequence = std::make_integer_sequence{}; - m_arg_print_funcs.clear(); - m_arg_print_funcs.resize(sizeof...(Args)); - create_conv_funcs(sequence, std::forward(args)...); - compile(std::move(fmt)); - process_strings(); - return to_string(); - } + template + std::string log(std::string fmt, Args&&... args) + { + auto sequence = std::make_integer_sequence{}; + m_arg_print_funcs.clear(); + m_arg_print_funcs.resize(sizeof...(Args)); + create_conv_funcs(sequence, std::forward(args)...); + compile(std::move(fmt)); + process_strings(); + return to_string(); + } - [[nodiscard]] std::string to_string() const; + [[nodiscard]] std::string to_string() const; - private: - template - void create_conv_funcs(std::integer_sequence, Args&&... args) - { - ((handle_func(std::forward(args))), ...); - } + private: + template + void create_conv_funcs(std::integer_sequence, Args&&... args) + { + ((handle_func(std::forward(args))), ...); + } - template - void handle_func(const T& t) - { - m_arg_print_funcs[index] = [&t, this](std::ostream& stream, const fmt_spec_t& type) - { - switch (type.sign) - { - case fmt_sign_t::SPACE: - if constexpr (std::is_arithmetic_v) - { - if (type.type != fmt_type_t::BINARY && static_cast(t) >= 0l) - stream << ' '; - } - break; - case fmt_sign_t::PLUS: - case fmt_sign_t::MINUS: - break; - } - switch (type.type) - { - case fmt_type_t::BINARY: - { - if constexpr (std::is_trivially_copyable_v) - { - // copy bytes of type - char buffer[sizeof(T)]; - std::memcpy(buffer, &t, sizeof(T)); - // display prefix - if (type.alternate_form) - stream << '0' << (type.uppercase ? 'B' : 'b'); - // print bytes - for (size_t i = 0; i < sizeof(T); ++i) - { - // print bits - for (size_t j = 0; j < 8; ++j) - stream << ((buffer[i] & (1 << j)) ? '1' : '0'); - // special seperator defined via sign (weird hack, change?) - if (type.sign == fmt_sign_t::SPACE && i != sizeof(T) - 1) - stream << ' '; - } - } - else - { - if constexpr (blt::meta::is_streamable_v) - stream << t; - else - stream << "{INVALID TYPE}"; - } - break; - } - case fmt_type_t::CHAR: - if constexpr (std::is_arithmetic_v || std::is_convertible_v) - { - stream << static_cast(t); - } - else - { - if constexpr (blt::meta::is_streamable_v) - stream << t; - else - stream << "{INVALID TYPE}"; - } - break; - case fmt_type_t::TYPE: - stream << blt::type_string(); - break; - default: - handle_type(stream, type); - if constexpr (blt::meta::is_streamable_v) - { - if constexpr (std::is_same_v || std::is_same_v) - stream << static_cast(t); - else if constexpr (std::is_same_v) - stream << static_cast(t); - else - stream << t; - }else - stream << "{INVALID TYPE}"; - } - }; - } + template + void handle_func(const T& t) + { + m_arg_print_funcs[index] = [&t, this](std::ostream& stream, const fmt_spec_t& type) { + switch (type.sign) + { + case fmt_sign_t::SPACE: + if constexpr (std::is_arithmetic_v) + { + if (type.type != fmt_type_t::BINARY && static_cast(t) >= 0l) + stream << ' '; + } + break; + case fmt_sign_t::PLUS: + case fmt_sign_t::MINUS: + break; + } + switch (type.type) + { + case fmt_type_t::BINARY: + { + if constexpr (std::is_trivially_copyable_v) + { + // copy bytes of type + char buffer[sizeof(T)]; + std::memcpy(buffer, &t, sizeof(T)); + // display prefix + if (type.alternate_form) + stream << '0' << (type.uppercase ? 'B' : 'b'); + // print bytes + for (size_t i = 0; i < sizeof(T); ++i) + { + // print bits + for (size_t j = 0; j < 8; ++j) + stream << ((buffer[i] & (1 << j)) ? '1' : '0'); + // special seperator defined via sign (weird hack, change?) + if (type.sign == fmt_sign_t::SPACE && i != sizeof(T) - 1) + stream << ' '; + } + } else + { + if constexpr (blt::meta::is_streamable_v) + stream << t; + else + stream << "{INVALID TYPE}"; + } + break; + } + case fmt_type_t::CHAR: + if constexpr (std::is_arithmetic_v || std::is_convertible_v) + { + stream << static_cast(t); + } else + { + if constexpr (blt::meta::is_streamable_v) + stream << t; + else + stream << "{INVALID TYPE}"; + } + break; + case fmt_type_t::TYPE: + stream << blt::type_string(); + break; + default: + handle_type(stream, type); + if constexpr (blt::meta::is_streamable_v) + { + if constexpr (std::is_same_v || std::is_same_v) + stream << static_cast(t); + else if constexpr (std::is_same_v) + stream << static_cast(t); + else + stream << t; + } else + stream << "{INVALID TYPE}"; + } + }; + } - [[nodiscard]] size_t find_ending_brace(size_t begin) const; - void setup_stream(const fmt_spec_t& spec) const; - void process_strings(); - static void handle_type(std::ostream& stream, const fmt_spec_t& spec); + [[nodiscard]] size_t find_ending_brace(size_t begin) const; + void setup_stream(const fmt_spec_t& spec) const; + void process_strings(); + static void handle_type(std::ostream& stream, const fmt_spec_t& spec); - static void exponential(std::ostream& stream); - static void fixed(std::ostream& stream); + static void exponential(std::ostream& stream); + static void fixed(std::ostream& stream); - void compile(std::string fmt); + void compile(std::string fmt); - std::optional> consume_to_next_fmt(); + std::optional> consume_to_next_fmt(); - std::string m_fmt; - std::ostream& m_stream; - fmt_parser_t m_parser{m_arg_print_funcs}; - // normal sections of string - std::vector m_string_sections; - // processed format specs - std::vector m_fmt_specs; - std::vector> m_arg_print_funcs; - size_t m_last_fmt_pos = 0; - size_t m_arg_pos = 0; - }; + std::string m_fmt; + std::ostream& m_stream; + fmt_parser_t m_parser{m_arg_print_funcs}; + // normal sections of string + std::vector m_string_sections; + // processed format specs + std::vector m_fmt_specs; + std::vector> m_arg_print_funcs; + size_t m_last_fmt_pos = 0; + size_t m_arg_pos = 0; + }; - void print(const std::string& str); + void print(const std::string& str); - void newline(); + void newline(); - logger_t& get_global_logger(); + logger_t& get_global_logger(); - template - void print(std::string fmt, Args&&... args) - { - auto& logger = get_global_logger(); - print(logger.log(std::move(fmt), std::forward(args)...)); - } + logging_config_t& get_global_config(); - template - void print(std::ostream& stream, std::string fmt, Args&&... args) - { - auto& logger = get_global_logger(); - stream << logger.log(std::move(fmt), std::forward(args)...); - } + void set_thread_name(const std::string& name); - template - void println(std::string fmt, Args&&... args) - { - print(std::move(fmt), std::forward(args)...); - newline(); - } + template + void print(std::string fmt, Args&&... args) + { + auto& logger = get_global_logger(); + print(logger.log(std::move(fmt), std::forward(args)...)); + } - template - void println(std::ostream& stream, std::string fmt, Args&&... args) - { - print(stream, std::move(fmt), std::forward(args)...); - stream << std::endl; - } + template + void print(std::ostream& stream, std::string fmt, Args&&... args) + { + auto& logger = get_global_logger(); + stream << logger.log(std::move(fmt), std::forward(args)...); + } + + template + void println(std::string fmt, Args&&... args) + { + print(std::move(fmt), std::forward(args)...); + newline(); + } + + template + void println(std::ostream& stream, std::string fmt, Args&&... args) + { + print(stream, std::move(fmt), std::forward(args)...); + stream << std::endl; + } } #endif // BLT_LOGGING_LOGGING_H diff --git a/include/blt/logging/logging_config.h b/include/blt/logging/logging_config.h index 5ae7b93..afaad32 100644 --- a/include/blt/logging/logging_config.h +++ b/include/blt/logging/logging_config.h @@ -22,9 +22,9 @@ #include #include #include -#include -#include #include +#include +#include namespace blt::logging { @@ -121,6 +121,79 @@ namespace blt::logging friend logger_t; public: + logging_config_t() + { + compile(); + } + + void compile(); + + logging_config_t& add_log_output(fs::writer_t* writer) + { + log_outputs.push_back(writer); + return *this; + } + + logging_config_t& set_log_format(std::string format) + { + log_format = std::move(format); + compile(); + return *this; + } + + logging_config_t& set_error_color(std::string color) + { + error_color = std::move(color); + compile(); + return *this; + } + + logging_config_t& set_log_level_colors(std::array colors) + { + log_level_colors = std::move(colors); + compile(); + return *this; + } + + logging_config_t& set_log_level_names(std::array names) + { + log_level_names = std::move(names); + return *this; + } + + logging_config_t& set_level(const log_level_t level) + { + this->level = level; + return *this; + } + + logging_config_t& set_use_color(const bool use_color) + { + this->use_color = use_color; + compile(); + return *this; + } + + logging_config_t& set_print_full_name(const bool print_full_name) + { + this->print_full_name = print_full_name; + return *this; + } + + logging_config_t& set_ensure_alignment(const bool ensure_alignment) + { + this->ensure_alignment = ensure_alignment; + return *this; + } + + [[nodiscard]] std::pair&, const std::vector&> get_log_tag_tokens() const + { + return {log_tag_tokens, log_tag_content}; + } + + private: + std::vector log_tag_content; + std::vector log_tag_tokens; // wrappers for streams exist in blt/fs/stream_wrappers.h std::vector log_outputs = get_default_log_outputs(); std::string log_format = get_default_log_format(); @@ -135,7 +208,6 @@ namespace blt::logging // This creates output where the user message always starts at the same column. bool ensure_alignment = true; - private: static std::string get_default_log_format(); static std::vector get_default_log_outputs(); static std::array get_default_log_level_colors(); diff --git a/src/blt/logging/logging.cpp b/src/blt/logging/logging.cpp index 18fc5e7..f0cc3ec 100644 --- a/src/blt/logging/logging.cpp +++ b/src/blt/logging/logging.cpp @@ -17,19 +17,37 @@ */ #include #include +#include #include +#include #include #include +#include #include namespace blt::logging { + struct global_context_t + { + logging_config_t global_config; + std::mutex thread_name_mutex; + hashmap_t thread_names; + }; + + static global_context_t global_context; + struct logging_thread_context_t { std::stringstream stream; logger_t logger{stream}; }; + logging_thread_context_t& get_thread_context() + { + thread_local logging_thread_context_t context; + return context; + } + std::string logger_t::to_string() const { return dynamic_cast(m_stream).str(); @@ -195,8 +213,7 @@ namespace blt::logging logger_t& get_global_logger() { - thread_local logging_thread_context_t context; - return context.logger; + return get_thread_context().logger; } void print(const std::string& str) @@ -208,4 +225,15 @@ namespace blt::logging { std::cout << std::endl; } + + logging_config_t& get_global_config() + { + return global_context.global_config; + } + + void set_thread_name(const std::string& name) + { + std::scoped_lock lock{global_context.thread_name_mutex}; + global_context.thread_names[std::this_thread::get_id()] = name; + } } diff --git a/src/blt/logging/logging_config.cpp b/src/blt/logging/logging_config.cpp index 2d1295c..9ca501d 100644 --- a/src/blt/logging/logging_config.cpp +++ b/src/blt/logging/logging_config.cpp @@ -52,7 +52,86 @@ namespace blt::logging return map; } - hashmap_t tag_map = make_map(); + std::array(log_tag_token_t::CONTENT)> tag_known_values{ + // year + false, + // month + false, + // day + false, + // hour + false, + // minute + false, + // second + false, + // ms + false, + // ns + false, + // unix + false, + // iso year + false, + // time + false, + // full_time + false, + // lc + true, + // ec + true, + // conditional error + false, + // reset + true, + // log level + false, + // thread_name + false, + // file + false, + // line + false, + // str + false + }; + } + + void logging_config_t::compile() + { + static hashmap_t tag_map = tags::detail::make_map(); + log_tag_content.clear(); + log_tag_tokens.clear(); + + size_t i = 0; + for (; i < log_format.size(); ++i) + { + size_t start = i; + while (i < log_format.size() && log_format[i] != '{') + ++i; + if (i == log_format.size() || (i < log_format.size() && (i - start) > 0)) + { + log_tag_content.emplace_back(std::string_view(log_format.data() + start, i - start)); + log_tag_tokens.emplace_back(tags::detail::log_tag_token_t::CONTENT); + if (i == log_format.size()) + break; + } + start = i; + while (i < log_format.size() && log_format[i] != '}') + ++i; + const auto tag = std::string_view(log_format.data() + start, i - start + 1); + auto it = tag_map.find(tag); + if (it == tag_map.end()) + throw std::runtime_error("Invalid log tag: " + std::string(tag)); + log_tag_tokens.emplace_back(it->second); + } + + if (i < log_format.size()) + { + log_tag_content.emplace_back(std::string_view(log_format.data() + i, log_format.size() - i)); + log_tag_tokens.emplace_back(tags::detail::log_tag_token_t::CONTENT); + } } std::string logging_config_t::get_default_log_format() @@ -90,14 +169,7 @@ namespace blt::logging std::array logging_config_t::get_default_log_level_names() { - return { - "TRACE", - "DEBUG", - "INFO", - "WARN", - "ERROR", - "FATAL", - }; + return {"TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL",}; } std::string logging_config_t::get_default_error_color() diff --git a/tests/logger_tests.cpp b/tests/logger_tests.cpp index 527dcb2..03870f9 100644 --- a/tests/logger_tests.cpp +++ b/tests/logger_tests.cpp @@ -160,10 +160,10 @@ int main() std::ofstream os("test.txt"); blt::fs::fstream_writer_t wtr(os); - blt::fs::writer_wrapper_t writer(wtr); + blt::fs::writer_string_wrapper_t writer(wtr); writer.write("This is a println with a stream\n"); - writer.write("This is a mixed print"); + writer.write("This is a mixed print "); writer.write(std::to_string(25)); writer.write(" with multiple types "); writer.write(std::to_string(34.23340));