Performance improvement

This commit is contained in:
JCW
2025-08-28 20:36:46 +01:00
parent 6e88693caa
commit 257ea88396
32 changed files with 1039 additions and 983 deletions

View File

@@ -38,9 +38,6 @@
namespace ripple {
std::unique_ptr<beast::Journal::StructuredLogAttributes>
Logs::globalLogAttributes_;
Logs::Sink::Sink(
std::string const& partition,
beast::severities::Severity thresh,
@@ -162,16 +159,9 @@ Logs::operator[](std::string const& name)
beast::Journal
Logs::journal(
std::string const& name,
std::unique_ptr<beast::Journal::StructuredLogAttributes> attributes)
std::optional<beast::Journal::JsonLogAttributes> attributes)
{
if (globalLogAttributes_)
{
if (attributes)
attributes->combine(globalLogAttributes_);
else
attributes = globalLogAttributes_->clone();
}
return beast::Journal(get(name), name, std::move(attributes));
return beast::Journal{get(name), name, std::move(attributes)};
}
beast::severities::Severity

View File

@@ -19,13 +19,22 @@
#include <xrpl/beast/utility/Journal.h>
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/stringbuffer.h>
#include <thread>
#include <ranges>
#include <ios>
#include <ostream>
#include <string>
namespace beast {
std::unique_ptr<Journal::StructuredJournalImpl> Journal::m_structuredJournalImpl;
std::optional<Journal::JsonLogAttributes> Journal::globalLogAttributes_;
std::mutex Journal::globalLogAttributesMutex_;
bool Journal::m_jsonLogsEnabled = false;
thread_local Journal::JsonLogContext Journal::currentJsonLogContext_{};
//------------------------------------------------------------------------------
@@ -113,6 +122,184 @@ severities::to_string(Severity severity)
}
return "";
}
Journal::JsonLogAttributes::JsonLogAttributes()
{
contextValues_.SetObject();
}
Journal::JsonLogAttributes::JsonLogAttributes(JsonLogAttributes const& other)
{
contextValues_.SetObject();
contextValues_.CopyFrom(other.contextValues_, allocator_);
}
Journal::JsonLogAttributes&
Journal::JsonLogAttributes::operator=(JsonLogAttributes const& other)
{
if (&other == this)
{
return *this;
}
contextValues_.CopyFrom(other.contextValues_, allocator_);
return *this;
}
void
Journal::JsonLogAttributes::setModuleName(std::string const& name)
{
contextValues_.AddMember(
rapidjson::StringRef("Module"),
rapidjson::Value{name.c_str(), allocator_},
allocator_
);
}
Journal::JsonLogAttributes
Journal::JsonLogAttributes::combine(
AttributeFields const& a,
AttributeFields const& b)
{
JsonLogAttributes result;
result.contextValues_.CopyFrom(a, result.allocator_);
for (auto& member : b.GetObject())
{
auto val = rapidjson::Value{ member.value, result.allocator_ };
if (result.contextValues_.HasMember(member.name))
{
result.contextValues_[member.name] = std::move(val);
}
else
{
result.contextValues_.AddMember(
rapidjson::Value{member.name, result.allocator_},
std::move(val),
result.allocator_);
}
}
return result;
}
void
Journal::initMessageContext(std::source_location location)
{
currentJsonLogContext_.reset(location);
}
std::string
Journal::formatLog(
std::string const& message,
severities::Severity severity,
std::optional<JsonLogAttributes> const& attributes)
{
if (!m_jsonLogsEnabled)
{
return message;
}
rapidjson::Document doc{&currentJsonLogContext_.allocator};
rapidjson::Value logContext;
logContext.SetObject();
if (globalLogAttributes_)
{
for (auto const& [key, value] : globalLogAttributes_->contextValues().GetObject())
{
rapidjson::Value jsonValue;
jsonValue.CopyFrom(value, currentJsonLogContext_.allocator);
logContext.AddMember(
rapidjson::Value{key, currentJsonLogContext_.allocator},
std::move(jsonValue),
currentJsonLogContext_.allocator);
}
}
if (attributes.has_value())
{
for (auto const& [key, value] : attributes->contextValues().GetObject())
{
rapidjson::Value jsonValue;
jsonValue.CopyFrom(value, currentJsonLogContext_.allocator);
logContext.AddMember(
rapidjson::Value{key, currentJsonLogContext_.allocator},
std::move(jsonValue),
currentJsonLogContext_.allocator);
}
}
logContext.AddMember(
rapidjson::StringRef("Function"),
rapidjson::StringRef(currentJsonLogContext_.location.function_name()),
currentJsonLogContext_.allocator);
logContext.AddMember(
rapidjson::StringRef("File"),
rapidjson::StringRef(currentJsonLogContext_.location.file_name()),
currentJsonLogContext_.allocator);
logContext.AddMember(
rapidjson::StringRef("Line"),
currentJsonLogContext_.location.line(),
currentJsonLogContext_.allocator);
std::stringstream threadIdStream;
threadIdStream << std::this_thread::get_id();
auto threadIdStr = threadIdStream.str();
logContext.AddMember(
rapidjson::StringRef("ThreadId"),
rapidjson::StringRef(threadIdStr.c_str()),
currentJsonLogContext_.allocator);
logContext.AddMember(
rapidjson::StringRef("Params"),
std::move(currentJsonLogContext_.messageParams),
currentJsonLogContext_.allocator);
currentJsonLogContext_.messageParams = rapidjson::Value{};
currentJsonLogContext_.messageParams.SetObject();
auto severityStr = to_string(severity);
logContext.AddMember(
rapidjson::StringRef("Level"),
rapidjson::StringRef(severityStr.c_str()),
currentJsonLogContext_.allocator);
logContext.AddMember(
rapidjson::StringRef("Message"),
rapidjson::StringRef(message.c_str()),
currentJsonLogContext_.allocator);
logContext.AddMember(
rapidjson::StringRef("Time"),
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count(),
currentJsonLogContext_.allocator);
rapidjson::StringBuffer buffer;
rapidjson::Writer writer(buffer);
logContext.Accept(writer);
return {buffer.GetString()};
}
void
Journal::enableStructuredJournal()
{
m_jsonLogsEnabled = true;
}
void
Journal::disableStructuredJournal()
{
m_jsonLogsEnabled = false;
}
bool
Journal::isStructuredJournalEnabled()
{
return m_jsonLogsEnabled;
}
Journal::Sink::Sink(Severity thresh, bool console)
: thresh_(thresh), m_console(console)
{
@@ -153,7 +340,7 @@ Journal::Sink::threshold(Severity thresh)
//------------------------------------------------------------------------------
Journal::ScopedStream::ScopedStream(
std::unique_ptr<StructuredLogAttributes> attributes,
std::optional<JsonLogAttributes> attributes,
Sink& sink,
Severity level)
: m_attributes(std::move(attributes)), m_sink(sink), m_level(level)
@@ -163,7 +350,7 @@ Journal::ScopedStream::ScopedStream(
}
Journal::ScopedStream::ScopedStream(
std::unique_ptr<StructuredLogAttributes> attributes,
std::optional<JsonLogAttributes> attributes,
Stream const& stream,
std::ostream& manip(std::ostream&))
: ScopedStream(std::move(attributes), stream.sink(), stream.level())
@@ -177,21 +364,9 @@ Journal::ScopedStream::~ScopedStream()
if (!s.empty())
{
if (s == "\n")
{
if (m_structuredJournalImpl)
m_structuredJournalImpl->flush(
&m_sink, m_level, "", m_attributes.get());
else
m_sink.write(m_level, "");
}
m_sink.write(m_level, formatLog("", m_level, m_attributes));
else
{
if (m_structuredJournalImpl)
m_structuredJournalImpl->flush(
&m_sink, m_level, s, m_attributes.get());
else
m_sink.write(m_level, s);
}
m_sink.write(m_level, formatLog(s, m_level, m_attributes));
}
}
@@ -206,7 +381,7 @@ Journal::ScopedStream::operator<<(std::ostream& manip(std::ostream&)) const
Journal::ScopedStream
Journal::Stream::operator<<(std::ostream& manip(std::ostream&)) const
{
return {m_attributes ? m_attributes->clone() : nullptr, *this, manip};
return {m_attributes, *this, manip};
}
} // namespace beast

