diff --git a/src/fw/core/format.cpp b/src/fw/core/format.cpp index d17f1884d..ffe912c10 100644 --- a/src/fw/core/format.cpp +++ b/src/fw/core/format.cpp @@ -41,3 +41,16 @@ void format::limit_trailing_zeros(std::string& str, int _trailing_max) } } + +fw::string32 format::time_point_to_string(const std::chrono::system_clock::time_point &time_point) +{ + std::time_t time = std::chrono::system_clock::to_time_t(time_point); + // The result of ctime and ctime_s is formatted like: "Www Mmm dd hh:mm:ss yyyy\n\0" (24 chars + end of line + end of string) +#ifdef WIN32 + char str[26]; + ctime_s(str, sizeof str, &time); + return {str, 24}; +#else + return {ctime(&time), 24}; +#endif +} \ No newline at end of file diff --git a/src/fw/core/format.h b/src/fw/core/format.h index 63b1b143f..3684a07df 100644 --- a/src/fw/core/format.h +++ b/src/fw/core/format.h @@ -1,10 +1,12 @@ #pragma once -#include +#include "./string.h" +#include "./types.h" +#include #include +#include +#include #include -#include -#include "types.h" namespace fw { @@ -37,5 +39,6 @@ namespace fw return result; } void limit_trailing_zeros(std::string& str, int _trailing_max); + fw::string32 time_point_to_string(const std::chrono::system_clock::time_point&); }; } \ No newline at end of file diff --git a/src/fw/core/log.cpp b/src/fw/core/log.cpp index d62e075cc..3276ac5ab 100644 --- a/src/fw/core/log.cpp +++ b/src/fw/core/log.cpp @@ -1,30 +1,12 @@ #include "log.h" -#include // va_list, va_start, va_end -#include // vfprintf #include -#include -#include -#include using namespace fw; std::deque log::s_logs; log::Verbosity log::s_verbosity = Verbosity_DEFAULT; -static fw::string32 time_point_to_string(const std::chrono::system_clock::time_point &time_point) -{ - std::time_t time = std::chrono::system_clock::to_time_t(time_point); - // The result of ctime and ctime_s is formatted like: "Www Mmm dd hh:mm:ss yyyy\n\0" (24 chars + end of line + end of string) -#ifdef WIN32 - char str[26]; - ctime_s(str, sizeof str, &time); - return {str, 24}; -#else - return {ctime(&time), 24}; -#endif -} - std::map& log::get_verbosity_by_category() { // use singleton pattern instead of static member to avoid static code issues @@ -40,52 +22,6 @@ log::Verbosity log::get_verbosity(const std::string& _category) return s_verbosity; } -void log::push_message(Verbosity _verbosity, const char* _category, const char* _format, ...) -{ - // Print log only if verbosity level allows it - - if (_verbosity <= get_verbosity(_category) ) - { - {}; - // Store the message in the front of the queue - Message& message = s_logs.emplace_front(); - message.verbosity = _verbosity; - message.category = _category; - - message.text.push_back('['); - message.text.append( time_point_to_string(message.date) ); - message.text.push_back('|'); - message.text.append(log::to_string(_verbosity)); - message.text.push_back('|'); - message.text.append( _category ); - message.text.push_back(']'); - message.text.push_back(' '); - - // Fill a buffer with the formatted message - va_list arglist; - va_start( arglist, _format ); - message.text.append_fmt(_format, arglist); - va_end( arglist ); - - // Select the appropriate color depending on the verbosity - switch (_verbosity) - { - case log::Verbosity_Error: std::cout << RED; break; - case log::Verbosity_Warning: std::cout << MAGENTA; break; - default: std::cout << RESET; break; - } - - // print the text and reset the color - printf("%s" RESET, message.text.c_str()); - - // Constraint the queue to have a limited size - constexpr size_t max_count = 5000; // a Message is 512 bytes - constexpr size_t min_count = 4000; // - if (s_logs.size() > max_count ) s_logs.resize(min_count); - } - -} - const char* log::to_string(log::Verbosity _verbosity) { switch (_verbosity) diff --git a/src/fw/core/log.h b/src/fw/core/log.h index a878b52b6..b0c0cccbc 100644 --- a/src/fw/core/log.h +++ b/src/fw/core/log.h @@ -1,10 +1,13 @@ #pragma once +#include "./string.h" +#include "format.h" +#include +#include #include -#include +#include #include -#include -#include "./string.h" +#include #define RESET "\033[0m" #define BLACK "\033[30m" /* Black */ @@ -27,13 +30,13 @@ #define KO RED "[KO]" RESET // red colored "[KO]" string. #define OK GREEN "[OK]" RESET // green colored "[OK]" string. -# define LOG_ERROR(...) fw::log::push_message( fw::log::Verbosity_Error , __VA_ARGS__ ); fw::log::flush(); -# define LOG_WARNING(...) fw::log::push_message( fw::log::Verbosity_Warning, __VA_ARGS__ ); -# define LOG_MESSAGE(...) fw::log::push_message( fw::log::Verbosity_Message, __VA_ARGS__ ); +# define LOG_ERROR(...) fw::log::push_message( fw::log::Verbosity_Error , ##__VA_ARGS__ ); fw::log::flush(); +# define LOG_WARNING(...) fw::log::push_message( fw::log::Verbosity_Warning, ##__VA_ARGS__ ); +# define LOG_MESSAGE(...) fw::log::push_message( fw::log::Verbosity_Message, ##__VA_ARGS__ ); # define LOG_FLUSH() fw::log::flush(); #if NDBL_DEBUG -# define LOG_VERBOSE(...) fw::log::push_message( fw::log::Verbosity_Verbose, __VA_ARGS__ ); +# define LOG_VERBOSE(...) fw::log::push_message( fw::log::Verbosity_Verbose, ##__VA_ARGS__ ); #else # define LOG_VERBOSE(...) #endif @@ -66,12 +69,6 @@ namespace fw { Verbosity verbosity=Verbosity_DEFAULT; // verbosity level }; - private: - static std::deque s_logs; // message history - static Verbosity s_verbosity; // global verbosity level - static std::map& get_verbosity_by_category(); - - public: static const std::deque& get_messages(); // Get message history static void set_verbosity(const std::string& _category, Verbosity _level) // Set verbosity level for a given category { get_verbosity_by_category().insert_or_assign(_category, _level ); } @@ -85,6 +82,46 @@ namespace fw { static Verbosity get_verbosity(const std::string& _category); // Get verbosity level for a given category inline static Verbosity get_verbosity() { return s_verbosity; } // Get global verbosity level static void flush(); // Ensure all messages have been printed out - static void push_message(Verbosity, const char* _category, const char* _format, ...); // Push a new message for a given category + + template + static void push_message(Verbosity _verbosity, const char* _category, const char* _format, Args... args) // Push a new message for a given category + { + // Print log only if verbosity level allows it + + if (_verbosity <= get_verbosity(_category) ) + { + Message& message = s_logs.emplace_front(); // Store a new message in the front of the queue + message.verbosity = _verbosity; + message.category = _category; + message.text.append_fmt("[%s|%s|%s] " // Append a formatted prefix with time, verbosity level and category + , format::time_point_to_string(message.date).c_str() + , log::to_string(_verbosity) + , _category ); + + message.text.append_fmt(_format, args...); // Fill a buffer with the formatted message + + // Select the appropriate color depending on the verbosity + switch (_verbosity) + { + case log::Verbosity_Error: std::cout << RED; break; + case log::Verbosity_Warning: std::cout << MAGENTA; break; + default: std::cout << RESET; break; + } + + // print the text and reset the color + printf("%s" RESET, message.text.c_str()); + + // Constraint the queue to have a limited size + constexpr size_t max_count = 5000; // a Message is 512 bytes + constexpr size_t min_count = 4000; // + if (s_logs.size() > max_count ) s_logs.resize(min_count); + } + + } + + private: + static std::deque s_logs; // message history + static Verbosity s_verbosity; // global verbosity level + static std::map& get_verbosity_by_category(); }; } \ No newline at end of file diff --git a/src/fw/core/string.h b/src/fw/core/string.h index 1c6c6ef4b..6e9b5e45f 100644 --- a/src/fw/core/string.h +++ b/src/fw/core/string.h @@ -1,8 +1,9 @@ #pragma once -#include +#include #include // for memcpy #include // for std::move +#include // va_list, va_start, va_end #include "types.h" @@ -29,7 +30,7 @@ namespace fw , m_ptr(nullptr) {} - basic_string(const CharT* str) + explicit basic_string(const CharT* str) : m_alloc_strategy(alloc_strategy::HEAP) , m_length(strlen(str)) , m_capacity(0) @@ -47,7 +48,7 @@ namespace fw : basic_string(other.c_str()) {} - basic_string(basic_string&& other) + basic_string(basic_string&& other) noexcept : m_alloc_strategy(alloc_strategy::HEAP) , m_length(0) , m_capacity(0) @@ -56,14 +57,11 @@ namespace fw *this = std::move(other); } - basic_string& operator=(basic_string&& other) + basic_string& operator=(basic_string&& other) noexcept { if( m_alloc_strategy == alloc_strategy::HEAP ) { - if( m_ptr != nullptr) - { - delete[] m_ptr; - } + delete[] m_ptr; m_ptr = other.m_ptr; m_length = other.m_length; m_capacity = other.m_capacity; @@ -135,10 +133,11 @@ namespace fw { return append(str, strlen(str)); } template - inline size_t append_fmt(const char* _format, Args... args ) - { - return m_length = vsnprintf(m_ptr+m_length, m_capacity-m_length, _format, args...); - } + inline size_t append_fmt(const char* _format, Args...args ) + { return m_length = snprintf(m_ptr+m_length, m_capacity-m_length, _format, args... ); } + + inline size_t append_fmt(const char* _str ) + { return m_length = snprintf(m_ptr+m_length, m_capacity-m_length, "%s", _str ); } /** provided to easily switch to/from std::string */ inline basic_string& push_back(CharT str)