From 983cb7c18d17e6a268d50ce1f1b0330337fac716 Mon Sep 17 00:00:00 2001 From: JCW Date: Fri, 12 Sep 2025 18:38:19 +0100 Subject: [PATCH] Performance test Signed-off-by: JCW --- include/xrpl/basics/Log.h | 27 +- include/xrpl/beast/utility/Journal.h | 383 +++++++++----------- include/xrpl/beast/utility/WrappedSink.h | 10 +- src/libxrpl/basics/Log.cpp | 67 ++-- src/libxrpl/beast/utility/beast_Journal.cpp | 42 ++- src/test/beast/beast_Journal_test.cpp | 4 +- src/test/csf/Sim.h | 8 +- src/test/jtx/CaptureLogs.h | 8 +- src/test/jtx/CheckMessageLogs.h | 8 +- src/test/server/Server_test.cpp | 8 +- src/test/unit_test/SuiteJournal.h | 21 +- src/tests/libxrpl/basics/log.cpp | 40 +- src/xrpld/app/consensus/RCLConsensus.cpp | 8 +- 13 files changed, 300 insertions(+), 334 deletions(-) diff --git a/include/xrpl/basics/Log.h b/include/xrpl/basics/Log.h index f24c89c3d6..cabdbc70d5 100644 --- a/include/xrpl/basics/Log.h +++ b/include/xrpl/basics/Log.h @@ -26,6 +26,8 @@ #include #include +#include + #include #include #include @@ -74,10 +76,10 @@ private: operator=(Sink const&) = delete; void - write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override; + write(beast::severities::Severity level, beast::Journal::StringBuffer text) override; void - writeAlways(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) + writeAlways(beast::severities::Severity level, beast::Journal::StringBuffer text) override; }; @@ -135,7 +137,7 @@ private: Does nothing if there is no associated system file. */ void - write(std::string&& str); + write(std::string const& str); /** @} */ @@ -156,7 +158,7 @@ private: // Batching members mutable std::mutex batchMutex_; - beast::lockfree::queue messages_; + boost::lockfree::queue> messages_; static constexpr size_t BATCH_BUFFER_SIZE = 64 * 1024; // 64KB buffer std::array batchBuffer_{}; std::span writeBuffer_; // Points to available write space @@ -217,8 +219,7 @@ public: write( beast::severities::Severity level, std::string const& partition, - std::string_view text, - beast::Journal::MessagePoolNode owner, + beast::Journal::StringBuffer text, bool console); std::string @@ -280,12 +281,16 @@ private: // Wraps a Journal::Stream to skip evaluation of // expensive argument lists if the stream is not active. #ifndef JLOG +#define JLOG_JOIN_(a,b) a##b +#define JLOG_JOIN(a,b) JLOG_JOIN_(a,b) +#define JLOG_UNIQUE(base) JLOG_JOIN(base, __LINE__) // line-based unique name + #define JLOG(x) \ - if (!x) \ - { \ - } \ - else \ - x + if (auto JLOG_UNIQUE(stream) = (x); !JLOG_UNIQUE(stream)) \ + { \ + } \ + else \ + JLOG_UNIQUE(stream) #endif #ifndef CLOG diff --git a/include/xrpl/beast/utility/Journal.h b/include/xrpl/beast/utility/Journal.h index 1c30644de4..bcbca73ad6 100644 --- a/include/xrpl/beast/utility/Journal.h +++ b/include/xrpl/beast/utility/Journal.h @@ -35,164 +35,6 @@ #include #include -namespace beast { - -class StringBufferPool { -public: - // ----- Empty index marker ----- - static constexpr std::uint32_t kEmptyIdx = std::numeric_limits::max(); - - // ----- Single-word CAS target: {tag | idx} with pack/unpack ----- - struct Head { - std::uint32_t tag; - std::uint32_t idx; // kEmptyIdx means empty - - static std::uint64_t pack(Head h) noexcept { - return (std::uint64_t(h.tag) << 32) | h.idx; - } - static Head unpack(std::uint64_t v) noexcept { - return Head{ std::uint32_t(v >> 32), std::uint32_t(v) }; - } - }; - - // ----- Internal node ----- - struct Node { - std::uint32_t next_idx{kEmptyIdx}; - std::uint32_t self_idx{kEmptyIdx}; - std::string buf{}; - }; - static_assert(std::is_standard_layout_v, "Node must be standard layout"); - - // ----- User-facing move-only RAII handle ----- - class Handle { - public: - Handle() = default; - Handle(Handle&& other) noexcept - : owner_(other.owner_), node_(other.node_) { - other.owner_ = nullptr; other.node_ = nullptr; - } - Handle& operator=(Handle&& other) noexcept { - if (this != &other) { - // Return current if still held - if (owner_ && node_) owner_->give_back(std::move(*this)); - owner_ = other.owner_; - node_ = other.node_; - other.owner_ = nullptr; - other.node_ = nullptr; - } - return *this; - } - - Handle(const Handle&) = delete; - Handle& operator=(const Handle&) = delete; - - ~Handle() noexcept { - if (owner_ && node_) owner_->give_back(std::move(*this)); - } - - bool valid() const noexcept { return node_ != nullptr; } - std::string& string() noexcept { return node_->buf; } - const std::string& string() const noexcept { return node_->buf; } - - private: - friend class StringBufferPool; - Handle(StringBufferPool* owner, Node* n) : owner_(owner), node_(n) {} - - StringBufferPool* owner_ = nullptr; - Node* node_ = nullptr; - }; - - explicit StringBufferPool(std::uint32_t grow_by = 20) - : grow_by_(grow_by), head_(Head::pack({0, kEmptyIdx})) {} - - // Rent a buffer; grows on demand. Returns move-only RAII handle. - Handle rent() { - for (;;) { - std::uint64_t old64 = head_.load(std::memory_order_acquire); - Head old = Head::unpack(old64); - if (old.idx == kEmptyIdx) { grow_(); continue; } // rare slow path - - Node& n = nodes_[old.idx]; - std::uint32_t next = n.next_idx; - - Head neu{ std::uint32_t(old.tag + 1), next }; - if (head_.compare_exchange_weak(old64, Head::pack(neu), - std::memory_order_acq_rel, - std::memory_order_acquire)) { - return {this, &n}; - } - } - } - -private: - // Only the pool/handle can call this - void give_back(Handle&& h) noexcept { - Node* node = h.node_; - if (!node) return; // already invalid - const std::uint32_t idx = node->self_idx; - - node->buf.clear(); - - for (;;) { - std::uint64_t old64 = head_.load(std::memory_order_acquire); - Head old = Head::unpack(old64); - - node->next_idx = old.idx; - - Head neu{ std::uint32_t(old.tag + 1), idx }; - if (head_.compare_exchange_weak(old64, Head::pack(neu), - std::memory_order_acq_rel, - std::memory_order_acquire)) { - // Invalidate handle (prevents double return) - h.owner_ = nullptr; - h.node_ = nullptr; - return; - } - } - } - - void grow_() { - if (Head::unpack(head_.load(std::memory_order_acquire)).idx != kEmptyIdx) return; - std::scoped_lock lk(grow_mu_); - if (Head::unpack(head_.load(std::memory_order_acquire)).idx != kEmptyIdx) return; - - const std::uint32_t base = static_cast(nodes_.size()); - nodes_.resize(base + grow_by_); // indices [base .. base+grow_by_-1] - - // Init nodes and local chain - for (std::uint32_t i = 0; i < grow_by_; ++i) { - std::uint32_t idx = base + i; - Node& n = nodes_[idx]; - n.self_idx = idx; - n.next_idx = (i + 1 < grow_by_) ? (idx + 1) : kEmptyIdx; - } - - // Splice chain onto global head: [base .. base+grow_by_-1] - const std::uint32_t chain_head = base; - const std::uint32_t chain_tail = base + grow_by_ - 1; - - for (;;) { - std::uint64_t old64 = head_.load(std::memory_order_acquire); - Head old = Head::unpack(old64); - - nodes_[chain_tail].next_idx = old.idx; // tail -> old head - Head neu{ std::uint32_t(old.tag + 1), chain_head }; - - if (head_.compare_exchange_weak(old64, Head::pack(neu), - std::memory_order_acq_rel, - std::memory_order_acquire)) { - break; - } - } - } - - const std::uint32_t grow_by_; - std::atomic head_; // single 64-bit CAS (Head packed) - std::mutex grow_mu_; // only during growth - std::deque nodes_; // stable storage for nodes/strings -}; -} // namespace beast - namespace ripple::log { template class LogParameter @@ -248,102 +90,107 @@ namespace detail { class SimpleJsonWriter { public: - explicit SimpleJsonWriter(std::string& buffer) : buffer_(buffer) + explicit SimpleJsonWriter(std::string* buffer) : buffer_(buffer) { } + SimpleJsonWriter() = default; + + SimpleJsonWriter(SimpleJsonWriter const& other) = default; + SimpleJsonWriter& operator=(SimpleJsonWriter const& other) = default; + std::string& - buffer() { return buffer_; } + buffer() { return *buffer_; } void startObject() const { - buffer_.push_back('{'); + buffer_->push_back('{'); } void endObject() const { using namespace std::string_view_literals; - if (buffer_.back() == ',') - buffer_.pop_back(); - buffer_.append("},"sv); + if (buffer_->back() == ',') + buffer_->pop_back(); + buffer_->append("},"sv); } void writeKey(std::string_view key) const { writeString(key); - buffer_.back() = ':'; + buffer_->back() = ':'; } void startArray() const { - buffer_.push_back('['); + buffer_->push_back('['); } void endArray() const { using namespace std::string_view_literals; - if (buffer_.back() == ',') - buffer_.pop_back(); - buffer_.append("],"sv); + if (buffer_->back() == ',') + buffer_->pop_back(); + buffer_->append("],"sv); } void writeString(std::string_view str) const { using namespace std::string_view_literals; - buffer_.push_back('"'); - escape(str, buffer_); - buffer_.append("\","sv); + buffer_->push_back('"'); + escape(str, *buffer_); + buffer_->append("\","sv); } std::string_view writeInt(std::int32_t val) const { - return pushNumber(val, buffer_); + return pushNumber(val, *buffer_); } std::string_view writeInt(std::int64_t val) const { - return pushNumber(val, buffer_); + return pushNumber(val, *buffer_); } std::string_view writeUInt(std::uint32_t val) const { - return pushNumber(val, buffer_); + return pushNumber(val, *buffer_); } std::string_view writeUInt(std::uint64_t val) const { - return pushNumber(val, buffer_); + return pushNumber(val, *buffer_); } std::string_view writeDouble(double val) const { - return pushNumber(val, buffer_); + return pushNumber(val, *buffer_); } std::string_view writeBool(bool val) const { using namespace std::string_view_literals; auto str = val ? "true,"sv : "false,"sv; - buffer_.append(str); + buffer_->append(str); return str; } void writeNull() const { using namespace std::string_view_literals; - buffer_.append("null,"sv); + buffer_->append("null,"sv); } void writeRaw(std::string_view str) const { - buffer_.append(str); + buffer_->append(str); } void finish() { - buffer_.pop_back(); + buffer_->pop_back(); } private: @@ -427,7 +274,7 @@ private: buffer.append(chunk, p - chunk); } - std::string& buffer_; + std::string* buffer_ = nullptr; }; } // namespace detail @@ -482,23 +329,141 @@ public: class Sink; - using MessagePoolNode = lockfree::queue::Node*; + class StringBufferPool { + public: + static constexpr std::uint32_t kEmptyIdx = std::numeric_limits::max(); + + struct Head { + std::uint32_t tag; + std::uint32_t idx; // kEmptyIdx means empty + }; + + struct Node { + std::uint32_t next_idx{kEmptyIdx}; + std::uint32_t self_idx{kEmptyIdx}; + std::string buf{}; + }; + + class StringBuffer + { + public: + StringBuffer() = default; + + std::string& + str() { return node_->buf; } + + private: + StringBuffer(StringBufferPool* owner, Node* node) + : owner_(owner), node_(node) {} + + StringBufferPool* owner_ = nullptr; + Node* node_ = nullptr; + + friend class StringBufferPool; + }; + + explicit StringBufferPool(std::uint32_t grow_by = 20) + : growBy_(grow_by), head_({0, kEmptyIdx}) {} + + // Rent a buffer; grows on demand. Returns move-only RAII handle. + StringBuffer rent() { + for (;;) { + auto old = head_.load(std::memory_order_acquire); + if (old.idx == kEmptyIdx) { grow(); continue; } // rare slow path + + Node& n = nodes_[old.idx]; + std::uint32_t next = n.next_idx; + + Head neu{ old.tag + 1, next }; + if (head_.compare_exchange_weak(old, neu, + std::memory_order_acq_rel, + std::memory_order_acquire)) { + return {this, &n}; + } + } + } + + // Only the pool/handle can call this + void giveBack(StringBuffer&& h) noexcept { + Node* node = h.node_; + if (!node) return; // already invalid + const std::uint32_t idx = node->self_idx; + + for (;;) { + auto old = head_.load(std::memory_order_acquire); + + node->next_idx = old.idx; + + Head neu{ std::uint32_t(old.tag + 1), idx }; + if (head_.compare_exchange_weak(old, neu, + std::memory_order_acq_rel, + std::memory_order_acquire)) { + // Invalidate handle (prevents double return) + h.owner_ = nullptr; + h.node_ = nullptr; + return; + } + } + } + + private: + + void grow() { + if (head_.load(std::memory_order_acquire).idx != kEmptyIdx) return; + std::scoped_lock lk(growMutex_); + if (head_.load(std::memory_order_acquire).idx != kEmptyIdx) return; + + auto base = static_cast(nodes_.size()); + nodes_.resize(base + growBy_); + + // Init nodes and local chain + for (std::uint32_t i = 0; i < growBy_; ++i) { + std::uint32_t idx = base + i; + Node& n = nodes_[idx]; + n.self_idx = idx; + n.next_idx = (i + 1 < growBy_) ? (idx + 1) : kEmptyIdx; + } + + // Splice chain onto global head: [base .. base+grow_by_-1] + const std::uint32_t chain_head = base; + const std::uint32_t chain_tail = base + growBy_ - 1; + + for (;;) { + auto old = head_.load(std::memory_order_acquire); + + nodes_[chain_tail].next_idx = old.idx; // tail -> old head + Head neu{ std::uint32_t(old.tag + 1), chain_head }; + + if (head_.compare_exchange_weak(old, neu, + std::memory_order_acq_rel, + std::memory_order_acquire)) { + break; + } + } + } + + const std::uint32_t growBy_; + + // single 64-bit CAS + std::atomic head_; + + // only during growth + std::mutex growMutex_; + + // stable storage for nodes/strings + std::deque nodes_; + }; + using StringBuffer = StringBufferPool::StringBuffer; class JsonLogContext { - MessagePoolNode messageBuffer_; - detail::SimpleJsonWriter messageParamsWriter_; + StringBuffer messageBuffer_; + detail::SimpleJsonWriter jsonWriter_; bool hasMessageParams_ = false; - + bool messageBufferHandedOut_ = true; public: - explicit JsonLogContext() - : messageBuffer_(rentFromPool()) - , messageParamsWriter_(messageBuffer_->data) - { - messageBuffer_->data.reserve(1024 * 5); - } - MessagePoolNode + StringBuffer messageBuffer() { return messageBuffer_; } void @@ -524,11 +489,14 @@ public: detail::SimpleJsonWriter& writer() { - return messageParamsWriter_; + return jsonWriter_; } void - reset( + finish(); + + void + start( std::source_location location, severities::Severity severity, std::string_view moduleName, @@ -545,7 +513,7 @@ private: static std::shared_mutex globalLogAttributesMutex_; static bool jsonLogsEnabled_; - static lockfree::queue messagePool_; + static StringBufferPool messagePool_; static thread_local JsonLogContext currentJsonLogContext_; // Invariant: m_sink always points to a valid Sink @@ -556,25 +524,20 @@ private: std::source_location location, severities::Severity severity) const; - static MessagePoolNode + static StringBuffer formatLog(std::string const& message); public: //-------------------------------------------------------------------------- - static MessagePoolNode + static StringBuffer rentFromPool() { - auto node = messagePool_.pop(); - if (!node) - { - node = new lockfree::queue::Node(); - } - return node; + return messagePool_.rent(); } static void - returnMessageNode(MessagePoolNode node) { messagePool_.push(node); } + returnStringBuffer(StringBuffer&& node) { messagePool_.giveBack(std::move(node)); } static void enableStructuredJournal(); @@ -625,7 +588,7 @@ public: level is below the current threshold(). */ virtual void - write(Severity level, std::string_view text, MessagePoolNode owner = nullptr) = 0; + write(Severity level, StringBuffer text) = 0; /** Bypass filter and write text to the sink at the specified severity. * Always write the message, but maintain the same formatting as if @@ -635,7 +598,7 @@ public: * @param text Text to write to sink. */ virtual void - writeAlways(Severity level, std::string_view text, MessagePoolNode owner = nullptr) = 0; + writeAlways(Severity level, StringBuffer text) = 0; private: Severity thresh_; @@ -813,7 +776,7 @@ public: : name_(other.name_), m_sink(other.m_sink) { std::string buffer{other.attributes_}; - detail::SimpleJsonWriter writer{buffer}; + detail::SimpleJsonWriter writer{&buffer}; if (other.attributes_.empty() && jsonLogsEnabled_) { writer.startObject(); @@ -838,7 +801,7 @@ public: { std::string buffer; buffer.reserve(128); - detail::SimpleJsonWriter writer{buffer}; + detail::SimpleJsonWriter writer{&buffer}; if (jsonLogsEnabled_) { writer.startObject(); @@ -954,7 +917,7 @@ public: std::unique_lock lock(globalLogAttributesMutex_); globalLogAttributes_.reserve(1024); auto isEmpty = globalLogAttributes_.empty(); - detail::SimpleJsonWriter writer{globalLogAttributes_}; + detail::SimpleJsonWriter writer{&globalLogAttributes_}; if (isEmpty && jsonLogsEnabled_) { writer.startObject(); diff --git a/include/xrpl/beast/utility/WrappedSink.h b/include/xrpl/beast/utility/WrappedSink.h index 6024e6b797..8e083c467e 100644 --- a/include/xrpl/beast/utility/WrappedSink.h +++ b/include/xrpl/beast/utility/WrappedSink.h @@ -88,17 +88,19 @@ public: } void - write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + write(beast::severities::Severity level, Journal::StringBuffer text) override { using beast::Journal; - sink_.write(level, prefix_ + std::string(text), owner); + text.str() = prefix_ + text.str(); + sink_.write(level, text); } void - writeAlways(severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + writeAlways(severities::Severity level, Journal::StringBuffer text) override { using beast::Journal; - sink_.writeAlways(level, prefix_ + std::string(text), owner); + text.str() = prefix_ + text.str(); + sink_.writeAlways(level, text); } }; diff --git a/src/libxrpl/basics/Log.cpp b/src/libxrpl/basics/Log.cpp index 07fdffe682..7461086d6c 100644 --- a/src/libxrpl/basics/Log.cpp +++ b/src/libxrpl/basics/Log.cpp @@ -53,18 +53,18 @@ Logs::Sink::Sink( } void -Logs::Sink::write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner) +Logs::Sink::write(beast::severities::Severity level, beast::Journal::StringBuffer text) { if (level < threshold()) return; - logs_.write(level, partition_, text, owner, console()); + logs_.write(level, partition_, text, console()); } void -Logs::Sink::writeAlways(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner) +Logs::Sink::writeAlways(beast::severities::Severity level, beast::Journal::StringBuffer text) { - logs_.write(level, partition_, text, owner, console()); + logs_.write(level, partition_, text, console()); } //------------------------------------------------------------------------------ @@ -119,7 +119,7 @@ Logs::File::close() } void -Logs::File::write(std::string&& text) +Logs::File::write(std::string const& text) { if (m_stream.has_value()) m_stream->write(text.data(), text.size()); @@ -141,10 +141,8 @@ Logs::~Logs() { // Signal log thread to stop and wait for it to finish { - std::lock_guard lock(logMutex_); stopLogThread_ = true; } - logCondition_.notify_all(); if (logThread_.joinable()) logThread_.join(); @@ -202,27 +200,25 @@ void Logs::write( beast::severities::Severity level, std::string const& partition, - std::string_view text, - beast::Journal::MessagePoolNode owner, + beast::Journal::StringBuffer text, bool console) { std::string s; - std::string_view result = text; + std::string_view result = text.str(); if (!beast::Journal::isStructuredJournalEnabled()) { - format(s, text, level, partition); - result = s; + format(s, text.str(), level, partition); + text.str() = s; + result = text.str(); } // if (!silent_) - // std::cerr << s << '\n'; + // std::cerr << result << '\n'; - // Get a node from the pool or create a new one - if (!owner) return; - messages_.push(owner); + messages_.push(text); // Signal log thread that new messages are available - logCondition_.notify_one(); + // logCondition_.notify_one(); // Add to batch buffer for file output if (0) { @@ -291,42 +287,25 @@ Logs::flushBatchUnsafe() void Logs::logThreadWorker() { - beast::lockfree::queue::Node* node; - while (!stopLogThread_) { - std::unique_lock lock(logMutex_); - - // Wait for messages or stop signal - logCondition_.wait(lock, [this] { - return stopLogThread_ || !messages_.empty(); - }); - + std::this_thread::sleep_for(FLUSH_INTERVAL); + + beast::Journal::StringBuffer buffer; // Process all available messages - while ((node = messages_.pop())) + while (messages_.pop(buffer)) { - // Write to file - file_.write(std::move(node->data)); - // Also write to console if not silent if (!silent_) - std::cerr << node->data << '\n'; - + std::cerr << buffer.str() << '\n'; + + // Write to file + file_.write(buffer.str()); + // Return node to pool for reuse - beast::Journal::returnMessageNode(node); + beast::Journal::returnStringBuffer(std::move(buffer)); } } - - // Process any remaining messages on shutdown - while ((node = messages_.pop())) - { - file_.write(std::move(node->data)); - if (!silent_) - std::cerr << node->data << '\n'; - - // Return node to pool for reuse - beast::Journal::returnMessageNode(node); - } } std::string diff --git a/src/libxrpl/beast/utility/beast_Journal.cpp b/src/libxrpl/beast/utility/beast_Journal.cpp index b7a7c7ef18..6a932ac8de 100644 --- a/src/libxrpl/beast/utility/beast_Journal.cpp +++ b/src/libxrpl/beast/utility/beast_Journal.cpp @@ -113,7 +113,7 @@ fastTimestampToString(std::int64_t milliseconds_since_epoch) std::string Journal::globalLogAttributes_; std::shared_mutex Journal::globalLogAttributesMutex_; bool Journal::jsonLogsEnabled_ = false; -lockfree::queue Journal::messagePool_{}; +Journal::StringBufferPool Journal::messagePool_{}; thread_local Journal::JsonLogContext Journal::currentJsonLogContext_{}; //------------------------------------------------------------------------------ @@ -157,12 +157,12 @@ public: } void - write(severities::Severity, std::string_view, Journal::MessagePoolNode = nullptr) override + write(severities::Severity, Journal::StringBuffer) override { } void - writeAlways(severities::Severity, std::string_view, Journal::MessagePoolNode = nullptr) override + writeAlways(severities::Severity, Journal::StringBuffer) override { } }; @@ -205,7 +205,7 @@ severities::to_string(Severity severity) } void -Journal::JsonLogContext::reset( +Journal::JsonLogContext::start( std::source_location location, severities::Severity severity, std::string_view moduleName, @@ -223,7 +223,16 @@ Journal::JsonLogContext::reset( }; thread_local ThreadIdStringInitializer const threadId; - messageBuffer_->data.clear(); + if (!messageBufferHandedOut_) + { + returnStringBuffer(std::move(messageBuffer_)); + messageBufferHandedOut_ = true; + } + messageBuffer_ = rentFromPool(); + messageBufferHandedOut_ = false; + messageBuffer_.str().reserve(1024 * 5); + messageBuffer_.str().clear(); + jsonWriter_ = detail::SimpleJsonWriter{&messageBuffer_.str()}; if (!jsonLogsEnabled_) { @@ -284,15 +293,23 @@ Journal::JsonLogContext::reset( hasMessageParams_ = false; } +void +Journal::JsonLogContext::finish() +{ + messageBufferHandedOut_ = true; + messageBuffer_ = {}; + jsonWriter_ = {}; +} + void Journal::initMessageContext( std::source_location location, severities::Severity severity) const { - currentJsonLogContext_.reset(location, severity, name_, attributes_); + currentJsonLogContext_.start(location, severity, name_, attributes_); } -Journal::MessagePoolNode +Journal::StringBuffer Journal::formatLog(std::string const& message) { if (!jsonLogsEnabled_) @@ -397,7 +414,8 @@ Journal::ScopedStream::~ScopedStream() s = ""; auto messageHandle = formatLog(s); - m_sink.write(m_level, messageHandle->data, messageHandle); + m_sink.write(m_level, messageHandle); + currentJsonLogContext_.finish(); } } @@ -407,12 +425,4 @@ Journal::ScopedStream::operator<<(std::ostream& manip(std::ostream&)) const return m_ostream << manip; } -//------------------------------------------------------------------------------ - -Journal::ScopedStream -Journal::Stream::operator<<(std::ostream& manip(std::ostream&)) const -{ - return {*this, manip}; -} - } // namespace beast diff --git a/src/test/beast/beast_Journal_test.cpp b/src/test/beast/beast_Journal_test.cpp index e50d47b2e8..43f5d1668e 100644 --- a/src/test/beast/beast_Journal_test.cpp +++ b/src/test/beast/beast_Journal_test.cpp @@ -48,14 +48,14 @@ public: } void - write(severities::Severity level, std::string_view, beast::Journal::MessagePoolNode = nullptr) override + write(severities::Severity level, Journal::StringBuffer) override { if (level >= threshold()) ++m_count; } void - writeAlways(severities::Severity level, std::string_view, beast::Journal::MessagePoolNode = nullptr) override + writeAlways(severities::Severity level, Journal::StringBuffer) override { ++m_count; } diff --git a/src/test/csf/Sim.h b/src/test/csf/Sim.h index 7a606b40bf..e25d1a17f1 100644 --- a/src/test/csf/Sim.h +++ b/src/test/csf/Sim.h @@ -49,19 +49,19 @@ public: } void - write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + write(beast::severities::Severity level, beast::Journal::StringBuffer text) override { if (level < threshold()) return; - std::cout << clock_.now().time_since_epoch().count() << " " << text + std::cout << clock_.now().time_since_epoch().count() << " " << text.str() << std::endl; } void - writeAlways(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + writeAlways(beast::severities::Severity level, beast::Journal::StringBuffer text) override { - std::cout << clock_.now().time_since_epoch().count() << " " << text + std::cout << clock_.now().time_since_epoch().count() << " " << text.str() << std::endl; } }; diff --git a/src/test/jtx/CaptureLogs.h b/src/test/jtx/CaptureLogs.h index 2abcc6bd25..4d3bca044b 100644 --- a/src/test/jtx/CaptureLogs.h +++ b/src/test/jtx/CaptureLogs.h @@ -57,18 +57,18 @@ class CaptureLogs : public Logs } void - write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + write(beast::severities::Severity level, beast::Journal::StringBuffer text) override { std::lock_guard lock(strmMutex_); - strm_ << text; + strm_ << text.str(); } void - writeAlways(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) + writeAlways(beast::severities::Severity level, beast::Journal::StringBuffer text) override { std::lock_guard lock(strmMutex_); - strm_ << text; + strm_ << text.str(); } }; diff --git a/src/test/jtx/CheckMessageLogs.h b/src/test/jtx/CheckMessageLogs.h index 18ae98b196..63c37a6619 100644 --- a/src/test/jtx/CheckMessageLogs.h +++ b/src/test/jtx/CheckMessageLogs.h @@ -45,17 +45,17 @@ class CheckMessageLogs : public Logs } void - write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + write(beast::severities::Severity level, beast::Journal::StringBuffer text) override { - if (text.find(owner_.msg_) != std::string::npos) + if (text.str().find(owner_.msg_) != std::string::npos) *owner_.pFound_ = true; } void - writeAlways(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) + writeAlways(beast::severities::Severity level, beast::Journal::StringBuffer text) override { - write(level, text, owner); + write(level, text); } }; diff --git a/src/test/server/Server_test.cpp b/src/test/server/Server_test.cpp index 2ae572dfc2..81a7ef3b7a 100644 --- a/src/test/server/Server_test.cpp +++ b/src/test/server/Server_test.cpp @@ -89,19 +89,19 @@ public: } void - write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + write(beast::severities::Severity level, beast::Journal::StringBuffer text) override { if (level < threshold()) return; - suite_.log << text << std::endl; + suite_.log << text.str() << std::endl; } void - writeAlways(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) + writeAlways(beast::severities::Severity level, beast::Journal::StringBuffer text) override { - suite_.log << text << std::endl; + suite_.log << text.str() << std::endl; } }; diff --git a/src/test/unit_test/SuiteJournal.h b/src/test/unit_test/SuiteJournal.h index fc0f85d69a..f4858cd780 100644 --- a/src/test/unit_test/SuiteJournal.h +++ b/src/test/unit_test/SuiteJournal.h @@ -49,25 +49,24 @@ public: } void - write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override; + write(beast::severities::Severity level, beast::Journal::StringBuffer text) override; void - writeAlways(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override; + writeAlways(beast::severities::Severity level, beast::Journal::StringBuffer text) override; }; inline void -SuiteJournalSink::write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner) +SuiteJournalSink::write(beast::severities::Severity level, beast::Journal::StringBuffer text) { // Only write the string if the level at least equals the threshold. if (level >= threshold()) - writeAlways(level, text, owner); + writeAlways(level, text); } inline void SuiteJournalSink::writeAlways( beast::severities::Severity level, - std::string_view text, - beast::Journal::MessagePoolNode owner) + beast::Journal::StringBuffer text) { using namespace beast::severities; @@ -94,7 +93,7 @@ SuiteJournalSink::writeAlways( static std::mutex log_mutex; std::lock_guard lock(log_mutex); - suite_.log << s << partition_ << text << std::endl; + suite_.log << s << partition_ << text.str() << std::endl; } class SuiteJournal @@ -135,17 +134,17 @@ public: } void - write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + write(beast::severities::Severity level, beast::Journal::StringBuffer text) override { if (level < threshold()) return; - writeAlways(level, text, owner); + writeAlways(level, text); } inline void - writeAlways(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode = nullptr) override + writeAlways(beast::severities::Severity level, beast::Journal::StringBuffer text) override { - strm_ << text << std::endl; + strm_ << text.str() << std::endl; } std::stringstream const& diff --git a/src/tests/libxrpl/basics/log.cpp b/src/tests/libxrpl/basics/log.cpp index 10c2bb4c89..f48d347530 100644 --- a/src/tests/libxrpl/basics/log.cpp +++ b/src/tests/libxrpl/basics/log.cpp @@ -53,13 +53,13 @@ private: operator=(Sink const&) = delete; void - write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + write(beast::severities::Severity level, beast::Journal::StringBuffer text) override { logs_.write(level, partition_, text, false); } void - writeAlways(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) + writeAlways(beast::severities::Severity level, beast::Journal::StringBuffer text) override { logs_.write(level, partition_, text, false); @@ -86,17 +86,19 @@ public: write( beast::severities::Severity level, std::string const& partition, - std::string_view text, + beast::Journal::StringBuffer text, bool console) { std::string s; - std::string_view result = text; + std::string_view result = text.str(); if (!beast::Journal::isStructuredJournalEnabled()) { - format(s, text, level, partition); - result = s; + format(s, text.str(), level, partition); + text.str() = s; + result = text.str(); } logStream_.append(result); + beast::Journal::returnStringBuffer(std::move(text)); } }; @@ -228,7 +230,8 @@ TEST_CASE("Test JsonWriter") beast::detail::SimpleJsonWriter writer{buffer}; writer.writeString("\n\r\t123\b\f123"); - CHECK(writer.finish() == "\"\\n\\r\\t123\\b\\f123\""); + writer.finish(); + CHECK(writer.buffer() == "\"\\n\\r\\t123\\b\\f123\""); } { @@ -236,7 +239,8 @@ TEST_CASE("Test JsonWriter") beast::detail::SimpleJsonWriter writer{buffer}; writer.writeString("\t"); - CHECK(writer.finish() == "\"\\t\""); + writer.finish(); + CHECK(writer.buffer() == "\"\\t\""); } { @@ -244,7 +248,8 @@ TEST_CASE("Test JsonWriter") beast::detail::SimpleJsonWriter writer{buffer}; writer.writeString(std::string_view{"\0", 1}); - CHECK(writer.finish() == "\"\\u0000\""); + writer.finish(); + CHECK(writer.buffer() == "\"\\u0000\""); } { @@ -252,7 +257,8 @@ TEST_CASE("Test JsonWriter") beast::detail::SimpleJsonWriter writer{buffer}; writer.writeString("\"\\"); - CHECK(writer.finish() == "\"\\\"\\\\\""); + writer.finish(); + CHECK(writer.buffer() == "\"\\\"\\\\\""); } { @@ -264,7 +270,8 @@ TEST_CASE("Test JsonWriter") writer.writeBool(false); writer.writeNull(); writer.endArray(); - CHECK(writer.finish() == "[true,false,null]"); + writer.finish(); + CHECK(writer.buffer() == "[true,false,null]"); } } @@ -321,9 +328,10 @@ TEST_CASE("Test setJsonValue") log::detail::setJsonValue( writer, "testStream", {}, &stringBuf); writer.endObject(); + writer.finish(); CHECK( - writer.finish() == + writer.buffer() == R"AAA({"testBool":true,"testInt32":-1,"testUInt32":1,"testInt64":-1,"testUInt64":1,"testDouble":1.1,"testCharStar":"Char*","testStdString":"StdString","testStdStringView":"StdStringView","testToChars":"0","testStream":"0"})AAA"); } @@ -358,15 +366,15 @@ public: } void - write(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + write(beast::severities::Severity level, beast::Journal::StringBuffer text) override { - strm_ << text; + strm_ << text.str(); } void - writeAlways(beast::severities::Severity level, std::string_view text, beast::Journal::MessagePoolNode owner = nullptr) override + writeAlways(beast::severities::Severity level, beast::Journal::StringBuffer text) override { - strm_ << text; + strm_ << text.str(); } }; diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index 8dfd48c761..c43ed1fdc5 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -1132,10 +1132,10 @@ RclConsensusLogger::~RclConsensusLogger() << std::setw(3) << std::setfill('0') << (duration.count() % 1000) << "s. " << ss_->str(); + auto node = beast::Journal::rentFromPool(); if (beast::Journal::isStructuredJournalEnabled()) { - auto node = beast::Journal::rentFromPool(); - beast::detail::SimpleJsonWriter writer{node->data}; + beast::detail::SimpleJsonWriter writer{&node.str()}; writer.startObject(); writer.writeKey("Msg"); writer.writeString(outSs.str()); @@ -1143,12 +1143,12 @@ RclConsensusLogger::~RclConsensusLogger() writer.writeString(to_string(std::chrono::system_clock::now())); writer.endObject(); writer.finish(); - j_.sink().writeAlways(beast::severities::kInfo, writer.buffer(), node); } else { - j_.sink().writeAlways(beast::severities::kInfo, outSs.str()); + node.str() = outSs.str(); } + j_.sink().writeAlways(beast::severities::kInfo, node); } } // namespace ripple