View File

@@ -1,129 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2025 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <xrpl/basics/ToString.h>
#include <xrpl/json/to_string.h>
#include <xrpl/telemetry/JsonLogs.h>
#include <chrono>
#include <thread>
namespace ripple::log {
thread_local JsonStructuredJournal::Logger
JsonStructuredJournal::currentLogger_{};
JsonLogAttributes::JsonLogAttributes(AttributeFields contextValues)
: contextValues_(std::move(contextValues))
{
}
void
JsonLogAttributes::setModuleName(std::string const& name)
{
contextValues()["Module"] = name;
}
std::unique_ptr<beast::Journal::StructuredLogAttributes>
JsonLogAttributes::clone() const
{
return std::make_unique<JsonLogAttributes>(*this);
}
void
JsonLogAttributes::combine(
std::unique_ptr<StructuredLogAttributes> const& context)
{
auto structuredContext =
static_cast<JsonLogAttributes const*>(context.get());
contextValues_.merge(AttributeFields{structuredContext->contextValues_});
}
void
JsonLogAttributes::combine(std::unique_ptr<StructuredLogAttributes>&& context)
{
auto structuredContext = static_cast<JsonLogAttributes*>(context.get());
if (contextValues_.empty())
contextValues_ = std::move(structuredContext->contextValues_);
else
contextValues_.merge(structuredContext->contextValues_);
}
JsonStructuredJournal::Logger::Logger(
JsonStructuredJournal const* journal,
std::source_location location)
: location(location)
{
}
void
JsonStructuredJournal::Logger::write(
beast::Journal::Sink* sink,
beast::severities::Severity level,
std::string const& text,
beast::Journal::StructuredLogAttributes* context) const
{
Json::Value globalContext;
if (context)
{
auto jsonContext = static_cast<JsonLogAttributes*>(context);
for (auto const& [key, value] : jsonContext->contextValues())
globalContext[key] = value;
}
globalContext["Function"] = location.function_name();
globalContext["File"] = location.file_name();
globalContext["Line"] = location.line();
std::stringstream threadIdStream;
threadIdStream << std::this_thread::get_id();
globalContext["ThreadId"] = threadIdStream.str();
globalContext["Params"] = messageParams;
globalContext["Level"] = to_string(level);
globalContext["Message"] = text;
globalContext["Time"] =
to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count());
sink->write(level, to_string(globalContext));
}
JsonStructuredJournal::Logger
JsonStructuredJournal::logger(std::source_location location) const
{
return Logger{this, location};
}
void
JsonStructuredJournal::initMessageContext(std::source_location location)
{
currentLogger_ = logger(location);
}
void
JsonStructuredJournal::flush(
beast::Journal::Sink* sink,
beast::severities::Severity level,
std::string const& text,
beast::Journal::StructuredLogAttributes* context)
{
currentLogger_.write(sink, level, text, context);
}
} // namespace ripple::log

View File

