diff --git a/doc/source/doxygen-docs/changelog.md b/doc/source/doxygen-docs/changelog.md index f99bd00bc2..7a64c159d9 100644 --- a/doc/source/doxygen-docs/changelog.md +++ b/doc/source/doxygen-docs/changelog.md @@ -19,6 +19,8 @@ - New method mrpt::gui::CGlCanvasBase::CamaraParams::FromCamera() - \ref mrpt_math_grp - Added missing method for consistent API across pose classes: mrpt::math::TPose3D::operator+() + - \ref mrpt_system_grp + - mrpt::system::COutputLogger::writeLogToFile() will now save *all* messages despite the runtime log verbosity level. - BUG FIXES: - Fix error rendering an opengl scene with mrpt::opengl::CCamera objects in it. - rawlog-edit silently ignored when more than one operation was requested. diff --git a/libs/system/include/mrpt/system/COutputLogger.h b/libs/system/include/mrpt/system/COutputLogger.h index e9bb6e9330..f6d15ca479 100644 --- a/libs/system/include/mrpt/system/COutputLogger.h +++ b/libs/system/include/mrpt/system/COutputLogger.h @@ -11,13 +11,16 @@ #include #include -#include // for console color constants +#include // for console color constants #include #include #include #include #include +#include +#include +#include #include #include #include @@ -97,13 +100,16 @@ using output_logger_callback_t = std::function m_min_verbosity_level). Unset \b @@ -143,17 +149,18 @@ class COutputLogger * a_logger.setLoggerName("logger_name"); * \endcode */ - COutputLogger(std::string_view name); - /** Default class constructor. Name of the logger is initialized to "logStr" - */ - COutputLogger(); + COutputLogger(std::string_view name) : m_logger_name(name) {} + + /** Default constructor */ + COutputLogger() = default; + /** virtual dtor (so we can derive classes from this one) */ virtual ~COutputLogger(); /** \brief Main method to add the specified message string to the logger. * \sa logCond, logFmt */ void logStr(const VerbosityLevel level, std::string_view msg_str) - const; // renamed from log() to avoid conflict with math ::log() + const; // renamed from log() to avoid conflict with math ::log() /** \brief Alternative logging method, which mimics the printf behavior. * @@ -171,7 +178,7 @@ class COutputLogger * \sa logStr, logCond */ void logFmt(const VerbosityLevel level, const char* fmt, ...) const - MRPT_printf_format_check(3, 4); // arg 1=this + MRPT_printf_format_check(3, 4); // arg 1=this /** \brief Log the given message only if the condition is satisfied. * @@ -220,7 +227,8 @@ class COutputLogger * * \sa dumpToConsole, getAsString */ - void writeLogToFile(const std::string* fname_in = nullptr) const; + void writeLogToFile( + const std::optional fname_in = std::nullopt) const; /** \brief Dump the current contents of the COutputLogger instance in the * terminal window. * @@ -307,9 +315,10 @@ class COutputLogger std::string generateStringFromFormat( std::string_view fmt, va_list argp) const; - std::string m_logger_name; - mutable std::deque - m_history; // deque is better than vector to avoid memory reallocs + std::string m_logger_name = "COutputLogger"; + // deque is better than vector to avoid memory reallocs + mutable std::deque m_history; + std::shared_ptr m_historyMtx = std::make_shared(); std::deque m_listCallbacks; }; diff --git a/libs/system/src/COutputLogger.cpp b/libs/system/src/COutputLogger.cpp index 80518f7eb8..23ff1dd58d 100644 --- a/libs/system/src/COutputLogger.cpp +++ b/libs/system/src/COutputLogger.cpp @@ -7,18 +7,21 @@ | Released under BSD License. See: https://www.mrpt.org/License | +------------------------------------------------------------------------+ */ -#include "system-precomp.h" // Precompiled headers - #include +#include #include #include -#include // for logFmt +#include + +#include // for logFmt #include #include #include #include #include +#include "system-precomp.h" // Precompiled headers + #ifdef _MSC_VER #define WIN32_LEAN_AND_MEAN #include // OutputDebugString() for MSVC @@ -38,9 +41,9 @@ using namespace std; static std::array logging_levels_to_colors = { CONCOL_BLUE, // LVL_DEBUG - CONCOL_NORMAL, // LVL_INFO + CONCOL_NORMAL, // LVL_INFO CONCOL_GREEN, // LVL_WARN - CONCOL_RED // LVL_ERROR + CONCOL_RED // LVL_ERROR }; std::array& @@ -54,7 +57,7 @@ static std::array "DEBUG", // LVL_DEBUG "INFO ", // LVL_INFO "WARN ", // LVL_WARN - "ERROR" // LVL_ERROR + "ERROR" // LVL_ERROR }; std::array& COutputLogger::logging_levels_to_names() @@ -62,30 +65,27 @@ std::array& return ::logging_levels_to_names; } -COutputLogger::COutputLogger(std::string_view name) -{ - this->loggerReset(); - m_logger_name = name; -} -COutputLogger::COutputLogger() { this->loggerReset(); } COutputLogger::~COutputLogger() = default; + void COutputLogger::logStr( const VerbosityLevel level, std::string_view msg_str) const { - if (level < m_min_verbosity_level) return; - // initialize a TMsg object TMsg msg(level, msg_str, *this); - if (logging_enable_keep_record) m_history.push_back(msg); + if (logging_enable_keep_record) + { + auto lck = mrpt::lockHelper(*m_historyMtx); + m_history.push_back(msg); + } - if (logging_enable_console_output) + if (level >= m_min_verbosity_level && logging_enable_console_output) { msg.dumpToConsole(); - } - // User callbacks: - for (const auto& c : m_listCallbacks) - c(msg.body, msg.level, msg.name, msg.timestamp); + // User callbacks: + for (const auto& c : m_listCallbacks) + c(msg.body, msg.level, msg.name, msg.timestamp); + } } void COutputLogger::logFmt( @@ -151,6 +151,7 @@ void COutputLogger::setVerbosityLevel(const VerbosityLevel level) void COutputLogger::getLogAsString(std::string& fname) const { fname.clear(); + auto lck = mrpt::lockHelper(*m_historyMtx); for (const auto& h : m_history) fname += h.getAsString(); } std::string COutputLogger::getLogAsString() const @@ -159,23 +160,20 @@ std::string COutputLogger::getLogAsString() const this->getLogAsString(str); return str; } -void COutputLogger::writeLogToFile( - const std::string* fname_in /* = nullptr */) const +void COutputLogger::writeLogToFile(const std::optional fname_in) const { + using namespace std::string_literals; + // determine the filename - open it - std::string fname; - if (fname_in) - { - fname = *fname_in; - } - else - { - fname = m_logger_name + ".log"; - } + std::string fname = + fname_in.has_value() + ? fname_in.value() + : mrpt::system::fileNameStripInvalidChars(m_logger_name) + ".log"s; + std::ofstream f(fname); ASSERTMSG_( f.is_open(), mrpt::format( - "[%s:] Could not open external file: %s", + "[%s] Could not open external file: %s", m_logger_name.c_str(), fname.c_str())); std::string hist_str; @@ -186,11 +184,13 @@ void COutputLogger::writeLogToFile( void COutputLogger::dumpLogToConsole() const { + auto lck = mrpt::lockHelper(*m_historyMtx); for (const auto& h : m_history) h.dumpToConsole(); } std::string COutputLogger::getLoggerLastMsg() const { + auto lck = mrpt::lockHelper(*m_historyMtx); TMsg last_msg = m_history.back(); return last_msg.getAsString(); } @@ -200,18 +200,7 @@ void COutputLogger::getLoggerLastMsg(std::string& msg_str) const msg_str = this->getLoggerLastMsg(); } -void COutputLogger::loggerReset() -{ - m_logger_name = "log"; // just the default name - - m_history.clear(); - logging_enable_console_output = true; - logging_enable_keep_record = false; - - // set the minimum logging level allowed for printing. By default its - // LVL_INFO - m_min_verbosity_level = LVL_INFO; -} +void COutputLogger::loggerReset() { *this = COutputLogger(); } // TMsg Struct // //////////////////////////////////////////////////////////// @@ -254,7 +243,7 @@ void COutputLogger::TMsg::dumpToConsole() const { const std::string str = getAsString(); - const bool dump_to_cerr = (level == LVL_ERROR); // LVL_ERROR alternatively + const bool dump_to_cerr = (level == LVL_ERROR); // LVL_ERROR alternatively // dumped to stderr instead // of stdout