From 6cf9b344409efcc41a2b34f87100d25e1d2486af Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Wed, 3 Jul 2024 23:51:32 +1000 Subject: [PATCH] logging: Limit early logging buffer Log messages created prior to StartLogging() being called go into a buffer. Enforce a limit on the size of this buffer. --- src/logging.cpp | 31 +++++++++++++++++++++++++++++++ src/logging.h | 8 ++++++++ 2 files changed, 39 insertions(+) diff --git a/src/logging.cpp b/src/logging.cpp index 53af7d5ca72..9dafa720544 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -4,6 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include #include @@ -71,6 +72,9 @@ bool BCLog::Logger::StartLogging() // dump buffered messages from before we opened the log m_buffering = false; + if (m_buffer_lines_discarded > 0) { + LogPrintStr_(strprintf("Early logging buffer overflowed, %d log lines discarded.\n", m_buffer_lines_discarded), __func__, __FILE__, __LINE__, BCLog::ALL, Level::Info); + } while (!m_msgs_before_open.empty()) { const std::string& s = m_msgs_before_open.front(); @@ -82,6 +86,7 @@ bool BCLog::Logger::StartLogging() m_msgs_before_open.pop_front(); } + m_cur_buffer_memusage = 0; if (m_print_to_console) fflush(stdout); return true; @@ -94,6 +99,11 @@ void BCLog::Logger::DisconnectTestLogger() if (m_fileout != nullptr) fclose(m_fileout); m_fileout = nullptr; m_print_callbacks.clear(); + m_max_buffer_memusage = DEFAULT_MAX_LOG_BUFFER; + m_cur_buffer_memusage = 0; + m_buffer_lines_discarded = 0; + m_msgs_before_open.clear(); + } void BCLog::Logger::DisableLogging() @@ -362,9 +372,19 @@ std::string BCLog::Logger::GetLogPrefix(BCLog::LogFlags category, BCLog::Level l return s; } +static size_t MemUsage(const std::string& str) +{ + return str.size() + memusage::MallocUsage(sizeof(memusage::list_node)); +} + void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) { StdLockGuard scoped_lock(m_cs); + return LogPrintStr_(str, logging_function, source_file, source_line, category, level); +} + +void BCLog::Logger::LogPrintStr_(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) +{ std::string str_prefixed = LogEscapeMessage(str); if (m_started_new_line) { @@ -387,6 +407,17 @@ void BCLog::Logger::LogPrintStr(const std::string& str, const std::string& loggi if (m_buffering) { // buffer if we haven't started logging yet m_msgs_before_open.push_back(str_prefixed); + + m_cur_buffer_memusage += MemUsage(str_prefixed); + while (m_cur_buffer_memusage > m_max_buffer_memusage) { + if (m_msgs_before_open.empty()) { + m_cur_buffer_memusage = 0; + break; + } + m_cur_buffer_memusage -= MemUsage(m_msgs_before_open.front()); + m_msgs_before_open.pop_front(); + ++m_buffer_lines_discarded; + } return; } diff --git a/src/logging.h b/src/logging.h index 70539f03b05..b3fe70cca70 100644 --- a/src/logging.h +++ b/src/logging.h @@ -79,6 +79,7 @@ namespace BCLog { Error, }; constexpr auto DEFAULT_LOG_LEVEL{Level::Debug}; + constexpr size_t DEFAULT_MAX_LOG_BUFFER{1'000'000}; // buffer up to 1MB of log data prior to StartLogging class Logger { @@ -88,6 +89,9 @@ namespace BCLog { FILE* m_fileout GUARDED_BY(m_cs) = nullptr; std::list m_msgs_before_open GUARDED_BY(m_cs); bool m_buffering GUARDED_BY(m_cs) = true; //!< Buffer messages before logging can be started. + size_t m_max_buffer_memusage GUARDED_BY(m_cs){DEFAULT_MAX_LOG_BUFFER}; + size_t m_cur_buffer_memusage GUARDED_BY(m_cs){0}; + size_t m_buffer_lines_discarded GUARDED_BY(m_cs){0}; /** * m_started_new_line is a state variable that will suppress printing of @@ -111,6 +115,10 @@ namespace BCLog { /** Slots that connect to the print signal */ std::list> m_print_callbacks GUARDED_BY(m_cs) {}; + /** Send a string to the log output (internal) */ + void LogPrintStr_(const std::string& str, const std::string& logging_function, const std::string& source_file, int source_line, BCLog::LogFlags category, BCLog::Level level) + EXCLUSIVE_LOCKS_REQUIRED(m_cs); + public: bool m_print_to_console = false; bool m_print_to_file = false;