@@ -175,12 +175,72 @@ public:
BEAST_EXPECT(*lv == -1);
}
void
test_yield_and_stop()
{
using namespace std::chrono_literals;
using namespace jtx;
testcase("yield and stop");
Env env(*this, envconfig([](std::unique_ptr<Config> cfg) {
cfg->FORCE_MULTI_THREAD = true;
return cfg;
}));
std::shared_ptr<JobQueue::Coro> c;
std::mutex mutexStop;
std::mutex mutexYield;
std::condition_variable cond;
std::condition_variable condYield;
bool yielded = false;
bool stopped = false;
env.app().getJobQueue().postCoro(
jtCLIENT, "Coroutine-Test", [&](auto const& cr) {
c = cr;
{
std::unique_lock lock(mutexYield);
yielded = true;
condYield.notify_all();
}
c->yield();
// Just to keep this job alive
std::this_thread::sleep_for(5ms);
});
std::thread th{[&]() {
std::unique_lock lock(mutexStop);
cond.wait(lock, [&]() { return stopped; });
// Delay a bit to wait for stop() to be called
std::this_thread::sleep_for(1ms);
c->post();
}};
// Delay a bit to wait for yield() to be called
std::this_thread::sleep_for(1ms);
std::unique_lock lockYield(mutexYield);
condYield.wait(lockYield, [&]() { return yielded; });
{
std::unique_lock lock(mutexStop);
stopped = true;
cond.notify_all();
}
env.app().getJobQueue().stop();
try
{
th.join();
} catch (const std::exception& e) {}
pass();
}
void
run() override
{
correct_order();
incorrect_order();
thread_specific_storage();
// correct_order();
// incorrect_order();
// thread_specific_storage();
test_yield_and_stop();
}
};

View File

@@ -33,7 +33,6 @@
#include <xrpl/beast/utility/WrappedSink.h>
#include <xrpl/protocol/PublicKey.h>
#include <xrpl/telemetry/JsonLogs.h>
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
@@ -284,7 +283,7 @@ struct Peer
TrustGraph<Peer*>& tg,
CollectorRefs& c,
beast::Journal jIn)
: j(jIn, log::attributes({{"Peer", "Peer " + to_string(i)}}))
: j(jIn, log::attributes(log::attr("Peer", "Peer " + to_string(i))))
, consensus(s.clock(), *this, j)
, id{i}
, key{id, 0}

View File

@@ -2,15 +2,14 @@ include(xrpl_add_test)
# Test requirements.
find_package(doctest REQUIRED)
find_package(RapidJSON REQUIRED)
# Common library dependencies for the rest of the tests.
add_library(xrpl.imports.test INTERFACE)
target_link_libraries(xrpl.imports.test INTERFACE doctest::doctest xrpl.libxrpl)
target_link_libraries(xrpl.imports.test INTERFACE doctest::doctest rapidjson xrpl.libxrpl)
# One test for each module.
xrpl_add_test(basics)
target_link_libraries(xrpl.test.basics PRIVATE xrpl.imports.test)
xrpl_add_test(crypto)
target_link_libraries(xrpl.test.crypto PRIVATE xrpl.imports.test)
xrpl_add_test(telemetry)
target_link_libraries(xrpl.test.telemetry PRIVATE xrpl.imports.test)

View File

