Signed-off-by: JCW <a1q123456@users.noreply.github.com>
This commit is contained in:
JCW
2025-09-02 17:22:53 +01:00
parent f50f76788b
commit 1d3d0c6774
6 changed files with 263 additions and 252 deletions

View File

@@ -51,8 +51,6 @@ target_link_libraries(xrpl.libpb
# TODO: Clean up the number of library targets later. # TODO: Clean up the number of library targets later.
add_library(xrpl.imports.main INTERFACE) add_library(xrpl.imports.main INTERFACE)
find_package(RapidJSON)
target_link_libraries(xrpl.imports.main target_link_libraries(xrpl.imports.main
INTERFACE INTERFACE
LibArchive::LibArchive LibArchive::LibArchive
@@ -77,7 +75,6 @@ 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
) )
# Level 02 # Level 02

View File

@@ -29,8 +29,7 @@ class Xrpl(ConanFile):
'nudb/2.0.9', 'nudb/2.0.9',
'openssl/1.1.1w', 'openssl/1.1.1w',
'soci/4.0.3', 'soci/4.0.3',
'zlib/1.3.1', 'zlib/1.3.1'
"rapidjson/1.1.0"
] ]
test_requires = [ test_requires = [

View File

@@ -23,9 +23,10 @@
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <charconv> #include <charconv>
#include <string>
#include <source_location> #include <source_location>
#include <sstream> #include <sstream>
#include <string>
#include <string_view>
#include <utility> #include <utility>
namespace ripple::log { namespace ripple::log {
@@ -88,37 +89,45 @@ public:
void void
startObject() const startObject() const
{ {
stream_.append("{", 1); stream_.push_back('{');
} }
void void
endObject() const endObject() const
{ {
using namespace std::string_view_literals;
stream_.pop_back(); stream_.pop_back();
stream_.append("},", 2); stream_.append("},"sv);
} }
void void
writeKey(std::string_view key) const writeKey(std::string_view key) const
{ {
writeString(key); writeString(key);
*stream_.rbegin() = ':'; stream_.back() = ':';
} }
void void
startArray() const startArray() const
{ {
stream_.append("[", 1); stream_.push_back('[');
} }
void void
endArray() const endArray() const
{ {
using namespace std::string_view_literals;
stream_.pop_back(); stream_.pop_back();
stream_.append("],", 2); stream_.append("],"sv);
} }
void void
writeString(std::string_view str) const writeString(std::string_view str) const
{ {
using namespace std::string_view_literals;
stream_.push_back('"'); stream_.push_back('"');
escape(str, stream_); escape(str, stream_);
stream_.append("\",", 2); stream_.append("\","sv);
}
std::string_view
writeInt(std::int32_t val) const
{
return pushNumber(val, stream_);
} }
std::string_view std::string_view
writeInt(std::int64_t val) const writeInt(std::int64_t val) const
@@ -126,6 +135,11 @@ public:
return pushNumber(val, stream_); return pushNumber(val, stream_);
} }
std::string_view std::string_view
writeUInt(std::uint32_t val) const
{
return pushNumber(val, stream_);
}
std::string_view
writeUInt(std::uint64_t val) const writeUInt(std::uint64_t val) const
{ {
return pushNumber(val, stream_); return pushNumber(val, stream_);
@@ -138,15 +152,16 @@ public:
std::string_view std::string_view
writeBool(bool val) const writeBool(bool val) const
{ {
auto str = val ? "true," : "false,"; using namespace std::string_view_literals;
stream_.append(str, std::strlen(str)); auto str = val ? "true,"sv : "false,"sv;
stream_.append(str);
return str; return str;
} }
void void
writeNull() const writeNull() const
{ {
stream_.append("null", std::strlen("null")); using namespace std::string_view_literals;
stream_.push_back(','); stream_.append("null,"sv);
} }
void void
writeRaw(std::string_view str) const writeRaw(std::string_view str) const
@@ -154,11 +169,10 @@ public:
stream_.append(str); stream_.append(str);
} }
[[nodiscard]] std::string [[nodiscard]] std::string_view
finish() finish()
{ {
stream_.pop_back(); return std::string_view{stream_.c_str(), stream_.size() - 1};
return stream_;
} }
private: private:
@@ -166,10 +180,11 @@ private:
static std::string_view static std::string_view
pushNumber(T val, std::string& stream) pushNumber(T val, std::string& stream)
{ {
static char buffer[128]; thread_local char buffer[128];
auto result = std::to_chars(std::begin(buffer), std::end(buffer), val); auto result = std::to_chars(std::begin(buffer), std::end(buffer), val);
*result.ptr = ','; auto ptr = result.ptr;
auto len = result.ptr - std::begin(buffer); *ptr = ',';
auto len = ptr - std::begin(buffer);
stream.append(buffer, len + 1); stream.append(buffer, len + 1);
return {buffer, static_cast<size_t>(len)}; return {buffer, static_cast<size_t>(len)};
} }
@@ -179,17 +194,19 @@ private:
{ {
static constexpr char HEX[] = "0123456789ABCDEF"; static constexpr char HEX[] = "0123456789ABCDEF";
const char* p = str.data(); char const* p = str.data();
const char* end = p + str.size(); char const* end = p + str.size();
const char* chunk = p; char const* chunk = p;
while (p < end) { while (p < end)
{
auto c = static_cast<unsigned char>(*p); auto c = static_cast<unsigned char>(*p);
// JSON requires escaping for <0x20 and the two specials below. // JSON requires escaping for <0x20 and the two specials below.
bool needsEscape = (c < 0x20) || (c == '"') || (c == '\\'); bool needsEscape = (c < 0x20) || (c == '"') || (c == '\\');
if (!needsEscape) { if (!needsEscape)
{
++p; ++p;
continue; continue;
} }
@@ -198,21 +215,33 @@ private:
if (chunk != p) if (chunk != p)
os.append(chunk, p - chunk); os.append(chunk, p - chunk);
switch (c) { switch (c)
case '"': os.append("\\\"", 2); break; {
case '\\': os.append("\\\\", 2); break; case '"':
case '\b': os.append("\\b", 2); break; os.append("\\\"", 2);
case '\f': os.append("\\f", 2); break; break;
case '\n': os.append("\\n", 2); break; case '\\':
case '\r': os.append("\\r", 2); break; os.append("\\\\", 2);
case '\t': os.append("\\t", 2); break; break;
case '\b':
os.append("\\b", 2);
break;
case '\f':
os.append("\\f", 2);
break;
case '\n':
os.append("\\n", 2);
break;
case '\r':
os.append("\\r", 2);
break;
case '\t':
os.append("\\t", 2);
break;
default: { default: {
// Other C0 controls -> \u00XX (JSON compliant) // Other C0 controls -> \u00XX (JSON compliant)
char buf[6]{ char buf[6]{
'\\','u','0','0', '\\', 'u', '0', '0', HEX[(c >> 4) & 0xF], HEX[c & 0xF]};
HEX[(c >> 4) & 0xF],
HEX[c & 0xF]
};
os.append(buf, 6); os.append(buf, 6);
break; break;
} }
@@ -288,6 +317,7 @@ public:
public: public:
JsonLogContext() : messageParamsWriter_(buffer_) JsonLogContext() : messageParamsWriter_(buffer_)
{ {
buffer_.reserve(1024 * 5);
} }
SimpleJsonWriter& SimpleJsonWriter&
@@ -300,7 +330,7 @@ public:
reset( reset(
std::source_location location, std::source_location location,
severities::Severity severity, severities::Severity severity,
std::string const& journalAttributesJson) noexcept; std::string_view journalAttributesJson) noexcept;
}; };
private: private:
@@ -323,7 +353,7 @@ private:
std::source_location location, std::source_location location,
severities::Severity severity) const; severities::Severity severity) const;
static std::string static std::string_view
formatLog(std::string&& message); formatLog(std::string&& message);
public: public:
@@ -830,9 +860,10 @@ namespace ripple::log {
namespace detail { namespace detail {
template <typename T> template <typename T>
concept CanToChars = requires (T val) concept CanToChars = requires(T val) {
{ {
{ to_chars(std::declval<char*>(), std::declval<char*>(), val) } -> std::convertible_to<std::to_chars_result>; to_chars(std::declval<char*>(), std::declval<char*>(), val)
} -> std::convertible_to<std::to_chars_result>;
}; };
template <typename T> template <typename T>
@@ -901,7 +932,8 @@ setJsonValue(
if constexpr (CanToChars<ValueType>) if constexpr (CanToChars<ValueType>)
{ {
char buffer[1024]; char buffer[1024];
std::to_chars_result result = to_chars(std::begin(buffer), std::end(buffer), value); std::to_chars_result result =
to_chars(std::begin(buffer), std::end(buffer), value);
if (result.ec == std::errc{}) if (result.ec == std::errc{})
{ {
std::string_view sv; std::string_view sv;
@@ -925,7 +957,8 @@ setJsonValue(
if (outStream) if (outStream)
{ {
outStream->write(str.c_str(), static_cast<std::streamsize>(str.size())); outStream->write(
str.c_str(), static_cast<std::streamsize>(str.size()));
} }
} }
} }

View File

@@ -123,7 +123,7 @@ void
Journal::JsonLogContext::reset( Journal::JsonLogContext::reset(
std::source_location location, std::source_location location,
severities::Severity severity, severities::Severity severity,
std::string const& journalAttributesJson) noexcept std::string_view journalAttributesJson) noexcept
{ {
struct ThreadIdStringInitializer struct ThreadIdStringInitializer
{ {
@@ -152,7 +152,9 @@ Journal::JsonLogContext::reset(
if (!globalLogAttributesJson_.empty()) if (!globalLogAttributesJson_.empty())
{ {
writer().writeKey("GlobalParams"); writer().writeKey("GlobalParams");
writer().writeRaw(globalLogAttributesJson_); writer().writeRaw(std::string_view{
std::begin(globalLogAttributesJson_),
std::end(globalLogAttributesJson_)});
writer().endObject(); writer().endObject();
} }
@@ -166,7 +168,7 @@ Journal::JsonLogContext::reset(
writer().writeString(location.file_name()); writer().writeString(location.file_name());
writer().writeKey("Line"); writer().writeKey("Line");
writer().writeInt(location.line()); writer().writeInt(static_cast<std::int32_t>(location.line()));
writer().writeKey("ThreadId"); writer().writeKey("ThreadId");
writer().writeString(threadId.value); writer().writeString(threadId.value);
@@ -176,9 +178,9 @@ Journal::JsonLogContext::reset(
writer().writeString(severityStr); writer().writeString(severityStr);
writer().writeKey("Time"); writer().writeKey("Time");
writer().writeUInt(std::chrono::duration_cast<std::chrono::milliseconds>( writer().writeInt(std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()) std::chrono::system_clock::now().time_since_epoch())
.count()); .count());
} }
void void
@@ -186,10 +188,14 @@ Journal::initMessageContext(
std::source_location location, std::source_location location,
severities::Severity severity) const severities::Severity severity) const
{ {
currentJsonLogContext_.reset(location, severity, m_attributesJson); currentJsonLogContext_.reset(
location,
severity,
std::string_view{
std::begin(m_attributesJson), std::end(m_attributesJson)});
} }
std::string std::string_view
Journal::formatLog(std::string&& message) Journal::formatLog(std::string&& message)
{ {
if (!m_jsonLogsEnabled) if (!m_jsonLogsEnabled)
@@ -288,9 +294,9 @@ Journal::ScopedStream::~ScopedStream()
if (!s.empty()) if (!s.empty())
{ {
if (s == "\n") if (s == "\n")
m_sink.write(m_level, formatLog("")); m_sink.write(m_level, std::string{formatLog("")});
else else
m_sink.write(m_level, formatLog(std::move(s))); m_sink.write(m_level, std::string{formatLog(std::move(s))});
} }
} }

View File

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

View File

@@ -20,7 +20,10 @@
#include <xrpl/basics/Log.h> #include <xrpl/basics/Log.h>
#include <doctest/doctest.h> #include <doctest/doctest.h>
#include <rapidjson/document.h> #include <boost/json.hpp>
#include <numbers>
#include <iostream>
using namespace ripple; using namespace ripple;
@@ -51,21 +54,21 @@ private:
void void
write(beast::severities::Severity level, std::string&& text) override write(beast::severities::Severity level, std::string&& text) override
{ {
logs_.logStream_ << text; logs_.write(level, partition_, text, false);
} }
void void
writeAlways(beast::severities::Severity level, std::string&& text) writeAlways(beast::severities::Severity level, std::string&& text)
override override
{ {
logs_.logStream_ << text; logs_.write(level, partition_, text, false);
} }
}; };
std::stringstream& logStream_; std::string& logStream_;
public: public:
MockLogs(std::stringstream& logStream, beast::severities::Severity level) MockLogs(std::string& logStream, beast::severities::Severity level)
: Logs(level), logStream_(logStream) : Logs(level), logStream_(logStream)
{ {
} }
@@ -77,23 +80,35 @@ public:
{ {
return std::make_unique<Sink>(partition, startingLevel, *this); return std::make_unique<Sink>(partition, startingLevel, *this);
} }
void
write(
beast::severities::Severity level,
std::string const& partition,
std::string const& text,
bool console)
{
std::string s;
format(s, text, level, partition);
logStream_.append(s);
}
}; };
TEST_CASE("Text logs") TEST_CASE("Text logs")
{ {
std::stringstream logStream; std::string logStream;
MockLogs logs{logStream, beast::severities::kAll}; MockLogs logs{logStream, beast::severities::kAll};
logs.journal("Test").debug() << "Test"; logs.journal("Test").debug() << "Test";
CHECK(logStream.str().find("Test") != std::string::npos); CHECK(logStream.find("Test") != std::string::npos);
logStream.str(""); logStream.clear();
logs.journal("Test").debug() << "\n"; logs.journal("Test").debug() << "\n";
CHECK(logStream.str().find("\n") == std::string::npos); CHECK(logStream.find("\n") == std::string::npos);
} }
TEST_CASE("Test format output") TEST_CASE("Test format output")
@@ -118,35 +133,34 @@ TEST_CASE("Test format output when structured logs are enabled")
TEST_CASE("Enable json logs") TEST_CASE("Enable json logs")
{ {
std::stringstream logStream; std::string logStream;
MockLogs logs{logStream, beast::severities::kAll}; MockLogs logs{logStream, beast::severities::kAll};
logs.journal("Test").debug() << "Test"; logs.journal("Test ").debug() << "Test123";
CHECK(logStream.str() == "Test"); CHECK(logStream.find("Test123") != std::string::npos);
logStream.str(""); logStream.clear();
beast::Journal::enableStructuredJournal(); beast::Journal::enableStructuredJournal();
logs.journal("Test").debug() << "\n"; logs.journal("Test").debug() << "\n";
rapidjson::Document doc; boost::system::error_code ec;
doc.Parse(logStream.str().c_str()); auto doc = boost::json::parse(logStream, ec);
CHECK(ec == boost::system::errc::success);
CHECK(doc.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); CHECK(doc.is_object());
CHECK(doc.as_object().contains("Message"));
CHECK(doc.IsObject()); CHECK(doc.as_object()["Message"].is_string());
CHECK(doc.HasMember("Message")); CHECK(doc.as_object()["Message"].get_string() == "");
CHECK(doc["Message"].IsString());
CHECK(doc["Message"].GetString() == std::string{""});
beast::Journal::disableStructuredJournal(); beast::Journal::disableStructuredJournal();
} }
TEST_CASE("Global attributes") TEST_CASE("Global attributes")
{ {
std::stringstream logStream; std::string logStream;
MockLogs logs{logStream, beast::severities::kAll}; MockLogs logs{logStream, beast::severities::kAll};
@@ -156,25 +170,23 @@ TEST_CASE("Global attributes")
logs.journal("Test").debug() << "Test"; logs.journal("Test").debug() << "Test";
rapidjson::Document jsonLog; boost::system::error_code ec;
jsonLog.Parse(logStream.str().c_str()); auto jsonLog = boost::json::parse(logStream, ec);
CHECK(ec == boost::system::errc::success);
CHECK(jsonLog.is_object());
CHECK(jsonLog.as_object().contains("GlobalParams"));
CHECK(jsonLog.as_object()["GlobalParams"].is_object());
CHECK(jsonLog.as_object()["GlobalParams"].as_object().contains("Field1"));
CHECK(jsonLog.as_object()["GlobalParams"].as_object()["Field1"].is_string());
CHECK( CHECK(
jsonLog.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); jsonLog.as_object()["GlobalParams"].as_object()["Field1"].get_string() == "Value1");
CHECK(jsonLog.IsObject());
CHECK(jsonLog.HasMember("GlobalParams"));
CHECK(jsonLog["GlobalParams"].IsObject());
CHECK(jsonLog["GlobalParams"].HasMember("Field1"));
CHECK(jsonLog["GlobalParams"]["Field1"].IsString());
CHECK(
jsonLog["GlobalParams"]["Field1"].GetString() == std::string{"Value1"});
beast::Journal::disableStructuredJournal(); beast::Journal::disableStructuredJournal();
} }
TEST_CASE("Global attributes inheritable") TEST_CASE("Global attributes inheritable")
{ {
std::stringstream logStream; std::string logStream;
MockLogs logs{logStream, beast::severities::kAll}; MockLogs logs{logStream, beast::severities::kAll};
@@ -189,23 +201,19 @@ TEST_CASE("Global attributes inheritable")
.debug() .debug()
<< "Test"; << "Test";
rapidjson::Document jsonLog; boost::system::error_code ec;
jsonLog.Parse(logStream.str().c_str()); auto jsonLog = boost::json::parse(logStream, ec);
CHECK(ec == boost::system::errc::success);
CHECK(jsonLog.is_object());
CHECK(jsonLog.as_object()["GlobalParams"].as_object().contains("Field1"));
CHECK(jsonLog.as_object()["GlobalParams"].as_object()["Field1"].is_string());
CHECK( CHECK(
jsonLog.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); jsonLog.as_object()["GlobalParams"].as_object()["Field1"].get_string() == "Value1");
CHECK(jsonLog.IsObject());
CHECK(jsonLog["GlobalParams"].HasMember("Field1"));
CHECK(jsonLog["GlobalParams"]["Field1"].IsString());
CHECK( CHECK(
jsonLog["GlobalParams"]["Field1"].GetString() == std::string{"Value1"}); jsonLog.as_object()["JournalParams"].as_object()["Field1"].get_string() == "Value3");
CHECK( CHECK(
jsonLog["JournalParams"]["Field1"].GetString() == jsonLog.as_object()["JournalParams"].as_object()["Field2"].get_string() == "Value2");
std::string{"Value3"});
CHECK(
jsonLog["JournalParams"]["Field2"].GetString() ==
std::string{"Value2"});
beast::Journal::disableStructuredJournal(); beast::Journal::disableStructuredJournal();
} }
@@ -311,35 +319,33 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogFields")
<< std::boolalpha << false << std::boolalpha << false
<< log::field("Field3", "Value3"); << log::field("Field3", "Value3");
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK( CHECK(logValue.is_object());
logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); CHECK(logValue.as_object().contains("GlobalParams"));
CHECK(logValue.as_object().contains("JournalParams"));
CHECK(logValue.as_object().contains("MessageParams"));
CHECK(logValue.as_object().contains("Message"));
CHECK(logValue.IsObject()); CHECK(logValue.as_object()["GlobalParams"].is_object());
CHECK(logValue.HasMember("GlobalParams")); CHECK(logValue.as_object()["JournalParams"].is_object());
CHECK(logValue.HasMember("JournalParams")); CHECK(logValue.as_object()["MessageParams"].is_object());
CHECK(logValue.HasMember("MessageParams")); CHECK(logValue.as_object()["Message"].is_string());
CHECK(logValue.HasMember("Message"));
CHECK(logValue["GlobalParams"].IsObject()); CHECK(logValue.as_object()["MessageParams"].as_object().contains("Function"));
CHECK(logValue["JournalParams"].IsObject()); CHECK(logValue.as_object()["MessageParams"].as_object().contains("File"));
CHECK(logValue["MessageParams"].IsObject()); CHECK(logValue.as_object()["MessageParams"].as_object().contains("Line"));
CHECK(logValue["Message"].IsString()); CHECK(logValue.as_object()["MessageParams"].as_object().contains("ThreadId"));
CHECK(logValue.as_object()["MessageParams"].as_object().contains("Level"));
CHECK(logValue.as_object()["MessageParams"].as_object().contains("Time"));
CHECK(logValue["MessageParams"].HasMember("Function")); CHECK(logValue.as_object()["MessageParams"].as_object()["Function"].is_string());
CHECK(logValue["MessageParams"].HasMember("File")); CHECK(logValue.as_object()["MessageParams"].as_object()["File"].is_string());
CHECK(logValue["MessageParams"].HasMember("Line")); CHECK(logValue.as_object()["MessageParams"].as_object()["Line"].is_number());
CHECK(logValue["MessageParams"].HasMember("ThreadId"));
CHECK(logValue["MessageParams"].HasMember("Level"));
CHECK(logValue["MessageParams"].HasMember("Time"));
CHECK(logValue["MessageParams"]["Function"].IsString()); CHECK(logValue.as_object()["Message"].get_string() == std::string{"true Test false"});
CHECK(logValue["MessageParams"]["File"].IsString());
CHECK(logValue["MessageParams"]["Line"].IsNumber());
CHECK(logValue["Message"].GetString() == std::string{"true Test false"});
} }
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogLevels") TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogLevels")
@@ -348,15 +354,12 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogLevels")
stream().str(""); stream().str("");
journal().trace() << "Test"; journal().trace() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK( CHECK(
logValue.GetParseError() == logValue.as_object()["MessageParams"].as_object()["Level"].get_string() ==
rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["MessageParams"]["Level"].GetString() ==
beast::severities::to_string(beast::severities::kTrace)); beast::severities::to_string(beast::severities::kTrace));
} }
@@ -364,15 +367,12 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogLevels")
stream().str(""); stream().str("");
journal().debug() << "Test"; journal().debug() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK( CHECK(
logValue.GetParseError() == logValue.as_object()["MessageParams"].as_object()["Level"].get_string() ==
rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["MessageParams"]["Level"].GetString() ==
beast::severities::to_string(beast::severities::kDebug)); beast::severities::to_string(beast::severities::kDebug));
} }
@@ -380,15 +380,12 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogLevels")
stream().str(""); stream().str("");
journal().info() << "Test"; journal().info() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK( CHECK(
logValue.GetParseError() == logValue.as_object()["MessageParams"].as_object()["Level"].get_string() ==
rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["MessageParams"]["Level"].GetString() ==
beast::severities::to_string(beast::severities::kInfo)); beast::severities::to_string(beast::severities::kInfo));
} }
@@ -396,15 +393,12 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogLevels")
stream().str(""); stream().str("");
journal().warn() << "Test"; journal().warn() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK( CHECK(
logValue.GetParseError() == logValue.as_object()["MessageParams"].as_object()["Level"].get_string() ==
rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["MessageParams"]["Level"].GetString() ==
beast::severities::to_string(beast::severities::kWarning)); beast::severities::to_string(beast::severities::kWarning));
} }
@@ -412,15 +406,12 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogLevels")
stream().str(""); stream().str("");
journal().error() << "Test"; journal().error() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK( CHECK(
logValue.GetParseError() == logValue.as_object()["MessageParams"].as_object()["Level"].get_string() ==
rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["MessageParams"]["Level"].GetString() ==
beast::severities::to_string(beast::severities::kError)); beast::severities::to_string(beast::severities::kError));
} }
@@ -428,15 +419,12 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogLevels")
stream().str(""); stream().str("");
journal().fatal() << "Test"; journal().fatal() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK( CHECK(
logValue.GetParseError() == logValue.as_object()["MessageParams"].as_object()["Level"].get_string() ==
rapidjson::ParseErrorCode::kParseErrorNone);
CHECK(
logValue["MessageParams"]["Level"].GetString() ==
beast::severities::to_string(beast::severities::kFatal)); beast::severities::to_string(beast::severities::kFatal));
} }
} }
@@ -445,14 +433,12 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogStream")
{ {
journal().stream(beast::severities::kError) << "Test"; journal().stream(beast::severities::kError) << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK( CHECK(
logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); logValue.as_object()["MessageParams"].as_object()["Level"].get_string() ==
CHECK(
logValue["MessageParams"]["Level"].GetString() ==
beast::severities::to_string(beast::severities::kError)); beast::severities::to_string(beast::severities::kError));
} }
@@ -461,25 +447,28 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogParams")
journal().debug() << "Test: " << log::param("Field1", 1) << ", " journal().debug() << "Test: " << log::param("Field1", 1) << ", "
<< log::param( << log::param(
"Field2", "Field2",
std::numeric_limits<std::uint64_t>::max()); std::numeric_limits<std::uint64_t>::max())
<< ", "
<< log::param("Field3", std::numbers::pi);
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["MessageParams"].is_object());
CHECK(logValue.as_object()["MessageParams"].as_object()["Field1"].is_number());
CHECK(logValue.as_object()["MessageParams"].as_object()["Field1"].get_int64() == 1);
CHECK(logValue.as_object()["MessageParams"].as_object()["Field2"].is_number());
CHECK( CHECK(
logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); logValue.as_object()["MessageParams"].as_object()["Field2"].get_uint64() ==
CHECK(logValue["MessageParams"].IsObject());
CHECK(logValue["MessageParams"]["Field1"].IsNumber());
CHECK(logValue["MessageParams"]["Field1"].GetInt() == 1);
CHECK(logValue["MessageParams"]["Field2"].IsNumber());
CHECK(
logValue["MessageParams"]["Field2"].GetUint64() ==
std::numeric_limits<std::uint64_t>::max()); std::numeric_limits<std::uint64_t>::max());
CHECK(logValue["Message"].IsString());
CHECK( CHECK(
logValue["Message"].GetString() == logValue.as_object()["MessageParams"].as_object()["Field3"].get_double() ==
std::string{"Test: 1, 18446744073709551615"}); 3.141593);
CHECK(logValue.as_object()["Message"].is_string());
CHECK(
logValue.as_object()["Message"].get_string() ==
std::string{"Test: 1, 18446744073709551615, 3.141593"});
} }
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogFields") TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogFields")
@@ -489,24 +478,22 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJsonLogFields")
"Field2", "Field2",
std::numeric_limits<std::uint64_t>::max()); std::numeric_limits<std::uint64_t>::max());
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK( CHECK(logValue.as_object()["MessageParams"].is_object());
logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); CHECK(logValue.as_object()["MessageParams"].as_object()["Field1"].is_number());
CHECK(logValue.as_object()["MessageParams"].as_object()["Field1"].get_int64() == 1);
CHECK(logValue["MessageParams"].IsObject());
CHECK(logValue["MessageParams"]["Field1"].IsNumber());
CHECK(logValue["MessageParams"]["Field1"].GetInt() == 1);
// UInt64 doesn't fit in Json::Value so it should be converted to a string // 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 // NOTE: We should expect it to be an int64 after we make the json library
// support in64 and uint64 // support in64 and uint64
CHECK(logValue["MessageParams"]["Field2"].IsNumber()); CHECK(logValue.as_object()["MessageParams"].as_object()["Field2"].is_number());
CHECK( CHECK(
logValue["MessageParams"]["Field2"].GetUint64() == logValue.as_object()["MessageParams"].as_object()["Field2"].get_uint64() ==
std::numeric_limits<std::uint64_t>::max()); std::numeric_limits<std::uint64_t>::max());
CHECK(logValue["Message"].IsString()); CHECK(logValue.as_object()["Message"].is_string());
CHECK(logValue["Message"].GetString() == std::string{"Test"}); CHECK(logValue.as_object()["Message"].get_string() == "Test");
} }
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJournalAttributes") TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJournalAttributes")
@@ -517,18 +504,16 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJournalAttributes")
j.debug() << "Test"; j.debug() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["JournalParams"].as_object()["Field1"].is_string());
CHECK( CHECK(
logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); logValue.as_object()["JournalParams"].as_object()["Field1"].get_string() ==
CHECK(logValue["JournalParams"]["Field1"].IsString());
CHECK(
logValue["JournalParams"]["Field1"].GetString() ==
std::string{"Value1"}); std::string{"Value1"});
CHECK(logValue["JournalParams"]["Field2"].IsNumber()); CHECK(logValue.as_object()["JournalParams"].as_object()["Field2"].is_number());
CHECK(logValue["JournalParams"]["Field2"].GetInt() == 2); CHECK(logValue.as_object()["JournalParams"].as_object()["Field2"].get_int64() == 2);
} }
TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJournalAttributesInheritable") TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJournalAttributesInheritable")
@@ -540,22 +525,20 @@ TEST_CASE_FIXTURE(JsonLogStreamFixture, "TestJournalAttributesInheritable")
j2.debug() << "Test"; j2.debug() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["JournalParams"].as_object()["Field1"].is_string());
CHECK( CHECK(
logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); logValue.as_object()["JournalParams"].as_object()["Field1"].get_string() ==
CHECK(logValue["JournalParams"]["Field1"].IsString());
CHECK(
logValue["JournalParams"]["Field1"].GetString() ==
std::string{"Value1"}); std::string{"Value1"});
CHECK(logValue["JournalParams"]["Field3"].IsString()); CHECK(logValue.as_object()["JournalParams"].as_object()["Field3"].is_string());
CHECK( CHECK(
logValue["JournalParams"]["Field3"].GetString() == logValue.as_object()["JournalParams"].as_object()["Field3"].get_string() ==
std::string{"Value3"}); std::string{"Value3"});
CHECK(logValue["JournalParams"]["Field2"].IsNumber()); CHECK(logValue.as_object()["JournalParams"].as_object()["Field2"].is_number());
CHECK(logValue["JournalParams"]["Field2"].GetInt() == 2); CHECK(logValue.as_object()["JournalParams"].as_object()["Field2"].get_int64() == 2);
} }
TEST_CASE_FIXTURE( TEST_CASE_FIXTURE(
@@ -569,23 +552,21 @@ TEST_CASE_FIXTURE(
j2.debug() << "Test"; j2.debug() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["JournalParams"].as_object()["Field1"].is_string());
CHECK( CHECK(
logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); logValue.as_object()["JournalParams"].as_object()["Field1"].get_string() ==
CHECK(logValue["JournalParams"]["Field1"].IsString());
CHECK(
logValue["JournalParams"]["Field1"].GetString() ==
std::string{"Value1"}); std::string{"Value1"});
CHECK(logValue["JournalParams"]["Field3"].IsString()); CHECK(logValue.as_object()["JournalParams"].as_object()["Field3"].is_string());
CHECK( CHECK(
logValue["JournalParams"]["Field3"].GetString() == logValue.as_object()["JournalParams"].as_object()["Field3"].get_string() ==
std::string{"Value3"}); std::string{"Value3"});
// Field2 should be overwritten to 0 // Field2 should be overwritten to 0
CHECK(logValue["JournalParams"]["Field2"].IsNumber()); CHECK(logValue.as_object()["JournalParams"].as_object()["Field2"].is_number());
CHECK(logValue["JournalParams"]["Field2"].GetInt() == 2); CHECK(logValue.as_object()["JournalParams"].as_object()["Field2"].get_int64() == 2);
} }
TEST_CASE_FIXTURE( TEST_CASE_FIXTURE(
@@ -602,18 +583,16 @@ TEST_CASE_FIXTURE(
j2.debug() << "Test"; j2.debug() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["JournalParams"].as_object()["Field1"].is_string());
CHECK( CHECK(
logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); logValue.as_object()["JournalParams"].as_object()["Field1"].get_string() ==
CHECK(logValue["JournalParams"]["Field1"].IsString());
CHECK(
logValue["JournalParams"]["Field1"].GetString() ==
std::string{"Value1"}); std::string{"Value1"});
CHECK(logValue["JournalParams"]["Field2"].IsNumber()); CHECK(logValue.as_object()["JournalParams"].as_object()["Field2"].is_number());
CHECK(logValue["JournalParams"]["Field2"].GetInt() == 2); CHECK(logValue.as_object()["JournalParams"].as_object()["Field2"].get_int64() == 2);
} }
TEST_CASE_FIXTURE( TEST_CASE_FIXTURE(
@@ -630,16 +609,14 @@ TEST_CASE_FIXTURE(
j2.debug() << "Test"; j2.debug() << "Test";
rapidjson::Document logValue; boost::system::error_code ec;
logValue.Parse(stream().str().c_str()); auto logValue = boost::json::parse(stream().str(), ec);
CHECK(ec == boost::system::errc::success);
CHECK(logValue.as_object()["JournalParams"].as_object()["Field1"].is_string());
CHECK( CHECK(
logValue.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone); logValue.as_object()["JournalParams"].as_object()["Field1"].get_string() ==
CHECK(logValue["JournalParams"]["Field1"].IsString());
CHECK(
logValue["JournalParams"]["Field1"].GetString() ==
std::string{"Value1"}); std::string{"Value1"});
CHECK(logValue["JournalParams"]["Field2"].IsNumber()); CHECK(logValue.as_object()["JournalParams"].as_object()["Field2"].is_number());
CHECK(logValue["JournalParams"]["Field2"].GetInt() == 2); CHECK(logValue.as_object()["JournalParams"].as_object()["Field2"].get_int64() == 2);
} }