From 2b1086ee15a2969c3422d8ba1d85454b23d65bbd Mon Sep 17 00:00:00 2001 From: Brett Date: Mon, 10 Mar 2025 10:27:08 -0400 Subject: [PATCH] injectors --- CMakeLists.txt | 2 +- include/blt/logging/fwddecl.h | 2 + include/blt/logging/injector.h | 41 +++ include/blt/logging/logging_config.h | 17 +- src/blt/logging/logging.cpp | 402 +++++++++++++-------------- 5 files changed, 258 insertions(+), 206 deletions(-) create mode 100644 include/blt/logging/injector.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 672292b..1be4e27 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.8) +set(BLT_VERSION 5.2.9) set(BLT_TARGET BLT) diff --git a/include/blt/logging/fwddecl.h b/include/blt/logging/fwddecl.h index 5c8b7c0..47ecdd2 100644 --- a/include/blt/logging/fwddecl.h +++ b/include/blt/logging/fwddecl.h @@ -30,6 +30,8 @@ namespace blt::logging struct fmt_token_t; class fmt_tokenizer_t; class fmt_parser_t; + + class injector_t; } #endif //BLT_LOGGING_FWDDECL_H diff --git a/include/blt/logging/injector.h b/include/blt/logging/injector.h new file mode 100644 index 0000000..313f5bd --- /dev/null +++ b/include/blt/logging/injector.h @@ -0,0 +1,41 @@ +#pragma once +/* + * Copyright (C) 2024 Brett Terpstra + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef BLT_LOGGING_INJECTOR_H +#define BLT_LOGGING_INJECTOR_H + +namespace blt::logging +{ + struct injector_output_t + { + std::string new_logging_output; + // should we continue processing the injector call chain? + bool should_continue; + // should we log the resulting string at the end of the injector call chain? If false for any injector, it becomes false for all injectors. + bool should_log; + }; + + class injector_t + { + public: + virtual ~injector_t() = default; + virtual injector_output_t inject(const std::string& input) = 0; + }; +} + +#endif //BLT_LOGGING_INJECTOR_H diff --git a/include/blt/logging/logging_config.h b/include/blt/logging/logging_config.h index f5cad5a..199a7e6 100644 --- a/include/blt/logging/logging_config.h +++ b/include/blt/logging/logging_config.h @@ -20,6 +20,7 @@ #define BLT_LOGGING_LOGGING_CONFIG_H #include +#include #include #include #include @@ -133,9 +134,15 @@ namespace blt::logging void compile(); - logging_config_t& add_log_output(fs::writer_t* writer) + logging_config_t& add_log_output(fs::writer_t& writer) { - m_log_outputs.push_back(writer); + m_log_outputs.push_back(&writer); + return *this; + } + + logging_config_t& add_injector(injector_t* injector) + { + m_injectors.push_back(std::unique_ptr(injector)); return *this; } @@ -200,8 +207,7 @@ namespace blt::logging i32 line) const; private: - std::vector m_log_tag_content; - std::vector m_log_tag_tokens; + std::vector> m_injectors; // wrappers for streams exist in blt/fs/stream_wrappers.h std::vector m_log_outputs = get_default_log_outputs(); std::string m_log_format = get_default_log_format(); @@ -219,6 +225,9 @@ namespace blt::logging size_t m_longest_name_length = 0; + std::vector m_log_tag_content; + std::vector m_log_tag_tokens; + 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 9cc26fb..7ff8311 100644 --- a/src/blt/logging/logging.cpp +++ b/src/blt/logging/logging.cpp @@ -20,231 +20,231 @@ #include #include #include -#include +#include #include #include #include namespace blt::logging { - struct global_context_t - { - logging_config_t global_config; - }; + struct global_context_t + { + logging_config_t global_config; + }; - static global_context_t global_context; + static global_context_t global_context; - struct logging_thread_context_t - { - std::stringstream stream; - std::stringstream logging_stream; - std::string thread_name; - logger_t logger{stream}; - }; + struct logging_thread_context_t + { + std::stringstream stream; + std::stringstream logging_stream; + std::string thread_name; + logger_t logger{stream}; + }; - logging_thread_context_t& get_thread_context() - { - thread_local logging_thread_context_t context; - return context; - } + 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(); - } + std::string logger_t::to_string() const + { + return dynamic_cast(m_stream).str(); + } - size_t logger_t::find_ending_brace(size_t begin) const - { - size_t braces = 0; - for (; begin < m_fmt.size(); ++begin) - { - if (m_fmt[begin] == '{') - ++braces; - else if (m_fmt[begin] == '}') - --braces; - if (braces == 0) - return begin; - } - return std::string::npos; - } + size_t logger_t::find_ending_brace(size_t begin) const + { + size_t braces = 0; + for (; begin < m_fmt.size(); ++begin) + { + if (m_fmt[begin] == '{') + ++braces; + else if (m_fmt[begin] == '}') + --braces; + if (braces == 0) + return begin; + } + return std::string::npos; + } - void logger_t::setup_stream(const fmt_spec_t& spec) const - { - if (spec.prefix_char) - m_stream << std::setfill(*spec.prefix_char); - else - m_stream << std::setfill(' '); - switch (spec.alignment) - { - case fmt_align_t::LEFT: - m_stream << std::left; - break; - case fmt_align_t::CENTER: - // TODO? - break; - case fmt_align_t::RIGHT: - m_stream << std::right; - break; - } - if (spec.width > 0) - m_stream << std::setw(static_cast(spec.width)); - else - m_stream << std::setw(0); - if (spec.precision > 0) - m_stream << std::setprecision(static_cast(spec.precision)); - else - m_stream << std::setprecision(16); - if (spec.alternate_form) - m_stream << std::showbase; - else - m_stream << std::noshowbase; - if (spec.uppercase) - m_stream << std::uppercase; - else - m_stream << std::nouppercase; - if (spec.sign == fmt_sign_t::PLUS) - m_stream << std::showpos; - else - m_stream << std::noshowpos; - } + void logger_t::setup_stream(const fmt_spec_t& spec) const + { + if (spec.prefix_char) + m_stream << std::setfill(*spec.prefix_char); + else + m_stream << std::setfill(' '); + switch (spec.alignment) + { + case fmt_align_t::LEFT: + m_stream << std::left; + break; + case fmt_align_t::CENTER: + // TODO? + break; + case fmt_align_t::RIGHT: + m_stream << std::right; + break; + } + if (spec.width > 0) + m_stream << std::setw(static_cast(spec.width)); + else + m_stream << std::setw(0); + if (spec.precision > 0) + m_stream << std::setprecision(static_cast(spec.precision)); + else + m_stream << std::setprecision(16); + if (spec.alternate_form) + m_stream << std::showbase; + else + m_stream << std::noshowbase; + if (spec.uppercase) + m_stream << std::uppercase; + else + m_stream << std::nouppercase; + if (spec.sign == fmt_sign_t::PLUS) + m_stream << std::showpos; + else + m_stream << std::noshowpos; + } - void logger_t::process_strings() - { - auto spec_it = m_fmt_specs.begin(); - auto str_it = m_string_sections.begin(); - for (; spec_it != m_fmt_specs.end(); ++spec_it, ++str_it) - { - m_stream << *str_it; - auto arg_pos = spec_it->arg_id; - if (arg_pos == -1) - arg_pos = static_cast(m_arg_pos++); + void logger_t::process_strings() + { + auto spec_it = m_fmt_specs.begin(); + auto str_it = m_string_sections.begin(); + for (; spec_it != m_fmt_specs.end(); ++spec_it, ++str_it) + { + m_stream << *str_it; + auto arg_pos = spec_it->arg_id; + if (arg_pos == -1) + arg_pos = static_cast(m_arg_pos++); - setup_stream(*spec_it); - m_arg_print_funcs[arg_pos](m_stream, *spec_it); - } - m_stream << *str_it; - } + setup_stream(*spec_it); + m_arg_print_funcs[arg_pos](m_stream, *spec_it); + } + m_stream << *str_it; + } - void logger_t::handle_type(std::ostream& stream, const fmt_spec_t& spec) - { - switch (spec.type) - { - case fmt_type_t::DECIMAL: - stream << std::noboolalpha; - stream << std::dec; - break; - case fmt_type_t::OCTAL: - stream << std::oct; - break; - case fmt_type_t::HEX: - stream << std::hex; - break; - case fmt_type_t::HEX_FLOAT: - stream << std::hexfloat; - break; - case fmt_type_t::EXPONENT: - stream << std::scientific; - break; - case fmt_type_t::FIXED_POINT: - stream << std::fixed; - break; - case fmt_type_t::GENERAL: - stream << std::defaultfloat; - break; - case fmt_type_t::UNSPECIFIED: - stream << std::boolalpha; - stream << std::dec; - break; - default: - break; - } - } + void logger_t::handle_type(std::ostream& stream, const fmt_spec_t& spec) + { + switch (spec.type) + { + case fmt_type_t::DECIMAL: + stream << std::noboolalpha; + stream << std::dec; + break; + case fmt_type_t::OCTAL: + stream << std::oct; + break; + case fmt_type_t::HEX: + stream << std::hex; + break; + case fmt_type_t::HEX_FLOAT: + stream << std::hexfloat; + break; + case fmt_type_t::EXPONENT: + stream << std::scientific; + break; + case fmt_type_t::FIXED_POINT: + stream << std::fixed; + break; + case fmt_type_t::GENERAL: + stream << std::defaultfloat; + break; + case fmt_type_t::UNSPECIFIED: + stream << std::boolalpha; + stream << std::dec; + break; + default: + break; + } + } - void logger_t::exponential(std::ostream& stream) - { - stream << std::scientific; - } + void logger_t::exponential(std::ostream& stream) + { + stream << std::scientific; + } - void logger_t::fixed(std::ostream& stream) - { - stream << std::fixed; - } + void logger_t::fixed(std::ostream& stream) + { + stream << std::fixed; + } - void logger_t::compile(std::string fmt) - { - m_fmt = std::move(fmt); - m_last_fmt_pos = 0; - m_arg_pos = 0; - auto& ss = dynamic_cast(m_stream); - ss.str(""); - m_stream.clear(); - m_string_sections.clear(); - m_fmt_specs.clear(); - ptrdiff_t last_pos = 0; - while (auto pair = consume_to_next_fmt()) - { - const auto [begin, end] = *pair; - m_string_sections.emplace_back(m_fmt.data() + last_pos, begin - last_pos); - if (end - begin > 1) - m_fmt_specs.push_back(m_parser.parse(std::string_view{m_fmt.data() + static_cast(begin) + 1, end - begin - 1})); - else - m_fmt_specs.emplace_back(); - last_pos = static_cast(end) + 1; - } - m_string_sections.emplace_back(m_fmt.data() + last_pos, m_fmt.size() - last_pos); - m_last_fmt_pos = 0; - } + void logger_t::compile(std::string fmt) + { + m_fmt = std::move(fmt); + m_last_fmt_pos = 0; + m_arg_pos = 0; + auto& ss = dynamic_cast(m_stream); + ss.str(""); + m_stream.clear(); + m_string_sections.clear(); + m_fmt_specs.clear(); + ptrdiff_t last_pos = 0; + while (auto pair = consume_to_next_fmt()) + { + const auto [begin, end] = *pair; + m_string_sections.emplace_back(m_fmt.data() + last_pos, begin - last_pos); + if (end - begin > 1) + m_fmt_specs.push_back(m_parser.parse(std::string_view{m_fmt.data() + static_cast(begin) + 1, end - begin - 1})); + else + m_fmt_specs.emplace_back(); + last_pos = static_cast(end) + 1; + } + m_string_sections.emplace_back(m_fmt.data() + last_pos, m_fmt.size() - last_pos); + m_last_fmt_pos = 0; + } - std::optional> logger_t::consume_to_next_fmt() - { - const auto begin = m_fmt.find('{', m_last_fmt_pos); - if (begin == std::string::npos) - return {}; - const auto end = find_ending_brace(begin); - if (end == std::string::npos) - { - std::stringstream ss; - ss << "Invalid format string, missing closing '}' near " << m_fmt.substr(std::min(static_cast(begin) - 5, 0l)); - throw std::runtime_error(ss.str()); - } - m_last_fmt_pos = end + 1; - return std::pair{begin, end}; - } + std::optional> logger_t::consume_to_next_fmt() + { + const auto begin = m_fmt.find('{', m_last_fmt_pos); + if (begin == std::string::npos) + return {}; + const auto end = find_ending_brace(begin); + if (end == std::string::npos) + { + std::stringstream ss; + ss << "Invalid format string, missing closing '}' near " << m_fmt.substr(std::min(static_cast(begin) - 5, 0l)); + throw std::runtime_error(ss.str()); + } + m_last_fmt_pos = end + 1; + return std::pair{begin, end}; + } - logger_t& get_global_logger() - { - return get_thread_context().logger; - } + logger_t& get_global_logger() + { + return get_thread_context().logger; + } - void print(const std::string& str) - { - std::cout << str; - } + void print(const std::string& str) + { + std::cout << str; + } - void newline() - { - std::cout << std::endl; - } + void newline() + { + std::cout << std::endl; + } - logging_config_t& get_global_config() - { - return global_context.global_config; - } + logging_config_t& get_global_config() + { + return global_context.global_config; + } - void set_thread_name(const std::string& name) - { - get_thread_context().thread_name = name; - } + void set_thread_name(const std::string& name) + { + get_thread_context().thread_name = name; + } - const std::string& get_thread_name() - { - return get_thread_context().thread_name; - } + const std::string& get_thread_name() + { + return get_thread_context().thread_name; + } - std::ostream& get_local_stream() - { - auto& context = get_thread_context(); - context.logging_stream.str(""); - return context.logging_stream; - } + std::ostream& get_local_stream() + { + auto& context = get_thread_context(); + context.logging_stream.str(""); + return context.logging_stream; + } }