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.
add_library(xrpl.imports.main INTERFACE)
find_package(RapidJSON)
target_link_libraries(xrpl.imports.main
INTERFACE
LibArchive::LibArchive
@@ -77,7 +75,6 @@ add_module(xrpl beast)
target_link_libraries(xrpl.libxrpl.beast PUBLIC
xrpl.imports.main
xrpl.libpb
rapidjson
)
# Level 02

View File

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

View File

@@ -23,9 +23,10 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <charconv>
#include <string>
#include <source_location>
#include <sstream>
#include <string>
#include <string_view>
#include <utility>
namespace ripple::log {
@@ -88,37 +89,45 @@ public:
void
startObject() const
{
stream_.append("{", 1);
stream_.push_back('{');
}
void
endObject() const
{
using namespace std::string_view_literals;
stream_.pop_back();
stream_.append("},", 2);
stream_.append("},"sv);
}
void
writeKey(std::string_view key) const
{
writeString(key);
*stream_.rbegin() = ':';
stream_.back() = ':';
}
void
startArray() const
{
stream_.append("[", 1);
stream_.push_back('[');
}
void
endArray() const
{
using namespace std::string_view_literals;
stream_.pop_back();
stream_.append("],", 2);
stream_.append("],"sv);
}
void
writeString(std::string_view str) const
{
using namespace std::string_view_literals;
stream_.push_back('"');
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
writeInt(std::int64_t val) const
@@ -126,6 +135,11 @@ public:
return pushNumber(val, stream_);
}
std::string_view
writeUInt(std::uint32_t val) const
{
return pushNumber(val, stream_);
}
std::string_view
writeUInt(std::uint64_t val) const
{
return pushNumber(val, stream_);
@@ -138,15 +152,16 @@ public:
std::string_view
writeBool(bool val) const
{
auto str = val ? "true," : "false,";
stream_.append(str, std::strlen(str));
using namespace std::string_view_literals;
auto str = val ? "true,"sv : "false,"sv;
stream_.append(str);
return str;
}
void
writeNull() const
{
stream_.append("null", std::strlen("null"));
stream_.push_back(',');
using namespace std::string_view_literals;
stream_.append("null,"sv);
}
void
writeRaw(std::string_view str) const
@@ -154,11 +169,10 @@ public:
stream_.append(str);
}
[[nodiscard]] std::string
[[nodiscard]] std::string_view
finish()
{
stream_.pop_back();
return stream_;
return std::string_view{stream_.c_str(), stream_.size() - 1};
}
private:
@@ -166,10 +180,11 @@ private:
static std::string_view
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);
*result.ptr = ',';
auto len = result.ptr - std::begin(buffer);
auto ptr = result.ptr;
*ptr = ',';
auto len = ptr - std::begin(buffer);
stream.append(buffer, len + 1);
return {buffer, static_cast<size_t>(len)};
}
@@ -179,17 +194,19 @@ private:
{
static constexpr char HEX[] = "0123456789ABCDEF";
const char* p = str.data();
const char* end = p + str.size();
const char* chunk = p;
char const* p = str.data();
char const* end = p + str.size();
char const* chunk = p;
while (p < end) {
while (p < end)
{
auto c = static_cast<unsigned char>(*p);
// JSON requires escaping for <0x20 and the two specials below.
bool needsEscape = (c < 0x20) || (c == '"') || (c == '\\');
if (!needsEscape) {
if (!needsEscape)
{
++p;
continue;
}
@@ -198,21 +215,33 @@ private:
if (chunk != p)
os.append(chunk, p - chunk);
switch (c) {
case '"': os.append("\\\"", 2); break;
case '\\': os.append("\\\\", 2); 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;
switch (c)
{
case '"':
os.append("\\\"", 2);
break;
case '\\':
os.append("\\\\", 2);
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: {
// Other C0 controls -> \u00XX (JSON compliant)
char buf[6]{
'\\','u','0','0',
HEX[(c >> 4) & 0xF],
HEX[c & 0xF]
};
'\\', 'u', '0', '0', HEX[(c >> 4) & 0xF], HEX[c & 0xF]};
os.append(buf, 6);
break;
}
@@ -288,6 +317,7 @@ public:
public:
JsonLogContext() : messageParamsWriter_(buffer_)
{
buffer_.reserve(1024 * 5);
}
SimpleJsonWriter&
@@ -300,7 +330,7 @@ public:
reset(
std::source_location location,
severities::Severity severity,
std::string const& journalAttributesJson) noexcept;
std::string_view journalAttributesJson) noexcept;
};
private:
@@ -323,7 +353,7 @@ private:
std::source_location location,
severities::Severity severity) const;
static std::string
static std::string_view
formatLog(std::string&& message);
public:
@@ -830,9 +860,10 @@ namespace ripple::log {
namespace detail {
template <typename T>
concept CanToChars = requires (T val)
{
{ to_chars(std::declval<char*>(), std::declval<char*>(), val) } -> std::convertible_to<std::to_chars_result>;
concept CanToChars = requires(T val) {
{
to_chars(std::declval<char*>(), std::declval<char*>(), val)
} -> std::convertible_to<std::to_chars_result>;
};
template <typename T>
@@ -901,7 +932,8 @@ setJsonValue(
if constexpr (CanToChars<ValueType>)
{
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{})
{
std::string_view sv;
@@ -925,7 +957,8 @@ setJsonValue(
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(
std::source_location location,
severities::Severity severity,
std::string const& journalAttributesJson) noexcept
std::string_view journalAttributesJson) noexcept
{
struct ThreadIdStringInitializer
{
@@ -152,7 +152,9 @@ Journal::JsonLogContext::reset(
if (!globalLogAttributesJson_.empty())
{
writer().writeKey("GlobalParams");
writer().writeRaw(globalLogAttributesJson_);
writer().writeRaw(std::string_view{
std::begin(globalLogAttributesJson_),
std::end(globalLogAttributesJson_)});
writer().endObject();
}
@@ -166,7 +168,7 @@ Journal::JsonLogContext::reset(
writer().writeString(location.file_name());
writer().writeKey("Line");
writer().writeInt(location.line());
writer().writeInt(static_cast<std::int32_t>(location.line()));
writer().writeKey("ThreadId");
writer().writeString(threadId.value);
@@ -176,7 +178,7 @@ Journal::JsonLogContext::reset(
writer().writeString(severityStr);
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())
.count());
}
@@ -186,10 +188,14 @@ Journal::initMessageContext(
std::source_location location,
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)
{
if (!m_jsonLogsEnabled)
@@ -288,9 +294,9 @@ Journal::ScopedStream::~ScopedStream()
if (!s.empty())
{
if (s == "\n")
m_sink.write(m_level, formatLog(""));
m_sink.write(m_level, std::string{formatLog("")});
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.
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 rapidjson xrpl.libxrpl)
target_link_libraries(xrpl.imports.test INTERFACE doctest::doctest xrpl.libxrpl)
# One test for each module.
xrpl_add_test(basics)

View File

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