Switch to yyjson

Signed-off-by: JCW <a1q123456@users.noreply.github.com>
This commit is contained in:
JCW
2025-08-29 15:00:58 +01:00
parent 52becffa48
commit 21a5260bb7
5 changed files with 359 additions and 156 deletions

View File

@@ -52,6 +52,7 @@ target_link_libraries(xrpl.libpb
add_library(xrpl.imports.main INTERFACE) add_library(xrpl.imports.main INTERFACE)
find_package(RapidJSON) find_package(RapidJSON)
find_package(yyjson)
target_link_libraries(xrpl.imports.main target_link_libraries(xrpl.imports.main
INTERFACE INTERFACE
@@ -77,7 +78,7 @@ add_module(xrpl beast)
target_link_libraries(xrpl.libxrpl.beast PUBLIC target_link_libraries(xrpl.libxrpl.beast PUBLIC
xrpl.imports.main xrpl.imports.main
xrpl.libpb xrpl.libpb
rapidjson yyjson::yyjson
) )
# Level 02 # Level 02

View File

@@ -30,7 +30,8 @@ class Xrpl(ConanFile):
'openssl/3.5.2', 'openssl/3.5.2',
'soci/4.0.3', 'soci/4.0.3',
'zlib/1.3.1', 'zlib/1.3.1',
"rapidjson/1.1.0" "rapidjson/1.1.0",
"yyjson/0.10.0"
] ]
test_requires = [ test_requires = [

View File

@@ -22,7 +22,9 @@
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <rapidjson/document.h> #include <boost/asio/execution/allocator.hpp>
#include <yyjson.h>
#include <deque> #include <deque>
#include <optional> #include <optional>
@@ -78,6 +80,19 @@ std::ostream&
operator<<(std::ostream& os, LogParameter<T> const& param); operator<<(std::ostream& os, LogParameter<T> const& param);
} // namespace ripple::log } // namespace ripple::log
namespace yyjson {
struct YYJsonDeleter
{
void
operator()(yyjson_mut_doc* doc)
{
yyjson_mut_doc_free(doc);
}
};
using YYJsonDocPtr = std::unique_ptr<yyjson_mut_doc, YYJsonDeleter>;
} // namespace yyjson
namespace beast { namespace beast {
/** A namespace for easy access to logging severity values. */ /** A namespace for easy access to logging severity values. */
@@ -129,18 +144,21 @@ public:
ripple::log::LogParameter<T> const& param); ripple::log::LogParameter<T> const& param);
class Sink; class Sink;
class JsonLogAttributes class JsonLogAttributes
{ {
public: public:
using AttributeFields = rapidjson::Value; using AttributeFields = yyjson::YYJsonDocPtr;
JsonLogAttributes(); JsonLogAttributes();
JsonLogAttributes(JsonLogAttributes const& other); JsonLogAttributes(JsonLogAttributes const& other);
JsonLogAttributes(JsonLogAttributes&& other);
JsonLogAttributes& JsonLogAttributes&
operator=(JsonLogAttributes const& other); operator=(JsonLogAttributes const& other);
JsonLogAttributes&
operator=(JsonLogAttributes&& other);
void void
setModuleName(std::string const& name); setModuleName(std::string const& name);
@@ -159,15 +177,8 @@ public:
return contextValues_; return contextValues_;
} }
rapidjson::MemoryPoolAllocator<>&
allocator()
{
return allocator_;
}
private: private:
AttributeFields contextValues_; AttributeFields contextValues_;
rapidjson::MemoryPoolAllocator<> allocator_;
friend class Journal; friend class Journal;
}; };
@@ -175,8 +186,7 @@ public:
struct JsonLogContext struct JsonLogContext
{ {
std::source_location location = {}; std::source_location location = {};
rapidjson::Value messageParams; yyjson::YYJsonDocPtr messageParams;
rapidjson::MemoryPoolAllocator<> allocator;
JsonLogContext() = default; JsonLogContext() = default;
@@ -184,9 +194,9 @@ public:
reset(std::source_location location_) noexcept reset(std::source_location location_) noexcept
{ {
location = location_; location = location_;
messageParams = rapidjson::Value{}; messageParams.reset(yyjson_mut_doc_new(nullptr));
messageParams.SetObject(); yyjson_mut_doc_set_root(
allocator.Clear(); messageParams.get(), yyjson_mut_obj(messageParams.get()));
} }
}; };
@@ -560,8 +570,6 @@ public:
Stream Stream
warn(std::source_location location = std::source_location::current()) const warn(std::source_location location = std::source_location::current()) const
{ {
char const* a = "a";
rapidjson::Value v{a, 1};
if (m_jsonLogsEnabled) if (m_jsonLogsEnabled)
initMessageContext(location); initMessageContext(location);
return {m_attributes, *m_sink, severities::kWarning}; return {m_attributes, *m_sink, severities::kWarning};
@@ -715,39 +723,225 @@ using logwstream = basic_logstream<wchar_t>;
namespace ripple::log { namespace ripple::log {
namespace detail { namespace detail {
inline void
setJsonField(
std::string const& name,
std::int8_t value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_sint(doc, value));
}
inline void
setJsonField(
std::string const& name,
std::uint8_t value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_uint(doc, value));
}
inline void
setJsonField(
std::string const& name,
std::int16_t value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_sint(doc, value));
}
inline void
setJsonField(
std::string const& name,
std::uint16_t value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_uint(doc, value));
}
inline void
setJsonField(
std::string const& name,
std::int32_t value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_sint(doc, value));
}
inline void
setJsonField(
std::string const& name,
std::uint32_t value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_uint(doc, value));
}
inline void
setJsonField(
std::string const& name,
std::int64_t value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_sint(doc, value));
}
inline void
setJsonField(
std::string const& name,
std::uint64_t value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_uint(doc, value));
}
inline void
setJsonField(
std::string const& name,
std::string const& value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_strncpy(doc, value.c_str(), value.length()));
}
inline void
setJsonField(
std::string const& name,
char const* value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_strcpy(doc, value));
}
inline void
setJsonField(
std::string const& name,
bool value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_bool(doc, value));
}
inline void
setJsonField(
std::string const& name,
float value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_real(doc, value));
}
inline void
setJsonField(
std::string const& name,
double value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_real(doc, value));
}
inline void
setJsonField(
std::string const& name,
std::nullptr_t,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_null(doc));
}
inline void
setJsonField(
std::string const& name,
yyjson_mut_val* value,
yyjson_mut_doc* doc,
yyjson_mut_val* obj)
{
yyjson_mut_obj_put(
obj,
yyjson_mut_strncpy(doc, name.c_str(), name.length()),
yyjson_mut_val_mut_copy(doc, value));
}
template <typename T>
concept CanSetJsonValue = requires(T val) {
setJsonField(
std::declval<std::string const&>(),
val,
std::declval<yyjson_mut_doc*>(),
std::declval<yyjson_mut_val*>());
};
template <typename T> template <typename T>
void void
setJsonValue( setJsonValue(
rapidjson::Value& object, yyjson::YYJsonDocPtr& object,
rapidjson::MemoryPoolAllocator<>& allocator,
char const* name, char const* name,
T&& value, T&& value,
std::ostream* outStream) std::ostream* outStream)
{ {
using ValueType = std::decay_t<T>; using ValueType = std::decay_t<T>;
rapidjson::Value jsonValue; auto root = yyjson_mut_doc_get_root(object.get());
if constexpr (std::constructible_from<
rapidjson::Value, if constexpr (CanSetJsonValue<ValueType>)
ValueType,
rapidjson::MemoryPoolAllocator<>&>)
{ {
jsonValue = rapidjson::Value{value, allocator}; setJsonField(name, std::forward<T>(value), object.get(), root);
if (outStream)
{
(*outStream) << value;
}
}
else if constexpr (std::constructible_from<rapidjson::Value, ValueType>)
{
jsonValue = rapidjson::Value{value};
if (outStream)
{
(*outStream) << value;
}
}
else if constexpr (std::same_as<ValueType, std::string>)
{
jsonValue = rapidjson::Value{value.c_str(), allocator};
if (outStream) if (outStream)
{ {
(*outStream) << value; (*outStream) << value;
@@ -758,16 +952,13 @@ setJsonValue(
std::ostringstream oss; std::ostringstream oss;
oss << value; oss << value;
jsonValue = rapidjson::Value{oss.str().c_str(), allocator}; setJsonField(name, oss.str(), object.get(), root);
if (outStream) if (outStream)
{ {
(*outStream) << oss.str(); (*outStream) << oss.str();
} }
} }
object.AddMember(
rapidjson::StringRef(name), std::move(jsonValue), allocator);
} }
} // namespace detail } // namespace detail
@@ -779,7 +970,6 @@ operator<<(std::ostream& os, LogParameter<T> const& param)
return os; return os;
detail::setJsonValue( detail::setJsonValue(
beast::Journal::currentJsonLogContext_.messageParams, beast::Journal::currentJsonLogContext_.messageParams,
beast::Journal::currentJsonLogContext_.allocator,
param.name_, param.name_,
param.value_, param.value_,
&os); &os);
@@ -794,7 +984,6 @@ operator<<(std::ostream& os, LogField<T> const& param)
return os; return os;
detail::setJsonValue( detail::setJsonValue(
beast::Journal::currentJsonLogContext_.messageParams, beast::Journal::currentJsonLogContext_.messageParams,
beast::Journal::currentJsonLogContext_.allocator,
param.name_, param.name_,
param.value_, param.value_,
nullptr); nullptr);
@@ -822,11 +1011,7 @@ attributes(Pair&&... pairs)
beast::Journal::JsonLogAttributes result; beast::Journal::JsonLogAttributes result;
(detail::setJsonValue( (detail::setJsonValue(
result.contextValues(), result.contextValues(), pairs.first, pairs.second, nullptr),
result.allocator(),
pairs.first,
pairs.second,
nullptr),
...); ...);
return result; return result;

View File

@@ -19,10 +19,6 @@
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <rapidjson/document.h>
#include <rapidjson/stringbuffer.h>
#include <rapidjson/writer.h>
#include <ios> #include <ios>
#include <ostream> #include <ostream>
#include <ranges> #include <ranges>
@@ -125,13 +121,20 @@ severities::to_string(Severity severity)
Journal::JsonLogAttributes::JsonLogAttributes() Journal::JsonLogAttributes::JsonLogAttributes()
{ {
contextValues_.SetObject(); contextValues_.reset(yyjson_mut_doc_new(nullptr));
yyjson_mut_doc_set_root(
contextValues_.get(), yyjson_mut_obj(contextValues_.get()));
} }
Journal::JsonLogAttributes::JsonLogAttributes(JsonLogAttributes const& other) Journal::JsonLogAttributes::JsonLogAttributes(JsonLogAttributes const& other)
{ {
contextValues_.SetObject(); contextValues_.reset(
contextValues_.CopyFrom(other.contextValues_, allocator_); yyjson_mut_doc_mut_copy(other.contextValues_.get(), nullptr));
}
Journal::JsonLogAttributes::JsonLogAttributes(JsonLogAttributes&& other)
{
contextValues_ = std::move(other.contextValues_);
} }
Journal::JsonLogAttributes& Journal::JsonLogAttributes&
@@ -141,17 +144,29 @@ Journal::JsonLogAttributes::operator=(JsonLogAttributes const& other)
{ {
return *this; return *this;
} }
contextValues_.CopyFrom(other.contextValues_, allocator_); contextValues_.reset(
yyjson_mut_doc_mut_copy(other.contextValues_.get(), nullptr));
return *this;
}
Journal::JsonLogAttributes&
Journal::JsonLogAttributes::operator=(JsonLogAttributes&& other)
{
if (&other == this)
{
return *this;
}
contextValues_ = std::move(other.contextValues_);
return *this; return *this;
} }
void void
Journal::JsonLogAttributes::setModuleName(std::string const& name) Journal::JsonLogAttributes::setModuleName(std::string const& name)
{ {
contextValues_.AddMember( auto root = yyjson_mut_doc_get_root(contextValues_.get());
rapidjson::StringRef("Module"), ripple::log::detail::setJsonField(
rapidjson::Value{name.c_str(), allocator_}, "Module", name, contextValues_.get(), root);
allocator_);
} }
Journal::JsonLogAttributes Journal::JsonLogAttributes
@@ -161,22 +176,23 @@ Journal::JsonLogAttributes::combine(
{ {
JsonLogAttributes result; JsonLogAttributes result;
result.contextValues_.CopyFrom(a, result.allocator_); result.contextValues_.reset(yyjson_mut_doc_mut_copy(a.get(), nullptr));
for (auto& member : b.GetObject()) auto bRoot = yyjson_mut_doc_get_root(b.get());
auto root = yyjson_mut_doc_get_root(result.contextValues_.get());
for (auto iter = yyjson_mut_obj_iter_with(bRoot);
yyjson_mut_obj_iter_has_next(&iter);
yyjson_mut_obj_iter_next(&iter))
{ {
auto val = rapidjson::Value{member.value, result.allocator_}; auto key = iter.cur;
if (result.contextValues_.HasMember(member.name)) auto val = yyjson_mut_obj_iter_get_val(key);
{
result.contextValues_[member.name] = std::move(val); auto keyCopied =
} yyjson_mut_val_mut_copy(result.contextValues_.get(), key);
else auto valueCopied =
{ yyjson_mut_val_mut_copy(result.contextValues_.get(), val);
result.contextValues_.AddMember(
rapidjson::Value{member.name, result.allocator_}, yyjson_mut_obj_put(root, keyCopied, valueCopied);
std::move(val),
result.allocator_);
}
} }
return result; return result;
@@ -199,92 +215,89 @@ Journal::formatLog(
return message; return message;
} }
rapidjson::Document doc{&currentJsonLogContext_.allocator}; yyjson::YYJsonDocPtr doc{yyjson_mut_doc_new(nullptr)};
rapidjson::Value logContext; auto logContext = yyjson_mut_obj(doc.get());
logContext.SetObject(); yyjson_mut_doc_set_root(doc.get(), logContext);
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);
if (attributes.has_value())
{
for (auto const& [key, value] : attributes->contextValues().GetObject())
{
if (logContext.HasMember(key))
continue;
rapidjson::Value jsonValue;
jsonValue.CopyFrom(value, currentJsonLogContext_.allocator);
logContext.AddMember(
rapidjson::Value{key, currentJsonLogContext_.allocator},
std::move(jsonValue),
currentJsonLogContext_.allocator);
}
}
if (globalLogAttributes_) if (globalLogAttributes_)
{ {
for (auto const& [key, value] : auto root = yyjson_mut_doc_get_root(
globalLogAttributes_->contextValues().GetObject()) globalLogAttributes_->contextValues().get());
for (auto iter = yyjson_mut_obj_iter_with(root);
yyjson_mut_obj_iter_has_next(&iter);
yyjson_mut_obj_iter_next(&iter))
{ {
if (logContext.HasMember(key)) auto key = iter.cur;
continue; auto val = yyjson_mut_obj_iter_get_val(key);
rapidjson::Value jsonValue;
jsonValue.CopyFrom(value, currentJsonLogContext_.allocator);
logContext.AddMember( auto keyCopied = yyjson_mut_val_mut_copy(doc.get(), key);
rapidjson::Value{key, currentJsonLogContext_.allocator}, auto valueCopied = yyjson_mut_val_mut_copy(doc.get(), val);
std::move(jsonValue),
currentJsonLogContext_.allocator); yyjson_mut_obj_put(logContext, keyCopied, valueCopied);
} }
} }
rapidjson::StringBuffer buffer; if (attributes.has_value())
rapidjson::Writer writer(buffer); {
auto root = yyjson_mut_doc_get_root(attributes->contextValues().get());
for (auto iter = yyjson_mut_obj_iter_with(root);
yyjson_mut_obj_iter_has_next(&iter);
yyjson_mut_obj_iter_next(&iter))
{
auto key = iter.cur;
auto val = yyjson_mut_obj_iter_get_val(key);
logContext.Accept(writer); auto keyCopied = yyjson_mut_val_mut_copy(doc.get(), key);
auto valueCopied = yyjson_mut_val_mut_copy(doc.get(), val);
return {buffer.GetString()}; yyjson_mut_obj_put(logContext, keyCopied, valueCopied);
}
}
ripple::log::detail::setJsonField(
"Function",
currentJsonLogContext_.location.function_name(),
doc.get(),
logContext);
ripple::log::detail::setJsonField(
"File",
currentJsonLogContext_.location.file_name(),
doc.get(),
logContext);
ripple::log::detail::setJsonField(
"Line",
static_cast<std::uint64_t>(currentJsonLogContext_.location.line()),
doc.get(),
logContext);
std::stringstream threadIdStream;
threadIdStream << std::this_thread::get_id();
auto threadIdStr = threadIdStream.str();
auto messageParamsRoot =
yyjson_mut_doc_get_root(currentJsonLogContext_.messageParams.get());
ripple::log::detail::setJsonField(
"ThreadId", threadIdStr, doc.get(), logContext);
ripple::log::detail::setJsonField(
"Params", messageParamsRoot, doc.get(), logContext);
yyjson_mut_doc_set_root(
currentJsonLogContext_.messageParams.get(), nullptr);
auto severityStr = to_string(severity);
ripple::log::detail::setJsonField(
"Level", severityStr, doc.get(), logContext);
ripple::log::detail::setJsonField(
"Message", message, doc.get(), logContext);
ripple::log::detail::setJsonField(
"Time",
std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count(),
doc.get(),
logContext);
std::string result = yyjson_mut_write(doc.get(), 0, nullptr);
return result;
} }
void void

View File

@@ -195,6 +195,7 @@ TEST_CASE("Global attributes inheritable")
CHECK(jsonLog.IsObject()); CHECK(jsonLog.IsObject());
CHECK(jsonLog.HasMember("Field1")); CHECK(jsonLog.HasMember("Field1"));
CHECK(jsonLog.HasMember("Field2"));
CHECK(jsonLog["Field1"].IsString()); CHECK(jsonLog["Field1"].IsString());
// Field1 should be overwritten to Value3 // Field1 should be overwritten to Value3
CHECK(jsonLog["Field1"].GetString() == std::string{"Value3"}); CHECK(jsonLog["Field1"].GetString() == std::string{"Value3"});
@@ -412,6 +413,8 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogParams")
"Field2", "Field2",
std::numeric_limits<std::uint64_t>::max()); std::numeric_limits<std::uint64_t>::max());
auto test = stream().str();
rapidjson::Document logValue; rapidjson::Document logValue;
logValue.Parse(stream().str().c_str()); logValue.Parse(stream().str().c_str());