diff --git a/CMakeLists.txt b/CMakeLists.txt index 947184b..3f5c706 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,13 +12,14 @@ include("cmake/CPM.cmake") CPMAddPackage( NAME efp - VERSION 0.1.0-rc.5 - URL "https://github.com/cwahn/efp/archive/refs/tags/v0.1.0-rc.4.tar.gz" + URL "https://github.com/cwahn/efp/archive/refs/tags/v0.1.1-beta.tar.gz" ) +# Neccessary for ESPIDF support +set(FMT_INSTALL OFF CACHE BOOL "Disable fmt install/export") +set(FMT_EXPORT OFF CACHE BOOL "Disable fmt export targets") CPMAddPackage( NAME fmt - VERSION 10.2.1 URL "https://github.com/fmtlib/fmt/archive/refs/tags/10.2.1.tar.gz" ) diff --git a/example/efp_logger_example.cpp b/example/efp_logger_example.cpp index 91a3f85..4a2f9f1 100644 --- a/example/efp_logger_example.cpp +++ b/example/efp_logger_example.cpp @@ -8,6 +8,9 @@ int main() { // Optional log level setting. Default is LogLevel::Info Logger::set_log_level(LogLevel::Trace); + // Optional log period setting. Default is 20ms + // Logger::set_log_period(std::chrono::milliseconds(1000));` + // Optional log output setting. // default is stdout // Logger::set_output("./efp_logger_test.log"); // Logger::set_output(stdout); @@ -21,10 +24,15 @@ int main() { // Use the logging functions trace("This is a trace message with no formating"); - debug("This is a debug message with a pointer: {:p}", (void*)&x); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + debug("This is a debug message with a pointer: {}", (void*)&x); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); info("This is a info message with a float: {}", 3.14f); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); warn("This is a warn message with a int: {}", 42); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); error("This is a error message with a string literal: {}", "error"); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); // ! Sending std::string to the buffer is O(n) and may increase risk of buffer overflow // ! Every 20 ~ 30 char will take one buffer space. fatal("This is a fatal message with a std::string: {}", std::string("fatal error")); @@ -34,6 +42,7 @@ int main() { // const auto a_1000 = std::string(1000, 'a'); // info("This is a info message with a 1000 char string: {}", a_1000); // info("Does it support Korean? {}", "한글도 되나요?"); + // info("This is a info message with a empty string: {}", std::string("")); return 0; } \ No newline at end of file diff --git a/include/efp/logger.hpp b/include/efp/logger.hpp index 52bbdcd..7bd85e0 100644 --- a/include/efp/logger.hpp +++ b/include/efp/logger.hpp @@ -1,5 +1,5 @@ -#ifndef EFP_RT_LOG_HPP_ -#define EFP_RT_LOG_HPP_ +#ifndef EFP_LOGGER_HPP_ +#define EFP_LOGGER_HPP_ #include #include @@ -17,7 +17,6 @@ #define EFP_LOG_TIME_STAMP true #define EFP_LOG_BUFFER_SIZE 256 // todo Maybe compile time log-level -// todo Processing period configuration namespace efp { enum class LogLevel : char { @@ -86,8 +85,8 @@ namespace efp { LogLevel level; }; - constexpr uint8_t stl_string_data_capacity = sizeof(FormatedMessage); - constexpr uint8_t stl_string_head_capacity = stl_string_data_capacity - sizeof(size_t); + constexpr size_t stl_string_data_capacity = sizeof(FormatedMessage); + constexpr size_t stl_string_head_capacity = stl_string_data_capacity - sizeof(size_t); // Data structure for std::string preventing each char takes size of full Enum; struct StlStringHead { @@ -236,7 +235,10 @@ namespace efp { : stl_string_head_capacity); // Extracting the remaining parts of the string if necessary - size_t remaining_length = arg.length - stl_string_head_capacity; + size_t remaining_length = arg.length > stl_string_head_capacity + ? arg.length - stl_string_head_capacity + : 0; + while (remaining_length > 0) { _read_buffer->pop_front().match( [&](const StlStringData& d) { @@ -341,8 +343,8 @@ namespace efp { private: Spinlock _spinlock; - Vcq* _write_buffer; Vcq* _read_buffer; + Vcq* _write_buffer; fmt::dynamic_format_arg_store _dyn_args; LogLevel _log_level = LogLevel::Info; std::FILE* _output_file = stdout; @@ -377,7 +379,6 @@ namespace efp { } static inline void set_log_level(LogLevel log_level) { - instance()._log_buffer.set_log_level(log_level); } @@ -385,7 +386,16 @@ namespace efp { return instance()._log_buffer.get_log_level(); } - static void set_output(FILE* output_file) { + static inline void set_log_period(std::chrono::milliseconds period) { + instance()._period = period; + } + + static inline std::chrono::milliseconds get_log_period() { + return instance()._period; + } + + static void + set_output(FILE* output_file) { instance()._log_buffer.set_output_file(output_file); } @@ -442,31 +452,35 @@ namespace efp { protected: private: Logger() - : // with_time_stamp(true), - _run(true), - _thread([&]() { + : _period{20}, + _run{true}, + _thread{[&]() { while (_run.load()) { + const auto start_time_point = std::chrono::steady_clock::now(); #if EFP_LOG_TIME_STAMP == true process_with_time(); #else process(); #endif - // todo periodic - std::this_thread::sleep_for(std::chrono::milliseconds{1}); + const auto end_time_point = std::chrono::steady_clock::now(); + const auto elapsed_time = + std::chrono::duration_cast( + end_time_point - start_time_point); + + if (elapsed_time < _period) { + std::this_thread::sleep_for(_period - elapsed_time); + } } - }) { + }} { } - LogLevel _log_level; + std::chrono::milliseconds _period; detail::LogBuffer _log_buffer; - std::atomic _run; std::thread _thread; }; - // LogLevel Logger::instance().log_level = LogLevel::Debug; - namespace detail { template