mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-27 06:25:51 +00:00
Performance improvement
This commit is contained in:
@@ -51,6 +51,8 @@ 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
|
||||
@@ -75,6 +77,7 @@ add_module(xrpl beast)
|
||||
target_link_libraries(xrpl.libxrpl.beast PUBLIC
|
||||
xrpl.imports.main
|
||||
xrpl.libpb
|
||||
rapidjson
|
||||
)
|
||||
|
||||
# Level 02
|
||||
@@ -85,14 +88,9 @@ target_link_libraries(xrpl.libxrpl.basics PUBLIC xrpl.libxrpl.beast)
|
||||
add_module(xrpl json)
|
||||
target_link_libraries(xrpl.libxrpl.json PUBLIC xrpl.libxrpl.basics)
|
||||
|
||||
add_module(xrpl telemetry)
|
||||
target_link_libraries(xrpl.libxrpl.telemetry PUBLIC xrpl.libxrpl.json)
|
||||
|
||||
add_module(xrpl crypto)
|
||||
target_link_libraries(xrpl.libxrpl.crypto PUBLIC
|
||||
xrpl.libxrpl.basics
|
||||
xrpl.libxrpl.telemetry
|
||||
)
|
||||
target_link_libraries(xrpl.libxrpl.crypto PUBLIC xrpl.libxrpl.basics)
|
||||
|
||||
# Level 04
|
||||
add_module(xrpl protocol)
|
||||
@@ -139,7 +137,6 @@ target_link_modules(xrpl PUBLIC
|
||||
beast
|
||||
crypto
|
||||
json
|
||||
telemetry
|
||||
protocol
|
||||
resource
|
||||
server
|
||||
|
||||
@@ -16,7 +16,6 @@ install (
|
||||
xrpl.libxrpl.beast
|
||||
xrpl.libxrpl.crypto
|
||||
xrpl.libxrpl.json
|
||||
xrpl.libxrpl.telemetry
|
||||
xrpl.libxrpl.protocol
|
||||
xrpl.libxrpl.resource
|
||||
xrpl.libxrpl.ledger
|
||||
|
||||
@@ -30,6 +30,7 @@ class Xrpl(ConanFile):
|
||||
'openssl/1.1.1w',
|
||||
'soci/4.0.3',
|
||||
'zlib/1.3.1',
|
||||
"rapidjson/1.1.0"
|
||||
]
|
||||
|
||||
test_requires = [
|
||||
|
||||
@@ -167,8 +167,6 @@ private:
|
||||
beast::severities::Severity thresh_;
|
||||
File file_;
|
||||
bool silent_ = false;
|
||||
static std::unique_ptr<beast::Journal::StructuredLogAttributes>
|
||||
globalLogAttributes_;
|
||||
|
||||
public:
|
||||
Logs(beast::severities::Severity level);
|
||||
@@ -191,8 +189,8 @@ public:
|
||||
beast::Journal
|
||||
journal(
|
||||
std::string const& name,
|
||||
std::unique_ptr<beast::Journal::StructuredLogAttributes> attributes =
|
||||
{});
|
||||
std::optional<beast::Journal::JsonLogAttributes> attributes =
|
||||
std::nullopt);
|
||||
|
||||
beast::severities::Severity
|
||||
threshold() const;
|
||||
@@ -229,20 +227,6 @@ public:
|
||||
std::string const& partition,
|
||||
beast::severities::Severity startingLevel);
|
||||
|
||||
static void
|
||||
setGlobalAttributes(std::unique_ptr<beast::Journal::StructuredLogAttributes>
|
||||
globalLogAttributes)
|
||||
{
|
||||
if (!globalLogAttributes_)
|
||||
{
|
||||
globalLogAttributes_ = std::move(globalLogAttributes);
|
||||
}
|
||||
else
|
||||
{
|
||||
globalLogAttributes_->combine(std::move(globalLogAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static LogSeverity
|
||||
fromSeverity(beast::severities::Severity level);
|
||||
|
||||
@@ -21,11 +21,62 @@
|
||||
#define BEAST_UTILITY_JOURNAL_H_INCLUDED
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <memory>
|
||||
#include <deque>
|
||||
#include <utility>
|
||||
#include <source_location>
|
||||
#include <sstream>
|
||||
|
||||
|
||||
namespace ripple::log {
|
||||
template <typename T>
|
||||
class LogParameter
|
||||
{
|
||||
public:
|
||||
template <typename TArg>
|
||||
LogParameter(char const* name, TArg&& value)
|
||||
: name_(name), value_(std::forward<TArg>(value))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
char const* name_;
|
||||
T value_;
|
||||
|
||||
template <typename U>
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, LogParameter<U> const&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class LogField
|
||||
{
|
||||
public:
|
||||
template <typename TArg>
|
||||
LogField(char const* name, TArg&& value)
|
||||
: name_(name), value_(std::forward<TArg>(value))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
char const* name_;
|
||||
T value_;
|
||||
|
||||
template <typename U>
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, LogField<U> const&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, LogField<T> const& param);
|
||||
|
||||
template <typename T>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, LogParameter<T> const& param);
|
||||
}
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** A namespace for easy access to logging severity values. */
|
||||
@@ -64,75 +115,111 @@ to_string(Severity severity);
|
||||
class Journal
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
friend std::ostream&
|
||||
ripple::log::operator<<(std::ostream& os, ripple::log::LogField<T> const& param);
|
||||
|
||||
template <typename T>
|
||||
friend std::ostream&
|
||||
ripple::log::operator<<(
|
||||
std::ostream& os,
|
||||
ripple::log::LogParameter<T> const& param);
|
||||
|
||||
class Sink;
|
||||
|
||||
class StructuredJournalImpl;
|
||||
class JsonLogAttributes
|
||||
{
|
||||
public:
|
||||
using AttributeFields = rapidjson::Value;
|
||||
|
||||
class StructuredLogAttributes;
|
||||
JsonLogAttributes();
|
||||
JsonLogAttributes(JsonLogAttributes const& other);
|
||||
|
||||
JsonLogAttributes&
|
||||
operator=(JsonLogAttributes const& other);
|
||||
|
||||
void
|
||||
setModuleName(std::string const& name);
|
||||
|
||||
[[nodiscard]] static JsonLogAttributes
|
||||
combine(AttributeFields const& a, AttributeFields const& b);
|
||||
|
||||
AttributeFields&
|
||||
contextValues()
|
||||
{
|
||||
return contextValues_;
|
||||
}
|
||||
|
||||
[[nodiscard]] AttributeFields const&
|
||||
contextValues() const
|
||||
{
|
||||
return contextValues_;
|
||||
}
|
||||
|
||||
rapidjson::MemoryPoolAllocator<>&
|
||||
allocator()
|
||||
{
|
||||
return allocator_;
|
||||
}
|
||||
|
||||
private:
|
||||
AttributeFields contextValues_;
|
||||
rapidjson::MemoryPoolAllocator<> allocator_;
|
||||
|
||||
friend class Journal;
|
||||
};
|
||||
|
||||
struct JsonLogContext
|
||||
{
|
||||
std::source_location location = {};
|
||||
rapidjson::Value messageParams;
|
||||
rapidjson::MemoryPoolAllocator<> allocator;
|
||||
|
||||
JsonLogContext() = default;
|
||||
|
||||
void
|
||||
reset(std::source_location location_) noexcept
|
||||
{
|
||||
location = location_;
|
||||
messageParams = rapidjson::Value{};
|
||||
messageParams.SetObject();
|
||||
allocator.Clear();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
// Severity level / threshold of a Journal message.
|
||||
using Severity = severities::Severity;
|
||||
|
||||
std::unique_ptr<StructuredLogAttributes> m_attributes;
|
||||
std::optional<JsonLogAttributes> m_attributes;
|
||||
static std::optional<JsonLogAttributes> globalLogAttributes_;
|
||||
static std::mutex globalLogAttributesMutex_;
|
||||
static bool m_jsonLogsEnabled;
|
||||
|
||||
static thread_local JsonLogContext currentJsonLogContext_;
|
||||
|
||||
static std::unique_ptr<StructuredJournalImpl> m_structuredJournalImpl;
|
||||
|
||||
// Invariant: m_sink always points to a valid Sink
|
||||
Sink* m_sink = nullptr;
|
||||
|
||||
static void
|
||||
initMessageContext(std::source_location location);
|
||||
|
||||
static std::string
|
||||
formatLog(std::string const& message,
|
||||
severities::Severity severity,
|
||||
std::optional<JsonLogAttributes> const& attributes = std::nullopt);
|
||||
public:
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
enableStructuredJournal(std::unique_ptr<StructuredJournalImpl> impl)
|
||||
{
|
||||
m_structuredJournalImpl = std::move(impl);
|
||||
}
|
||||
enableStructuredJournal();
|
||||
|
||||
static void
|
||||
disableStructuredJournal()
|
||||
{
|
||||
m_structuredJournalImpl = nullptr;
|
||||
}
|
||||
disableStructuredJournal();
|
||||
|
||||
static bool
|
||||
isStructuredJournalEnabled()
|
||||
{
|
||||
return m_structuredJournalImpl != nullptr;
|
||||
}
|
||||
|
||||
class StructuredJournalImpl
|
||||
{
|
||||
public:
|
||||
StructuredJournalImpl() = default;
|
||||
StructuredJournalImpl(StructuredJournalImpl const&) = default;
|
||||
virtual void
|
||||
initMessageContext(std::source_location location) = 0;
|
||||
virtual void
|
||||
flush(
|
||||
Sink* sink,
|
||||
severities::Severity level,
|
||||
std::string const& text,
|
||||
StructuredLogAttributes* attributes) = 0;
|
||||
virtual ~StructuredJournalImpl() = default;
|
||||
};
|
||||
|
||||
class StructuredLogAttributes
|
||||
{
|
||||
public:
|
||||
StructuredLogAttributes() = default;
|
||||
StructuredLogAttributes(StructuredLogAttributes const&) = default;
|
||||
virtual void
|
||||
setModuleName(std::string const& name) = 0;
|
||||
virtual std::unique_ptr<StructuredLogAttributes>
|
||||
clone() const = 0;
|
||||
virtual void
|
||||
combine(std::unique_ptr<StructuredLogAttributes> const& attributes) = 0;
|
||||
virtual void
|
||||
combine(std::unique_ptr<StructuredLogAttributes>&& attributes) = 0;
|
||||
virtual ~StructuredLogAttributes() = default;
|
||||
};
|
||||
isStructuredJournalEnabled();
|
||||
|
||||
/** Abstraction for the underlying message destination. */
|
||||
class Sink
|
||||
@@ -214,25 +301,25 @@ public:
|
||||
public:
|
||||
ScopedStream(ScopedStream const& other)
|
||||
: ScopedStream(
|
||||
other.m_attributes ? other.m_attributes->clone() : nullptr,
|
||||
other.m_attributes,
|
||||
other.m_sink,
|
||||
other.m_level)
|
||||
{
|
||||
}
|
||||
|
||||
ScopedStream(
|
||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
||||
std::optional<JsonLogAttributes> attributes,
|
||||
Sink& sink,
|
||||
Severity level);
|
||||
|
||||
template <typename T>
|
||||
ScopedStream(
|
||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
||||
std::optional<JsonLogAttributes> attributes,
|
||||
Stream const& stream,
|
||||
T const& t);
|
||||
|
||||
ScopedStream(
|
||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
||||
std::optional<JsonLogAttributes> attributes,
|
||||
Stream const& stream,
|
||||
std::ostream& manip(std::ostream&));
|
||||
|
||||
@@ -255,7 +342,7 @@ public:
|
||||
operator<<(T const& t) const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<StructuredLogAttributes> m_attributes;
|
||||
std::optional<JsonLogAttributes> m_attributes;
|
||||
Sink& m_sink;
|
||||
Severity const m_level;
|
||||
std::ostringstream mutable m_ostream;
|
||||
@@ -291,7 +378,7 @@ public:
|
||||
Constructor is inlined so checking active() very inexpensive.
|
||||
*/
|
||||
Stream(
|
||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
||||
std::optional<JsonLogAttributes> attributes,
|
||||
Sink& sink,
|
||||
Severity level)
|
||||
: m_attributes(std::move(attributes)), m_sink(sink), m_level(level)
|
||||
@@ -304,7 +391,7 @@ public:
|
||||
/** Construct or copy another Stream. */
|
||||
Stream(Stream const& other)
|
||||
: Stream(
|
||||
other.m_attributes ? other.m_attributes->clone() : nullptr,
|
||||
other.m_attributes,
|
||||
other.m_sink,
|
||||
other.m_level)
|
||||
{
|
||||
@@ -353,7 +440,7 @@ public:
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
std::unique_ptr<StructuredLogAttributes> m_attributes;
|
||||
std::optional<JsonLogAttributes> m_attributes;
|
||||
Sink& m_sink;
|
||||
Severity m_level;
|
||||
};
|
||||
@@ -372,47 +459,29 @@ public:
|
||||
/** Journal has no default constructor. */
|
||||
Journal() = delete;
|
||||
|
||||
Journal(Journal const& other) : Journal(other, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Journal(
|
||||
Journal const& other,
|
||||
std::unique_ptr<StructuredLogAttributes> attributes)
|
||||
std::optional<JsonLogAttributes> attributes = std::nullopt)
|
||||
: m_sink(other.m_sink)
|
||||
{
|
||||
if (attributes)
|
||||
m_attributes = std::move(attributes);
|
||||
if (other.m_attributes)
|
||||
if (attributes.has_value())
|
||||
m_attributes = std::move(attributes.value());
|
||||
if (other.m_attributes.has_value())
|
||||
{
|
||||
if (m_attributes)
|
||||
m_attributes->combine(other.m_attributes);
|
||||
if (m_attributes.has_value())
|
||||
m_attributes = JsonLogAttributes::combine(
|
||||
other.m_attributes->contextValues_,
|
||||
m_attributes->contextValues_
|
||||
);
|
||||
else
|
||||
m_attributes = other.m_attributes->clone();
|
||||
m_attributes = other.m_attributes;
|
||||
}
|
||||
}
|
||||
|
||||
Journal(
|
||||
Journal&& other,
|
||||
std::unique_ptr<StructuredLogAttributes> attributes = {}) noexcept
|
||||
: m_sink(other.m_sink)
|
||||
{
|
||||
if (attributes)
|
||||
m_attributes = std::move(attributes);
|
||||
if (other.m_attributes)
|
||||
{
|
||||
if (m_attributes)
|
||||
m_attributes->combine(std::move(other.m_attributes));
|
||||
else
|
||||
m_attributes = std::move(other.m_attributes);
|
||||
}
|
||||
}
|
||||
|
||||
/** Create a journal that writes to the specified sink. */
|
||||
Journal(
|
||||
explicit Journal(
|
||||
Sink& sink,
|
||||
std::string const& name = {},
|
||||
std::unique_ptr<StructuredLogAttributes> attributes = {})
|
||||
std::optional<JsonLogAttributes> attributes = std::nullopt)
|
||||
: m_sink(&sink)
|
||||
{
|
||||
if (attributes)
|
||||
@@ -425,9 +494,11 @@ public:
|
||||
Journal&
|
||||
operator=(Journal const& other)
|
||||
{
|
||||
if (&other == this)
|
||||
return *this;
|
||||
|
||||
m_sink = other.m_sink;
|
||||
if (other.m_attributes)
|
||||
m_attributes = other.m_attributes->clone();
|
||||
m_attributes = other.m_attributes;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -435,8 +506,7 @@ public:
|
||||
operator=(Journal&& other) noexcept
|
||||
{
|
||||
m_sink = other.m_sink;
|
||||
if (other.m_attributes)
|
||||
m_attributes = std::move(other.m_attributes);
|
||||
m_attributes = std::move(other.m_attributes);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -452,7 +522,7 @@ public:
|
||||
stream(Severity level) const
|
||||
{
|
||||
return Stream(
|
||||
m_attributes ? m_attributes->clone() : nullptr, *m_sink, level);
|
||||
m_attributes, *m_sink, level);
|
||||
}
|
||||
|
||||
/** Returns `true` if any message would be logged at this severity level.
|
||||
@@ -470,10 +540,10 @@ public:
|
||||
Stream
|
||||
trace(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_structuredJournalImpl)
|
||||
m_structuredJournalImpl->initMessageContext(location);
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location);
|
||||
return {
|
||||
m_attributes ? m_attributes->clone() : nullptr,
|
||||
m_attributes,
|
||||
*m_sink,
|
||||
severities::kTrace};
|
||||
}
|
||||
@@ -481,10 +551,10 @@ public:
|
||||
Stream
|
||||
debug(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_structuredJournalImpl)
|
||||
m_structuredJournalImpl->initMessageContext(location);
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location);
|
||||
return {
|
||||
m_attributes ? m_attributes->clone() : nullptr,
|
||||
m_attributes,
|
||||
*m_sink,
|
||||
severities::kDebug};
|
||||
}
|
||||
@@ -492,10 +562,10 @@ public:
|
||||
Stream
|
||||
info(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_structuredJournalImpl)
|
||||
m_structuredJournalImpl->initMessageContext(location);
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location);
|
||||
return {
|
||||
m_attributes ? m_attributes->clone() : nullptr,
|
||||
m_attributes,
|
||||
*m_sink,
|
||||
severities::kInfo};
|
||||
}
|
||||
@@ -503,10 +573,12 @@ public:
|
||||
Stream
|
||||
warn(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_structuredJournalImpl)
|
||||
m_structuredJournalImpl->initMessageContext(location);
|
||||
const char* a = "a";
|
||||
rapidjson::Value v{a, 1};
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location);
|
||||
return {
|
||||
m_attributes ? m_attributes->clone() : nullptr,
|
||||
m_attributes,
|
||||
*m_sink,
|
||||
severities::kWarning};
|
||||
}
|
||||
@@ -514,10 +586,10 @@ public:
|
||||
Stream
|
||||
error(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_structuredJournalImpl)
|
||||
m_structuredJournalImpl->initMessageContext(location);
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location);
|
||||
return {
|
||||
m_attributes ? m_attributes->clone() : nullptr,
|
||||
m_attributes,
|
||||
*m_sink,
|
||||
severities::kError};
|
||||
}
|
||||
@@ -525,14 +597,25 @@ public:
|
||||
Stream
|
||||
fatal(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_structuredJournalImpl)
|
||||
m_structuredJournalImpl->initMessageContext(location);
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location);
|
||||
return {
|
||||
m_attributes ? m_attributes->clone() : nullptr,
|
||||
m_attributes,
|
||||
*m_sink,
|
||||
severities::kFatal};
|
||||
}
|
||||
/** @} */
|
||||
|
||||
static void
|
||||
addGlobalAttributes(JsonLogAttributes globalLogAttributes)
|
||||
{
|
||||
std::lock_guard lock(globalLogAttributesMutex_);
|
||||
if (!globalLogAttributes_)
|
||||
{
|
||||
globalLogAttributes_ = JsonLogAttributes{};
|
||||
}
|
||||
globalLogAttributes_ = JsonLogAttributes::combine(globalLogAttributes_->contextValues(), globalLogAttributes.contextValues());
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef __INTELLISENSE__
|
||||
@@ -548,7 +631,7 @@ static_assert(std::is_nothrow_destructible<Journal>::value == true, "");
|
||||
|
||||
template <typename T>
|
||||
Journal::ScopedStream::ScopedStream(
|
||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
||||
std::optional<JsonLogAttributes> attributes,
|
||||
Stream const& stream,
|
||||
T const& t)
|
||||
: ScopedStream(std::move(attributes), stream.sink(), stream.level())
|
||||
@@ -570,7 +653,7 @@ template <typename T>
|
||||
Journal::ScopedStream
|
||||
Journal::Stream::operator<<(T const& t) const
|
||||
{
|
||||
return {m_attributes ? m_attributes->clone() : nullptr, *this, t};
|
||||
return {m_attributes, *this, t};
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
@@ -642,4 +725,127 @@ using logwstream = basic_logstream<wchar_t>;
|
||||
|
||||
} // namespace beast
|
||||
|
||||
|
||||
namespace ripple::log {
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
void setJsonValue(
|
||||
rapidjson::Value& object,
|
||||
rapidjson::MemoryPoolAllocator<>& allocator,
|
||||
char const* name,
|
||||
T&& value,
|
||||
std::ostream* outStream)
|
||||
{
|
||||
using ValueType = std::decay_t<T>;
|
||||
rapidjson::Value jsonValue;
|
||||
if constexpr (std::constructible_from<rapidjson::Value, ValueType, rapidjson::MemoryPoolAllocator<>&>)
|
||||
{
|
||||
jsonValue = rapidjson::Value{value, allocator};
|
||||
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)
|
||||
{
|
||||
(*outStream) << value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << value;
|
||||
|
||||
jsonValue = rapidjson::Value{oss.str().c_str(), allocator};
|
||||
|
||||
if (outStream)
|
||||
{
|
||||
(*outStream) << oss.str();
|
||||
}
|
||||
}
|
||||
|
||||
object.AddMember(
|
||||
rapidjson::StringRef(name),
|
||||
std::move(jsonValue),
|
||||
allocator
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, LogParameter<T> const& param)
|
||||
{
|
||||
if (!beast::Journal::m_jsonLogsEnabled)
|
||||
return os;
|
||||
detail::setJsonValue(
|
||||
beast::Journal::currentJsonLogContext_.messageParams,
|
||||
beast::Journal::currentJsonLogContext_.allocator,
|
||||
param.name_, param.value_, &os);
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, LogField<T> const& param)
|
||||
{
|
||||
if (!beast::Journal::m_jsonLogsEnabled)
|
||||
return os;
|
||||
detail::setJsonValue(
|
||||
beast::Journal::currentJsonLogContext_.messageParams,
|
||||
beast::Journal::currentJsonLogContext_.allocator,
|
||||
param.name_, param.value_, nullptr);
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
LogParameter<T>
|
||||
param(char const* name, T&& value)
|
||||
{
|
||||
return LogParameter<T>{name, std::forward<T>(value)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
LogField<T>
|
||||
field(char const* name, T&& value)
|
||||
{
|
||||
return LogField<T>{name, std::forward<T>(value)};
|
||||
}
|
||||
|
||||
template<typename... Pair>
|
||||
[[nodiscard]] beast::Journal::JsonLogAttributes
|
||||
attributes(Pair&&... pairs)
|
||||
{
|
||||
beast::Journal::JsonLogAttributes result;
|
||||
|
||||
(detail::setJsonValue(
|
||||
result.contextValues(),
|
||||
result.allocator(),
|
||||
pairs.first,
|
||||
pairs.second, nullptr), ...);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] std::pair<char const*, std::decay_t<T>>
|
||||
attr(char const* name, T&& value)
|
||||
{
|
||||
return std::make_pair(name, std::forward<T>(value));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include <xrpl/resource/Fees.h>
|
||||
#include <xrpl/resource/Gossip.h>
|
||||
#include <xrpl/resource/detail/Import.h>
|
||||
#include <xrpl/telemetry/JsonLogs.h>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <xrpl/server/Port.h>
|
||||
#include <xrpl/server/detail/LowestLayer.h>
|
||||
#include <xrpl/server/detail/io_list.h>
|
||||
#include <xrpl/telemetry/JsonLogs.h>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
@@ -86,11 +85,11 @@ BasePeer<Handler, Impl>::BasePeer(
|
||||
, remote_address_(remote_address)
|
||||
, j_(journal,
|
||||
log::attributes(
|
||||
{{"PeerID",
|
||||
log::attr("PeerID",
|
||||
[] {
|
||||
static std::atomic<unsigned> id{0};
|
||||
return "##" + std::to_string(++id) + " ";
|
||||
}()}}))
|
||||
}())))
|
||||
, work_(boost::asio::make_work_guard(executor))
|
||||
, strand_(boost::asio::make_strand(executor))
|
||||
{
|
||||
|
||||
@@ -1,220 +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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_LOGGING_STRUCTUREDJOURNAL_H_INCLUDED
|
||||
#define RIPPLE_LOGGING_STRUCTUREDJOURNAL_H_INCLUDED
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
#include <memory>
|
||||
#include <source_location>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple::log {
|
||||
|
||||
template <typename T>
|
||||
class LogParameter
|
||||
{
|
||||
public:
|
||||
template <typename TArg>
|
||||
LogParameter(char const* name, TArg&& value)
|
||||
: name_(name), value_(std::forward<TArg>(value))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
char const* name_;
|
||||
T value_;
|
||||
|
||||
template <typename U>
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, LogParameter<U> const&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class LogField
|
||||
{
|
||||
public:
|
||||
template <typename TArg>
|
||||
LogField(char const* name, TArg&& value)
|
||||
: name_(name), value_(std::forward<TArg>(value))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
char const* name_;
|
||||
T value_;
|
||||
|
||||
template <typename U>
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, LogField<U> const&);
|
||||
};
|
||||
|
||||
class JsonLogAttributes : public beast::Journal::StructuredLogAttributes
|
||||
{
|
||||
public:
|
||||
using AttributeFields = std::unordered_map<std::string, Json::Value>;
|
||||
using Pair = AttributeFields::value_type;
|
||||
|
||||
explicit JsonLogAttributes(AttributeFields contextValues = {});
|
||||
|
||||
void
|
||||
setModuleName(std::string const& name) override;
|
||||
|
||||
[[nodiscard]] std::unique_ptr<StructuredLogAttributes>
|
||||
clone() const override;
|
||||
|
||||
void
|
||||
combine(std::unique_ptr<StructuredLogAttributes> const& context) override;
|
||||
|
||||
void
|
||||
combine(std::unique_ptr<StructuredLogAttributes>&& context) override;
|
||||
|
||||
AttributeFields&
|
||||
contextValues()
|
||||
{
|
||||
return contextValues_;
|
||||
}
|
||||
|
||||
private:
|
||||
AttributeFields contextValues_;
|
||||
};
|
||||
|
||||
class JsonStructuredJournal : public beast::Journal::StructuredJournalImpl
|
||||
{
|
||||
private:
|
||||
struct Logger
|
||||
{
|
||||
std::source_location location = {};
|
||||
Json::Value messageParams;
|
||||
|
||||
Logger() = default;
|
||||
Logger(
|
||||
JsonStructuredJournal const* journal,
|
||||
std::source_location location);
|
||||
|
||||
void
|
||||
write(
|
||||
beast::Journal::Sink* sink,
|
||||
beast::severities::Severity level,
|
||||
std::string const& text,
|
||||
beast::Journal::StructuredLogAttributes* context) const;
|
||||
};
|
||||
|
||||
[[nodiscard]] Logger
|
||||
logger(std::source_location location) const;
|
||||
|
||||
static thread_local Logger currentLogger_;
|
||||
|
||||
template <typename T>
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, LogParameter<T> const&);
|
||||
|
||||
template <typename T>
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& os, LogField<T> const&);
|
||||
|
||||
public:
|
||||
void
|
||||
initMessageContext(std::source_location location) override;
|
||||
|
||||
void
|
||||
flush(
|
||||
beast::Journal::Sink* sink,
|
||||
beast::severities::Severity level,
|
||||
std::string const& text,
|
||||
beast::Journal::StructuredLogAttributes* context) override;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, LogParameter<T> const& param)
|
||||
{
|
||||
using ValueType = std::decay_t<T>;
|
||||
// TODO: Update the Json library to support 64-bit integer values.
|
||||
if constexpr (
|
||||
std::constructible_from<Json::Value, ValueType> &&
|
||||
(!std::is_integral_v<ValueType> ||
|
||||
sizeof(ValueType) <= sizeof(Json::Int)))
|
||||
{
|
||||
JsonStructuredJournal::currentLogger_.messageParams[param.name_] =
|
||||
Json::Value{param.value_};
|
||||
return os << param.value_;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << param.value_;
|
||||
|
||||
JsonStructuredJournal::currentLogger_.messageParams[param.name_] =
|
||||
oss.str();
|
||||
return os << oss.str();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, LogField<T> const& param)
|
||||
{
|
||||
using ValueType = std::decay_t<T>;
|
||||
// TODO: Update the Json library to support 64-bit integer values.
|
||||
if constexpr (
|
||||
std::constructible_from<Json::Value, ValueType> &&
|
||||
(!std::is_integral_v<ValueType> ||
|
||||
sizeof(ValueType) <= sizeof(Json::Int)))
|
||||
{
|
||||
JsonStructuredJournal::currentLogger_.messageParams[param.name_] =
|
||||
Json::Value{param.value_};
|
||||
}
|
||||
else
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << param.value_;
|
||||
|
||||
JsonStructuredJournal::currentLogger_.messageParams[param.name_] =
|
||||
oss.str();
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
LogParameter<T>
|
||||
param(char const* name, T&& value)
|
||||
{
|
||||
return LogParameter<T>{name, std::forward<T>(value)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
LogField<T>
|
||||
field(char const* name, T&& value)
|
||||
{
|
||||
return LogField<T>{name, std::forward<T>(value)};
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::unique_ptr<JsonLogAttributes>
|
||||
attributes(std::initializer_list<JsonLogAttributes::Pair> const& fields)
|
||||
{
|
||||
return std::make_unique<JsonLogAttributes>(fields);
|
||||
}
|
||||
|
||||
} // namespace ripple::log
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
@@ -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{¤tJsonLogContext_.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
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -2,10 +2,11 @@ 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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include <doctest/doctest.h>
|
||||
@@ -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())
|
||||
|
||||
@@ -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>
|
||||
@@ -835,8 +834,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;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -1220,9 +1219,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)
|
||||
{
|
||||
@@ -2176,7 +2175,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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/process/v1/args.hpp>
|
||||
@@ -797,10 +796,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);
|
||||
|
||||
@@ -1190,6 +1190,10 @@ NetworkOPsImp::strOperatingMode(OperatingMode const mode, bool const admin)
|
||||
void
|
||||
NetworkOPsImp::submitTransaction(std::shared_ptr<STTx const> const& iTrans)
|
||||
{
|
||||
beast::Journal journal{
|
||||
m_journal,
|
||||
log::attributes(
|
||||
log::attr("TransactionID", to_string(iTrans->getTransactionID())))};
|
||||
if (isNeedNetworkLedger())
|
||||
{
|
||||
// Nothing we can do if we've never been in sync
|
||||
@@ -1253,6 +1257,9 @@ NetworkOPsImp::submitTransaction(std::shared_ptr<STTx const> const& iTrans)
|
||||
bool
|
||||
NetworkOPsImp::preProcessTransaction(std::shared_ptr<Transaction>& transaction)
|
||||
{
|
||||
beast::Journal journal{
|
||||
m_journal,
|
||||
log::attributes(log::attr("TransactionID", to_string(transaction->getID())))};
|
||||
auto const newFlags = app_.getHashRouter().getFlags(transaction->getID());
|
||||
|
||||
if ((newFlags & HashRouterFlags::BAD) != HashRouterFlags::UNDEFINED)
|
||||
|
||||
@@ -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_))
|
||||
))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,11 @@ public:
|
||||
, rules(rules_)
|
||||
, flags(flags_)
|
||||
, parentBatchId(parentBatchId_)
|
||||
, j(j_)
|
||||
, j(j_,
|
||||
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");
|
||||
@@ -101,7 +105,11 @@ public:
|
||||
, flags(flags_)
|
||||
, tx(tx_)
|
||||
, parentBatchId(parentBatchId_)
|
||||
, j(j_)
|
||||
, j(j_,
|
||||
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),
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -41,7 +41,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_(boost::asio::make_strand(io_context))
|
||||
|
||||
@@ -168,7 +168,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))
|
||||
|
||||
@@ -85,15 +85,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_)
|
||||
@@ -1392,6 +1392,12 @@ PeerImp::handleTransaction(
|
||||
{
|
||||
auto stx = std::make_shared<STTx const>(sit);
|
||||
uint256 txID = stx->getTransactionID();
|
||||
beast::Journal protocolJournal{
|
||||
p_journal_,
|
||||
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
|
||||
|
||||
@@ -830,15 +830,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_)
|
||||
|
||||
Reference in New Issue
Block a user