From 60536fd602c6483f91083fc75666d4168d5b18c6 Mon Sep 17 00:00:00 2001 From: Brett Date: Sun, 9 Mar 2025 15:06:31 -0400 Subject: [PATCH] i think logging is working. need to make macros and test --- CMakeLists.txt | 2 +- include/blt/logging/logging.h | 21 +- include/blt/logging/logging_config.h | 52 ++--- libraries/parallel-hashmap | 2 +- src/blt/logging/logging.cpp | 11 +- src/blt/logging/logging_config.cpp | 276 +++++++++++++++++++++------ 6 files changed, 274 insertions(+), 90 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bc147a..cba9a6d 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.2) +set(BLT_VERSION 5.2.3) set(BLT_TARGET BLT) diff --git a/include/blt/logging/logging.h b/include/blt/logging/logging.h index 35db5bc..ba091aa 100644 --- a/include/blt/logging/logging.h +++ b/include/blt/logging/logging.h @@ -31,9 +31,6 @@ namespace blt::logging { - namespace detail - {} - struct logger_t { explicit logger_t(std::ostream& stream): m_stream(stream) @@ -173,6 +170,8 @@ namespace blt::logging void set_thread_name(const std::string& name); + const std::string& get_thread_name(); + template void print(std::string fmt, Args&&... args) { @@ -200,6 +199,22 @@ namespace blt::logging print(stream, std::move(fmt), std::forward(args)...); stream << std::endl; } + + template + void log(log_level_t level, const char* file, const i32 line, std::string fmt, Args&&... args) + { + auto& logger = get_global_logger(); + auto& config = get_global_config(); + auto user_str = logger.log(std::move(fmt), std::forward(args)...); + auto log_fmt_str = config.generate(user_str, get_thread_name(), level, file, line); + if (log_fmt_str) + print(std::move(*log_fmt_str)); + } + + namespace detail + {} } +#define BLT_LOG(level, fmt, ...) blt::logging::log(level, __FILE__, __LINE__, fmt, ##__VA_ARGS__) + #endif // BLT_LOGGING_LOGGING_H diff --git a/include/blt/logging/logging_config.h b/include/blt/logging/logging_config.h index afaad32..1ce8656 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 @@ -44,10 +45,12 @@ namespace blt::logging inline constexpr auto SECOND = "{SECOND}"; // Current Millisecond inline constexpr auto MILLISECOND = "{MS}"; - // Current Nanosecond time, This is direct output of nanotime + // Current Nanosecond inline constexpr auto NANOSECOND = "{NS}"; // Current Unix time in milliseconds inline constexpr auto UNIX_TIME = "{UNIX}"; + // Current Unix time in nanosecond + inline constexpr auto UNIX_TIME_NANO = "{UNIX_NANO}"; // Formatted ISO year-month-day in a single variable inline constexpr auto ISO_YEAR = "{ISO_YEAR}"; // Formatted hour:minute:second in a single variable @@ -86,6 +89,7 @@ namespace blt::logging MS, NS, UNIX, + UNIX_NANO, ISO_YEAR, TIME, FULL_TIME, @@ -130,83 +134,87 @@ namespace blt::logging logging_config_t& add_log_output(fs::writer_t* writer) { - log_outputs.push_back(writer); + m_log_outputs.push_back(writer); return *this; } logging_config_t& set_log_format(std::string format) { - log_format = std::move(format); + m_log_format = std::move(format); compile(); return *this; } logging_config_t& set_error_color(std::string color) { - error_color = std::move(color); + m_error_color = std::move(color); compile(); return *this; } logging_config_t& set_log_level_colors(std::array colors) { - log_level_colors = std::move(colors); + m_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); + m_log_level_names = std::move(names); return *this; } logging_config_t& set_level(const log_level_t level) { - this->level = level; + this->m_level = level; return *this; } logging_config_t& set_use_color(const bool use_color) { - this->use_color = use_color; + this->m_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; + this->m_print_full_name = print_full_name; return *this; } logging_config_t& set_ensure_alignment(const bool ensure_alignment) { - this->ensure_alignment = ensure_alignment; + this->m_ensure_alignment = ensure_alignment; return *this; } [[nodiscard]] std::pair&, const std::vector&> get_log_tag_tokens() const { - return {log_tag_tokens, log_tag_content}; + return {m_log_tag_tokens, m_log_tag_content}; } + std::optional generate(const std::string& user_str, const std::string& thread_name, log_level_t level, const char* file, + i32 line) const; + private: - std::vector log_tag_content; - std::vector log_tag_tokens; + std::vector m_log_tag_content; + std::vector m_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(); - std::string error_color = get_default_error_color(); - std::array log_level_colors = get_default_log_level_colors(); - std::array log_level_names = get_default_log_level_names(); - log_level_t level = log_level_t::TRACE; - bool use_color = true; + std::vector m_log_outputs = get_default_log_outputs(); + std::string m_log_format = get_default_log_format(); + std::string m_error_color = get_default_error_color(); + std::array m_log_level_colors = get_default_log_level_colors(); + std::array m_log_level_names = get_default_log_level_names(); + log_level_t m_level = log_level_t::TRACE; + + bool m_use_color = true; // if true prints the whole path to the file (eg /home/user/.../.../project/src/source.cpp:line#) - bool print_full_name = false; + bool m_print_full_name = false; // this will attempt to use the maximum possible size for each printed element, then align to that. // This creates output where the user message always starts at the same column. - bool ensure_alignment = true; + bool m_ensure_alignment = true; static std::string get_default_log_format(); static std::vector get_default_log_outputs(); diff --git a/libraries/parallel-hashmap b/libraries/parallel-hashmap index 7ef2e73..93201da 160000 --- a/libraries/parallel-hashmap +++ b/libraries/parallel-hashmap @@ -1 +1 @@ -Subproject commit 7ef2e733416953b222851f9a360d7fc72d068ee5 +Subproject commit 93201da2ba5a6aba0a6e57ada64973555629b3e3 diff --git a/src/blt/logging/logging.cpp b/src/blt/logging/logging.cpp index f0cc3ec..5d52436 100644 --- a/src/blt/logging/logging.cpp +++ b/src/blt/logging/logging.cpp @@ -30,8 +30,6 @@ 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; @@ -39,6 +37,7 @@ namespace blt::logging struct logging_thread_context_t { std::stringstream stream; + std::string thread_name; logger_t logger{stream}; }; @@ -233,7 +232,11 @@ namespace blt::logging 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; + get_thread_context().thread_name = name; + } + + const std::string& get_thread_name() + { + return get_thread_context().thread_name; } } diff --git a/src/blt/logging/logging_config.cpp b/src/blt/logging/logging_config.cpp index 9ca501d..fe15c92 100644 --- a/src/blt/logging/logging_config.cpp +++ b/src/blt/logging/logging_config.cpp @@ -15,11 +15,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include #include #include #include #include #include +#include +#include namespace blt::logging { @@ -37,6 +40,7 @@ namespace blt::logging map[MILLISECOND] = log_tag_token_t::MS; map[NANOSECOND] = log_tag_token_t::NS; map[UNIX_TIME] = log_tag_token_t::UNIX; + map[UNIX_TIME_NANO] = log_tag_token_t::UNIX_NANO; map[ISO_YEAR] = log_tag_token_t::ISO_YEAR; map[TIME] = log_tag_token_t::TIME; map[FULL_TIME] = log_tag_token_t::FULL_TIME; @@ -51,89 +55,243 @@ namespace blt::logging map[STR] = log_tag_token_t::STR; return 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(); + m_log_tag_content.clear(); + m_log_tag_tokens.clear(); size_t i = 0; - for (; i < log_format.size(); ++i) + for (; i < m_log_format.size(); ++i) { size_t start = i; - while (i < log_format.size() && log_format[i] != '{') + while (i < m_log_format.size() && m_log_format[i] != '{') ++i; - if (i == log_format.size() || (i < log_format.size() && (i - start) > 0)) + if (i == m_log_format.size() || (i < m_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()) + m_log_tag_content.emplace_back(std::string_view(m_log_format.data() + start, i - start)); + m_log_tag_tokens.emplace_back(tags::detail::log_tag_token_t::CONTENT); + if (i == m_log_format.size()) break; } start = i; - while (i < log_format.size() && log_format[i] != '}') + while (i < m_log_format.size() && m_log_format[i] != '}') ++i; - const auto tag = std::string_view(log_format.data() + start, i - start + 1); + const auto tag = std::string_view(m_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); + m_log_tag_tokens.emplace_back(it->second); } - if (i < log_format.size()) + if (i < m_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); + m_log_tag_content.emplace_back(std::string_view(m_log_format.data() + i, m_log_format.size() - i)); + m_log_tag_tokens.emplace_back(tags::detail::log_tag_token_t::CONTENT); } } + std::string add_year(const tm* current_time) + { + return std::to_string(current_time->tm_year + 1900); + } + + std::string add_month(const tm* current_time, const bool ensure_alignment) + { + auto str = std::to_string(current_time->tm_mon + 1); + if (ensure_alignment && str.size() < 2) + str.insert(str.begin(), '0'); + return str; + } + + std::string add_day(const tm* current_time, const bool ensure_alignment) + { + auto str = std::to_string(current_time->tm_mday); + if (ensure_alignment && str.size() < 2) + str.insert(str.begin(), '0'); + return str; + } + + std::string add_hour(const tm* current_time, const bool ensure_alignment) + { + auto str = std::to_string(current_time->tm_hour); + if (ensure_alignment && str.size() < 2) + str.insert(str.begin(), '0'); + return str; + } + + std::string add_minute(const tm* current_time, const bool ensure_alignment) + { + auto str = std::to_string(current_time->tm_min); + if (ensure_alignment && str.size() < 2) + str.insert(str.begin(), '0'); + return str; + } + + std::string add_second(const tm* current_time, const bool ensure_alignment) + { + auto str = std::to_string(current_time->tm_sec); + if (ensure_alignment && str.size() < 2) + str.insert(str.begin(), '0'); + return str; + } + + std::optional logging_config_t::generate(const std::string& user_str, const std::string& thread_name, const log_level_t level, + const char* file, const i32 line) const + { + if (level < m_level) + return {}; + + std::string fmt; + + const std::time_t time = std::time(nullptr); + const auto current_time = std::localtime(&time); + const auto millis_time = system::getCurrentTimeMilliseconds(); + const auto nano_time = system::getCurrentTimeNanoseconds(); + + size_t content = 0; + for (const auto& log_tag_token : m_log_tag_tokens) + { + switch (log_tag_token) + { + case tags::detail::log_tag_token_t::YEAR: + fmt += add_year(current_time); + break; + case tags::detail::log_tag_token_t::MONTH: + fmt += add_month(current_time, m_ensure_alignment); + break; + case tags::detail::log_tag_token_t::DAY: + fmt += add_day(current_time, m_ensure_alignment); + break; + case tags::detail::log_tag_token_t::HOUR: + fmt += add_hour(current_time, m_ensure_alignment); + break; + case tags::detail::log_tag_token_t::MINUTE: + fmt += add_minute(current_time, m_ensure_alignment); + break; + case tags::detail::log_tag_token_t::SECOND: + fmt += add_second(current_time, m_ensure_alignment); + break; + case tags::detail::log_tag_token_t::MS: + { + auto str = std::to_string(millis_time % 1000); + if (m_ensure_alignment) + { + for (size_t i = str.size(); i < 4; ++i) + str.insert(str.begin(), '0'); + } + fmt += str; + break; + } + case tags::detail::log_tag_token_t::NS: + { + auto str = std::to_string(nano_time % 1000); + if (m_ensure_alignment) + { + for (size_t i = str.size(); i < 4; ++i) + str.insert(str.begin(), '0'); + } + fmt += str; + break; + } + case tags::detail::log_tag_token_t::UNIX: + { + auto str = std::to_string(millis_time % 1000); + if (m_ensure_alignment) + { + for (size_t i = str.size(); i < 4; ++i) + str.insert(str.begin(), '0'); + } + fmt += str; + break; + } + case tags::detail::log_tag_token_t::UNIX_NANO: + { + auto str = std::to_string(nano_time); + if (m_ensure_alignment) + { + for (size_t i = str.size(); i < 4; ++i) + str.insert(str.begin(), '0'); + } + fmt += str; + break; + } + case tags::detail::log_tag_token_t::ISO_YEAR: + { + fmt += add_year(current_time); + fmt += '-'; + fmt += add_month(current_time, m_ensure_alignment); + fmt += '-'; + fmt += add_day(current_time, m_ensure_alignment); + break; + } + case tags::detail::log_tag_token_t::TIME: + fmt += add_hour(current_time, m_ensure_alignment); + fmt += ':'; + fmt += add_minute(current_time, m_ensure_alignment); + fmt += ':'; + fmt += add_second(current_time, m_ensure_alignment); + break; + case tags::detail::log_tag_token_t::FULL_TIME: + fmt += add_year(current_time); + fmt += '-'; + fmt += add_month(current_time, m_ensure_alignment); + fmt += '-'; + fmt += add_day(current_time, m_ensure_alignment); + fmt += ' '; + fmt += add_hour(current_time, m_ensure_alignment); + fmt += ':'; + fmt += add_minute(current_time, m_ensure_alignment); + fmt += ':'; + fmt += add_second(current_time, m_ensure_alignment); + break; + case tags::detail::log_tag_token_t::LC: + if (!m_use_color) + break; + fmt += m_log_level_colors[static_cast(level)]; + break; + case tags::detail::log_tag_token_t::EC: + if (!m_use_color) + break; + fmt += m_error_color; + break; + case tags::detail::log_tag_token_t::CEC: + if (!m_use_color) + break; + if (static_cast(level) >= static_cast(log_level_t::ERROR)) + fmt += m_error_color; + break; + case tags::detail::log_tag_token_t::RESET: + if (!m_use_color) + break; + fmt += build(ansi::color::color_mode::RESET_ALL); + break; + case tags::detail::log_tag_token_t::LL: + fmt += m_log_level_names[static_cast(level)]; + break; + case tags::detail::log_tag_token_t::TN: + fmt += thread_name; + break; + case tags::detail::log_tag_token_t::FILE: + fmt += file; + break; + case tags::detail::log_tag_token_t::LINE: + fmt += std::to_string(line); + break; + case tags::detail::log_tag_token_t::STR: + fmt += user_str; + break; + case tags::detail::log_tag_token_t::CONTENT: + fmt += m_log_tag_content[content++]; + break; + } + } + + return fmt; + } + std::string logging_config_t::get_default_log_format() { return build(fg(ansi::color::color8_bright::CYAN)) + "[" + tags::FULL_TIME + "]" + tags::RESET + " " + tags::LOG_COLOR + "[" + tags::LOG_LEVEL