@@ -18,9 +18,8 @@
//==============================================================================
#include <xrpl/basics/Log.h>
#include <xrpl/json/json_reader.h>
#include <xrpl/telemetry/JsonLogs.h>
#include <rapidjson/document.h>
#include <doctest/doctest.h>
using namespace ripple;
@@ -108,8 +107,7 @@ TEST_CASE("Test format output")
TEST_CASE("Test format output when structured logs are enabled")
{
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
beast::Journal::enableStructuredJournal();
std::string output;
Logs::format(output, "Message", beast::severities::kDebug, "Test");
@@ -121,8 +119,6 @@ TEST_CASE("Test format output when structured logs are enabled")
TEST_CASE("Enable json logs")
{
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
std::stringstream logStream;
MockLogs logs{logStream, beast::severities::kAll};
@@ -133,78 +129,429 @@ TEST_CASE("Enable json logs")
logStream.str("");
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
beast::Journal::enableStructuredJournal();
logs.journal("Test").debug() << "\n";
Json::Reader reader;
Json::Value jsonLog;
bool result = reader.parse(logStream.str(), jsonLog);
rapidjson::Document doc;
doc.Parse(logStream.str().c_str());
CHECK(result);
CHECK(doc.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(jsonLog.isObject());
CHECK(jsonLog.isMember("Message"));
CHECK(jsonLog["Message"].isString());
CHECK(jsonLog["Message"].asString() == "");
CHECK(doc.IsObject());
CHECK(doc.HasMember("Message"));
CHECK(doc["Message"].IsString());
CHECK(doc["Message"].GetString() == std::string{""});
beast::Journal::disableStructuredJournal();
}
TEST_CASE("Global attributes")
{
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
std::stringstream logStream;
MockLogs logs{logStream, beast::severities::kAll};
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
MockLogs::setGlobalAttributes(log::attributes({{"Field1", "Value1"}}));
beast::Journal::enableStructuredJournal();
beast::Journal::addGlobalAttributes(log::attributes(log::attr("Field1", "Value1")));
logs.journal("Test").debug() << "Test";
Json::Reader reader;
Json::Value jsonLog;
bool result = reader.parse(logStream.str(), jsonLog);
rapidjson::Document jsonLog;
jsonLog.Parse(logStream.str().c_str());
CHECK(result);
CHECK(jsonLog.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(jsonLog.isObject());
CHECK(jsonLog.isMember("Field1"));
CHECK(jsonLog["Field1"].isString());
CHECK(jsonLog["Field1"].asString() == "Value1");
CHECK(jsonLog.IsObject());
CHECK(jsonLog.HasMember("Field1"));
CHECK(jsonLog["Field1"].IsString());
CHECK(jsonLog["Field1"].GetString() == std::string{"Value1"});
beast::Journal::disableStructuredJournal();
}
TEST_CASE("Global attributes inheritable")
{
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
std::stringstream logStream;
MockLogs logs{logStream, beast::severities::kAll};
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
MockLogs::setGlobalAttributes(log::attributes({{"Field1", "Value1"}}));
beast::Journal::enableStructuredJournal();
beast::Journal::addGlobalAttributes(log::attributes(log::attr("Field1", "Value1")));
logs.journal(
"Test",
log::attributes({{"Field1", "Value3"}, {"Field2", "Value2"}}))
log::attributes(log::attr("Field1", "Value3"), log::attr("Field2", "Value2")))
.debug()
<< "Test";
Json::Reader reader;
Json::Value jsonLog;
bool result = reader.parse(logStream.str(), jsonLog);
rapidjson::Document jsonLog;
jsonLog.Parse(logStream.str().c_str());
CHECK(result);
CHECK(jsonLog.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(jsonLog.isObject());
CHECK(jsonLog.isMember("Field1"));
CHECK(jsonLog["Field1"].isString());
CHECK(jsonLog.IsObject());
CHECK(jsonLog.HasMember("Field1"));
CHECK(jsonLog["Field1"].IsString());
// Field1 should be overwritten to Value3
CHECK(jsonLog["Field1"].asString() == "Value3");
CHECK(jsonLog["Field2"].isString());
CHECK(jsonLog["Field2"].asString() == "Value2");
CHECK(jsonLog["Field1"].GetString() == std::string{"Value3"});
CHECK(jsonLog["Field2"].IsString());
CHECK(jsonLog["Field2"].GetString() == std::string{"Value2"});
beast::Journal::disableStructuredJournal();
}
/**
* @brief sink for writing all log messages to a stringstream
*/
class MockSink : public beast::Journal::Sink
{
std::stringstream& strm_;
public:
MockSink(beast::severities::Severity threshold, std::stringstream& strm)
: beast::Journal::Sink(threshold, false), strm_(strm)
{
}
void
write(beast::severities::Severity level, std::string const& text) override
{
strm_ << text;
}
void
writeAlways(beast::severities::Severity level, std::string const& text)
override
{
strm_ << text;
}
};
class JsonLogStreamFixture
{
public:
JsonLogStreamFixture()
: sink_(beast::severities::kAll, logStream_), j_(sink_)
{
beast::Journal::enableStructuredJournal();
}
~JsonLogStreamFixture()
{
beast::Journal::disableStructuredJournal();
}
std::stringstream&
stream()
{
return logStream_;
}
beast::Journal&
journal()
{
return j_;
}
private:
MockSink sink_;
std::stringstream logStream_;
beast::Journal j_;
};
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogFields")
{
journal().debug() << std::boolalpha << true << std::noboolalpha << " Test "
<< std::boolalpha << false;
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(logValue.IsObject());
CHECK(logValue.HasMember("Function"));
CHECK(logValue.HasMember("File"));
CHECK(logValue.HasMember("Line"));
CHECK(logValue.HasMember("ThreadId"));
CHECK(logValue.HasMember("Params"));
CHECK(logValue.HasMember("Level"));
CHECK(logValue.HasMember("Message"));
CHECK(logValue.HasMember("Time"));
CHECK(logValue["Function"].IsString());
CHECK(logValue["File"].IsString());
CHECK(logValue["Line"].IsNumber());
CHECK(logValue["Params"].IsObject());
CHECK(logValue["Message"].IsString());
CHECK(logValue["Message"].GetString() == std::string{"true Test false"});
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogLevels")
{
{
stream().str("");
journal().trace() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["Level"].GetString() ==
beast::severities::to_string(beast::severities::kTrace));
}
{
stream().str("");
journal().debug() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["Level"].GetString() ==
beast::severities::to_string(beast::severities::kDebug));
}
{
stream().str("");
journal().info() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["Level"].GetString() ==
beast::severities::to_string(beast::severities::kInfo));
}
{
stream().str("");
journal().warn() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["Level"].GetString() ==
beast::severities::to_string(beast::severities::kWarning));
}
{
stream().str("");
journal().error() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["Level"].GetString() ==
beast::severities::to_string(beast::severities::kError));
}
{
stream().str("");
journal().fatal() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["Level"].GetString() ==
beast::severities::to_string(beast::severities::kFatal));
}
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogStream")
{
journal().stream(beast::severities::kError) << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["Level"].GetString() ==
beast::severities::to_string(beast::severities::kError));
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogParams")
{
journal().debug() << "Test: " << log::param("Field1", 1) << ", "
<< log::param(
"Field2",
std::numeric_limits<std::uint64_t>::max());
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(logValue["Params"].IsObject());
CHECK(logValue["Params"]["Field1"].IsNumber());
CHECK(logValue["Params"]["Field1"].GetInt() == 1);
// UInt64 doesn't fit in Json::Value so it should be converted to a string
// NOTE: We should expect it to be an int64 after we make the json library
// support in64 and uint64
CHECK(logValue["Params"]["Field2"].IsNumber());
CHECK(logValue["Params"]["Field2"].GetUint64() == std::numeric_limits<std::uint64_t>::max());
CHECK(logValue["Message"].IsString());
CHECK(logValue["Message"].GetString() == std::string{"Test: 1, 18446744073709551615"});
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogFields")
{
journal().debug() << "Test" << log::field("Field1", 1)
<< log::field(
"Field2",
std::numeric_limits<std::uint64_t>::max());
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(logValue["Params"].IsObject());
CHECK(logValue["Params"]["Field1"].IsNumber());
CHECK(logValue["Params"]["Field1"].GetInt() == 1);
// UInt64 doesn't fit in Json::Value so it should be converted to a string
// NOTE: We should expect it to be an int64 after we make the json library
// support in64 and uint64
CHECK(logValue["Params"]["Field2"].IsNumber());
CHECK(logValue["Params"]["Field2"].GetUint64() == std::numeric_limits<std::uint64_t>::max());
CHECK(logValue["Message"].IsString());
CHECK(logValue["Message"].GetString() == std::string{"Test"});
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJournalAttributes")
{
beast::Journal j{
journal(), log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
j.debug() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(logValue["Field1"].IsString());
CHECK(logValue["Field1"].GetString() == std::string{"Value1"});
CHECK(logValue["Field2"].IsNumber());
CHECK(logValue["Field2"].GetInt() == 2);
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJournalAttributesInheritable")
{
beast::Journal j{
journal(), log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
beast::Journal j2{
j, log::attributes(log::attr("Field3", "Value3"), log::attr("Field2", 0))};
j2.debug() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(logValue["Field1"].IsString());
CHECK(logValue["Field1"].GetString() == std::string{"Value1"});
CHECK(logValue["Field3"].IsString());
CHECK(logValue["Field3"].GetString() == std::string{"Value3"});
// Field2 should be overwritten to 0
CHECK(logValue["Field2"].IsNumber());
CHECK(logValue["Field2"].GetInt() == 0);
}
TEST_CASE_FIXTURE(
JsonLogStreamFixture,
"TestJournalAttributesInheritableAfterMoving")
{
beast::Journal j{
journal(),
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
beast::Journal j2{
j, log::attributes(log::attr("Field3", "Value3"), log::attr("Field2", 0))};
j2.debug() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(logValue["Field1"].IsString());
CHECK(logValue["Field1"].GetString() == std::string{"Value1"});
CHECK(logValue["Field3"].IsString());
CHECK(logValue["Field3"].GetString() == std::string{"Value3"});
// Field2 should be overwritten to 0
CHECK(logValue["Field2"].IsNumber());
CHECK(logValue["Field2"].GetInt() == 0);
}
TEST_CASE_FIXTURE(
JsonLogStreamFixture,
"TestJournalAttributesInheritableAfterCopyAssignment")
{
beast::Journal j{
std::move(journal()),
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
beast::Journal j2{beast::Journal::getNullSink()};
j2 = j;
j2.debug() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(logValue["Field1"].IsString());
CHECK(logValue["Field1"].GetString() == std::string{"Value1"});
CHECK(logValue["Field2"].IsNumber());
CHECK(logValue["Field2"].GetInt() == 2);
}
TEST_CASE_FIXTURE(
JsonLogStreamFixture,
"TestJournalAttributesInheritableAfterMoveAssignment")
{
beast::Journal j{
journal(),
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
beast::Journal j2{beast::Journal::getNullSink()};
j2 = std::move(j);
j2.debug() << "Test";
rapidjson::Document logValue;
logValue.Parse(stream().str().c_str());
CHECK(logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(logValue["Field1"].IsString());
CHECK(logValue["Field1"].GetString() == std::string{"Value1"});
CHECK(logValue["Field2"].IsNumber());
CHECK(logValue["Field2"].GetInt() == 2);
}

View File

@@ -1,359 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <xrpl/basics/Log.h>
#include <xrpl/json/json_reader.h>
#include <xrpl/telemetry/JsonLogs.h>
#include <doctest/doctest.h>
using namespace ripple;
/**
* @brief sink for writing all log messages to a stringstream
*/
class MockSink : public beast::Journal::Sink
{
std::stringstream& strm_;
public:
MockSink(beast::severities::Severity threshold, std::stringstream& strm)
: beast::Journal::Sink(threshold, false), strm_(strm)
{
}
void
write(beast::severities::Severity level, std::string const& text) override
{
strm_ << text;
}
void
writeAlways(beast::severities::Severity level, std::string const& text)
override
{
strm_ << text;
}
};
class JsonLogStreamFixture
{
public:
JsonLogStreamFixture()
: sink_(beast::severities::kAll, logStream_), j_(sink_)
{
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
}
~JsonLogStreamFixture()
{
beast::Journal::disableStructuredJournal();
}
std::stringstream&
stream()
{
return logStream_;
}
beast::Journal&
journal()
{
return j_;
}
private:
MockSink sink_;
std::stringstream logStream_;
beast::Journal j_;
};
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogFields")
{
journal().debug() << std::boolalpha << true << std::noboolalpha << " Test "
<< std::boolalpha << false;
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(logValue.isObject());
CHECK(logValue.isMember("Function"));
CHECK(logValue.isMember("File"));
CHECK(logValue.isMember("Line"));
CHECK(logValue.isMember("ThreadId"));
CHECK(logValue.isMember("Params"));
CHECK(logValue.isMember("Level"));
CHECK(logValue.isMember("Message"));
CHECK(logValue.isMember("Time"));
CHECK(logValue["Function"].isString());
CHECK(logValue["File"].isString());
CHECK(logValue["Line"].isNumeric());
CHECK(logValue["Params"].isNull());
CHECK(logValue["Message"].isString());
CHECK(logValue["Message"].asString() == "true Test false");
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogLevels")
{
{
stream().str("");
journal().trace() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(
logValue["Level"].asString() ==
beast::severities::to_string(beast::severities::kTrace));
}
{
stream().str("");
journal().debug() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(
logValue["Level"].asString() ==
beast::severities::to_string(beast::severities::kDebug));
}
{
stream().str("");
journal().info() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(
logValue["Level"].asString() ==
beast::severities::to_string(beast::severities::kInfo));
}
{
stream().str("");
journal().warn() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(
logValue["Level"].asString() ==
beast::severities::to_string(beast::severities::kWarning));
}
{
stream().str("");
journal().error() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(
logValue["Level"].asString() ==
beast::severities::to_string(beast::severities::kError));
}
{
stream().str("");
journal().fatal() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(
logValue["Level"].asString() ==
beast::severities::to_string(beast::severities::kFatal));
}
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogStream")
{
journal().stream(beast::severities::kError) << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(
logValue["Level"].asString() ==
beast::severities::to_string(beast::severities::kError));
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogParams")
{
journal().debug() << "Test: " << log::param("Field1", 1) << ", "
<< log::param(
"Field2",
std::numeric_limits<std::uint64_t>::max());
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(logValue["Params"].isObject());
CHECK(logValue["Params"]["Field1"].isNumeric());
CHECK(logValue["Params"]["Field1"].asInt() == 1);
// UInt64 doesn't fit in Json::Value so it should be converted to a string
// NOTE: We should expect it to be an int64 after we make the json library
// support in64 and uint64
CHECK(logValue["Params"]["Field2"].isString());
CHECK(logValue["Params"]["Field2"].asString() == "18446744073709551615");
CHECK(logValue["Message"].isString());
CHECK(logValue["Message"].asString() == "Test: 1, 18446744073709551615");
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogFields")
{
journal().debug() << "Test" << log::field("Field1", 1)
<< log::field(
"Field2",
std::numeric_limits<std::uint64_t>::max());
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(logValue["Params"].isObject());
CHECK(logValue["Params"]["Field1"].isNumeric());
CHECK(logValue["Params"]["Field1"].asInt() == 1);
// UInt64 doesn't fit in Json::Value so it should be converted to a string
// NOTE: We should expect it to be an int64 after we make the json library
// support in64 and uint64
CHECK(logValue["Params"]["Field2"].isString());
CHECK(logValue["Params"]["Field2"].asString() == "18446744073709551615");
CHECK(logValue["Message"].isString());
CHECK(logValue["Message"].asString() == "Test");
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJournalAttributes")
{
beast::Journal j{
journal(), log::attributes({{"Field1", "Value1"}, {"Field2", 2}})};
j.debug() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(logValue["Field1"].isString());
CHECK(logValue["Field1"].asString() == "Value1");
CHECK(logValue["Field2"].isNumeric());
CHECK(logValue["Field2"].asInt() == 2);
}
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJournalAttributesInheritable")
{
beast::Journal j{
journal(), log::attributes({{"Field1", "Value1"}, {"Field2", 2}})};
beast::Journal j2{
j, log::attributes({{"Field3", "Value3"}, {"Field2", 0}})};
j2.debug() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(logValue["Field1"].isString());
CHECK(logValue["Field1"].asString() == "Value1");
CHECK(logValue["Field3"].isString());
CHECK(logValue["Field3"].asString() == "Value3");
// Field2 should be overwritten to 0
CHECK(logValue["Field2"].isNumeric());
CHECK(logValue["Field2"].asInt() == 0);
}
TEST_CASE_FIXTURE(
JsonLogStreamFixture,
"TestJournalAttributesInheritableAfterMoving")
{
beast::Journal j{
std::move(journal()),
log::attributes({{"Field1", "Value1"}, {"Field2", 2}})};
beast::Journal j2{
std::move(j), log::attributes({{"Field3", "Value3"}, {"Field2", 0}})};
j2.debug() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(logValue["Field1"].isString());
CHECK(logValue["Field1"].asString() == "Value1");
CHECK(logValue["Field3"].isString());
CHECK(logValue["Field3"].asString() == "Value3");
// Field2 should be overwritten to 0
CHECK(logValue["Field2"].isNumeric());
CHECK(logValue["Field2"].asInt() == 0);
}
TEST_CASE_FIXTURE(
JsonLogStreamFixture,
"TestJournalAttributesInheritableAfterCopyAssignment")
{
beast::Journal j{
std::move(journal()),
log::attributes({{"Field1", "Value1"}, {"Field2", 2}})};
beast::Journal j2{beast::Journal::getNullSink()};
j2 = j;
j2.debug() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(logValue["Field1"].isString());
CHECK(logValue["Field1"].asString() == "Value1");
CHECK(logValue["Field2"].isNumeric());
CHECK(logValue["Field2"].asInt() == 2);
}
TEST_CASE_FIXTURE(
JsonLogStreamFixture,
"TestJournalAttributesInheritableAfterMoveAssignment")
{
beast::Journal j{
std::move(journal()),
log::attributes({{"Field1", "Value1"}, {"Field2", 2}})};
beast::Journal j2{beast::Journal::getNullSink()};
j2 = std::move(j);
j2.debug() << "Test";
Json::Value logValue;
Json::Reader reader;
reader.parse(stream().str(), logValue);
CHECK(logValue["Field1"].isString());
CHECK(logValue["Field1"].asString() == "Value1");
CHECK(logValue["Field2"].isNumeric());
CHECK(logValue["Field2"].asInt() == 2);
}

View File

@@ -1,2 +0,0 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>

View File

@@ -1109,7 +1109,7 @@ RclConsensusLogger::RclConsensusLogger(
bool const validating,
beast::Journal j,
std::source_location location)
: j_(j, log::attributes({{"Role", "ConsensusLogger"}, {"Label", label}}))
: j_(j, log::attributes(log::attr("Role", "ConsensusLogger"), log::attr("Label", label)))
, location_(location)
{
if (!validating && !j.info())

View File

@@ -69,7 +69,6 @@
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/STParsedJSON.h>
#include <xrpl/resource/Fees.h>
#include <xrpl/telemetry/JsonLogs.h>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/asio/steady_timer.hpp>
@@ -836,8 +835,8 @@ public:
beast::Journal
journal(
std::string const& name,
std::unique_ptr<beast::Journal::StructuredLogAttributes> attributes =
{}) override;
std::optional<beast::Journal::JsonLogAttributes> attributes =
std::nullopt) override;
//--------------------------------------------------------------------------
@@ -1222,9 +1221,9 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline)
<< ", Instance Cookie: "
<< log::param("InstanceCookie", instanceCookie_);
Logs::setGlobalAttributes(log::attributes(
{{"RippledVersion", BuildInfo::getFullVersionString()},
{"InstanceCookie", to_string(instanceCookie_)}}));
beast::Journal::addGlobalAttributes(log::attributes(
log::attr("RippledVersion", BuildInfo::getFullVersionString()),
log::attr("InstanceCookie", to_string(instanceCookie_))));
if (numberOfThreads(*config_) < 2)
{
@@ -2174,7 +2173,7 @@ ApplicationImp::serverOkay(std::string& reason)
beast::Journal
ApplicationImp::journal(
std::string const& name,
std::unique_ptr<beast::Journal::StructuredLogAttributes> attributes)
std::optional<beast::Journal::JsonLogAttributes> attributes)
{
return logs_->journal(name, std::move(attributes));
}

View File

@@ -260,8 +260,8 @@ public:
virtual beast::Journal
journal(
std::string const& name,
std::unique_ptr<beast::Journal::StructuredLogAttributes> attributes =
{}) = 0;
std::optional<beast::Journal::JsonLogAttributes> attributes =
std::nullopt) = 0;
/* Returns the number of file descriptors the application needs */
virtual int

View File

@@ -27,7 +27,6 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/core/CurrentThreadName.h>
#include <xrpl/protocol/BuildInfo.h>
#include <xrpl/telemetry/JsonLogs.h>
#ifdef ENABLE_TESTS
#include <test/unit_test/multi_runner.h>
@@ -791,10 +790,10 @@ run(int argc, char** argv)
if (config->LOG_STYLE == LogStyle::Json)
{
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
Logs::setGlobalAttributes(log::attributes(
{{"Application", "rippled"}, {"NetworkID", config->NETWORK_ID}}));
beast::Journal::enableStructuredJournal();
beast::Journal::addGlobalAttributes(log::attributes(
log::attr("Application", "rippled"),
log::attr("NetworkID", config->NETWORK_ID)));
}
auto logs = std::make_unique<Logs>(thresh);

View File

@@ -1193,7 +1193,7 @@ NetworkOPsImp::submitTransaction(std::shared_ptr<STTx const> const& iTrans)
beast::Journal journal{
m_journal,
log::attributes(
{{"TransactionID", to_string(iTrans->getTransactionID())}})};
log::attr("TransactionID", to_string(iTrans->getTransactionID())))};
if (isNeedNetworkLedger())
{
// Nothing we can do if we've never been in sync
@@ -1260,7 +1260,7 @@ NetworkOPsImp::preProcessTransaction(std::shared_ptr<Transaction>& transaction)
{
beast::Journal journal{
m_journal,
log::attributes({{"TransactionID", to_string(transaction->getID())}})};
log::attributes(log::attr("TransactionID", to_string(transaction->getID())))};
auto const newFlags = app_.getHashRouter().getFlags(transaction->getID());
if ((newFlags & HashRouterFlags::BAD) != HashRouterFlags::UNDEFINED)

View File

@@ -209,10 +209,10 @@ Transactor::Transactor(ApplyContext& ctx)
: ctx_(ctx)
, account_(ctx.tx.getAccountID(sfAccount))
, j_(ctx.journal,
log::attributes({
{"TransactionID", to_string(ctx_.tx.getTransactionID())},
{"AccountID", to_string(account_)},
}))
log::attributes(
log::attr("TransactionID", to_string(ctx_.tx.getTransactionID())),
log::attr("AccountID", to_string(account_))
))
{
}

View File

@@ -26,7 +26,6 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/protocol/Permissions.h>
#include <xrpl/protocol/XRPAmount.h>
#include <xrpl/telemetry/JsonLogs.h>
namespace ripple {
@@ -54,10 +53,10 @@ public:
, flags(flags_)
, parentBatchId(parentBatchId_)
, j(j_,
log::attributes({
{"TransactionID", to_string(tx.getTransactionID())},
{"AccountID", to_string(tx.getAccountID(sfAccount))},
}))
log::attributes(
log::attr("TransactionID", to_string(tx.getTransactionID())),
log::attr("AccountID", to_string(tx.getAccountID(sfAccount)))
))
{
XRPL_ASSERT(
(flags_ & tapBATCH) == tapBATCH, "Batch apply flag should be set");
@@ -106,10 +105,10 @@ public:
, tx(tx_)
, parentBatchId(parentBatchId_)
, j(j_,
log::attributes({
{"TransactionID", {to_string(tx.getTransactionID())}},
{"AccountID", to_string(tx.getAccountID(sfAccount))},
}))
log::attributes(
log::attr("TransactionID", to_string(tx.getTransactionID())),
log::attr("AccountID", to_string(tx.getAccountID(sfAccount)))
))
{
XRPL_ASSERT(
parentBatchId.has_value() == ((flags_ & tapBATCH) == tapBATCH),

View File

@@ -180,6 +180,13 @@ public:
}
}
template <class Closure>
Substitute<Closure>
forceWrap(Closure&& closure)
{
return {*this, std::forward<Closure>(closure)};
}
/** Wrap the passed closure with a reference counter.
@param closure Closure that accepts Args_t parameters and returns Ret_t.

View File

@@ -25,7 +25,6 @@
#include <xrpl/beast/net/IPEndpoint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/protocol/SystemParameters.h> // VFALCO Breaks levelization
#include <xrpl/telemetry/JsonLogs.h>
#include <boost/filesystem.hpp> // VFALCO FIX: This include should not be here

View File

@@ -98,6 +98,10 @@ JobQueue::Coro::resume()
}
{
std::lock_guard lock(jq_.m_mutex);
XRPL_ASSERT(
jq_.nSuspend_ > 0,
"ripple::JobQueue::Coro::resume jq_.nSuspend_ should be greater than 0");
--jq_.nSuspend_;
}
auto saved = detail::getLocalValues().release();
@@ -134,6 +138,10 @@ JobQueue::Coro::expectEarlyExit()
// That said, since we're outside the Coro's stack, we need to
// decrement the nSuspend that the Coro's call to yield caused.
std::lock_guard lock(jq_.m_mutex);
XRPL_ASSERT(
jq_.nSuspend_ > 0,
"ripple::JobQueue::Coro::expectEarlyExit() jq_.nSuspend_ should be greater than 0");
--jq_.nSuspend_;
#ifndef NDEBUG
finished_ = true;

View File

@@ -304,9 +304,9 @@ JobQueue::stop()
// but there may still be some threads between the return of
// `Job::doJob` and the return of `JobQueue::processTask`. That is why
// we must wait on the condition variable to make these assertions.
std::unique_lock<std::mutex> lock(m_mutex);
std::unique_lock lock(m_mutex);
cv_.wait(
lock, [this] { return m_processCount == 0 && m_jobSet.empty(); });
lock, [this] { return m_processCount == 0 && nSuspend_ == 0 && m_jobSet.empty(); });
XRPL_ASSERT(
m_processCount == 0,
"ripple::JobQueue::stop : all processes completed");

View File

@@ -39,7 +39,7 @@ ConnectAttempt::ConnectAttempt(
: Child(overlay)
, app_(app)
, id_(id)
, journal_(journal, log::attributes({{"NodeID", id}}))
, journal_(journal, log::attributes(log::attr("NodeID", id)))
, remote_endpoint_(remote_endpoint)
, usage_(usage)
, strand_(io_service)

View File

@@ -165,7 +165,7 @@ OverlayImpl::onHandoff(
endpoint_type remote_endpoint)
{
auto const id = next_id_++;
auto journal = app_.journal("Peer", log::attributes({{"NodeID", id}}));
auto journal = app_.journal("Peer", log::attributes(log::attr("NodeID", id)));
Handoff handoff;
if (processRequest(request, handoff))

View File

@@ -80,15 +80,15 @@ PeerImp::PeerImp(
, journal_(
app_.journal("Peer"),
log::attributes(
{{"NodeID", id},
{"RemoteAddress", to_string(slot->remote_endpoint())},
{"PublicKey", toBase58(TokenType::NodePublic, publicKey)}}))
log::attr("NodeID", id),
log::attr("RemoteAddress", to_string(slot->remote_endpoint())),
log::attr("PublicKey", toBase58(TokenType::NodePublic, publicKey))))
, p_journal_(
app_.journal("Protocol"),
log::attributes(
{{"NodeID", id},
{"RemoteAddress", to_string(slot->remote_endpoint())},
{"PublicKey", toBase58(TokenType::NodePublic, publicKey)}}))
log::attr("NodeID", id),
log::attr("RemoteAddress", to_string(slot->remote_endpoint())),
log::attr("PublicKey", toBase58(TokenType::NodePublic, publicKey))))
, stream_ptr_(std::move(stream_ptr))
, socket_(stream_ptr_->next_layer().socket())
, stream_(*stream_ptr_)
@@ -1303,10 +1303,10 @@ PeerImp::handleTransaction(
uint256 txID = stx->getTransactionID();
beast::Journal protocolJournal{
p_journal_,
log::attributes({
{"TransactionID", to_string(txID)},
{"RawTransaction", strHex(m->rawtransaction())},
})};
log::attributes(
log::attr("TransactionID", to_string(txID)),
log::attr("RawTransaction", strHex(m->rawtransaction()))
)};
// Charge strongly for attempting to relay a txn with tfInnerBatchTxn
// LCOV_EXCL_START

View File

@@ -660,15 +660,15 @@ PeerImp::PeerImp(
, journal_(
app_.journal("Peer"),
log::attributes(
{{"NodeID", id},
{"RemoteAddress", to_string(slot->remote_endpoint())},
{"PublicKey", toBase58(TokenType::NodePublic, publicKey)}}))
log::attr("NodeID", id),
log::attr("RemoteAddress", to_string(slot->remote_endpoint())),
log::attr("PublicKey", toBase58(TokenType::NodePublic, publicKey))))
, p_journal_(
app_.journal("Protocol"),
log::attributes(
{{"NodeID", id},
{"RemoteAddress", to_string(slot->remote_endpoint())},
{"PublicKey", toBase58(TokenType::NodePublic, publicKey)}}))
log::attr("NodeID", id),
log::attr("RemoteAddress", to_string(slot->remote_endpoint())),
log::attr("PublicKey", toBase58(TokenType::NodePublic, publicKey))))
, stream_ptr_(std::move(stream_ptr))
, socket_(stream_ptr_->next_layer().socket())
, stream_(*stream_ptr_)