mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-23 04: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.
|
# TODO: Clean up the number of library targets later.
|
||||||
add_library(xrpl.imports.main INTERFACE)
|
add_library(xrpl.imports.main INTERFACE)
|
||||||
|
|
||||||
|
find_package(RapidJSON)
|
||||||
|
|
||||||
target_link_libraries(xrpl.imports.main
|
target_link_libraries(xrpl.imports.main
|
||||||
INTERFACE
|
INTERFACE
|
||||||
LibArchive::LibArchive
|
LibArchive::LibArchive
|
||||||
@@ -75,6 +77,7 @@ add_module(xrpl beast)
|
|||||||
target_link_libraries(xrpl.libxrpl.beast PUBLIC
|
target_link_libraries(xrpl.libxrpl.beast PUBLIC
|
||||||
xrpl.imports.main
|
xrpl.imports.main
|
||||||
xrpl.libpb
|
xrpl.libpb
|
||||||
|
rapidjson
|
||||||
)
|
)
|
||||||
|
|
||||||
# Level 02
|
# Level 02
|
||||||
@@ -85,14 +88,9 @@ target_link_libraries(xrpl.libxrpl.basics PUBLIC xrpl.libxrpl.beast)
|
|||||||
add_module(xrpl json)
|
add_module(xrpl json)
|
||||||
target_link_libraries(xrpl.libxrpl.json PUBLIC xrpl.libxrpl.basics)
|
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)
|
add_module(xrpl crypto)
|
||||||
target_link_libraries(xrpl.libxrpl.crypto PUBLIC
|
target_link_libraries(xrpl.libxrpl.crypto PUBLIC xrpl.libxrpl.basics)
|
||||||
xrpl.libxrpl.basics
|
|
||||||
xrpl.libxrpl.telemetry
|
|
||||||
)
|
|
||||||
|
|
||||||
# Level 04
|
# Level 04
|
||||||
add_module(xrpl protocol)
|
add_module(xrpl protocol)
|
||||||
@@ -139,7 +137,6 @@ target_link_modules(xrpl PUBLIC
|
|||||||
beast
|
beast
|
||||||
crypto
|
crypto
|
||||||
json
|
json
|
||||||
telemetry
|
|
||||||
protocol
|
protocol
|
||||||
resource
|
resource
|
||||||
server
|
server
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ install (
|
|||||||
xrpl.libxrpl.beast
|
xrpl.libxrpl.beast
|
||||||
xrpl.libxrpl.crypto
|
xrpl.libxrpl.crypto
|
||||||
xrpl.libxrpl.json
|
xrpl.libxrpl.json
|
||||||
xrpl.libxrpl.telemetry
|
|
||||||
xrpl.libxrpl.protocol
|
xrpl.libxrpl.protocol
|
||||||
xrpl.libxrpl.resource
|
xrpl.libxrpl.resource
|
||||||
xrpl.libxrpl.ledger
|
xrpl.libxrpl.ledger
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class Xrpl(ConanFile):
|
|||||||
'openssl/1.1.1w',
|
'openssl/1.1.1w',
|
||||||
'soci/4.0.3',
|
'soci/4.0.3',
|
||||||
'zlib/1.3.1',
|
'zlib/1.3.1',
|
||||||
|
"rapidjson/1.1.0"
|
||||||
]
|
]
|
||||||
|
|
||||||
test_requires = [
|
test_requires = [
|
||||||
|
|||||||
@@ -167,8 +167,6 @@ private:
|
|||||||
beast::severities::Severity thresh_;
|
beast::severities::Severity thresh_;
|
||||||
File file_;
|
File file_;
|
||||||
bool silent_ = false;
|
bool silent_ = false;
|
||||||
static std::unique_ptr<beast::Journal::StructuredLogAttributes>
|
|
||||||
globalLogAttributes_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Logs(beast::severities::Severity level);
|
Logs(beast::severities::Severity level);
|
||||||
@@ -191,8 +189,8 @@ public:
|
|||||||
beast::Journal
|
beast::Journal
|
||||||
journal(
|
journal(
|
||||||
std::string const& name,
|
std::string const& name,
|
||||||
std::unique_ptr<beast::Journal::StructuredLogAttributes> attributes =
|
std::optional<beast::Journal::JsonLogAttributes> attributes =
|
||||||
{});
|
std::nullopt);
|
||||||
|
|
||||||
beast::severities::Severity
|
beast::severities::Severity
|
||||||
threshold() const;
|
threshold() const;
|
||||||
@@ -229,20 +227,6 @@ public:
|
|||||||
std::string const& partition,
|
std::string const& partition,
|
||||||
beast::severities::Severity startingLevel);
|
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:
|
public:
|
||||||
static LogSeverity
|
static LogSeverity
|
||||||
fromSeverity(beast::severities::Severity level);
|
fromSeverity(beast::severities::Severity level);
|
||||||
|
|||||||
@@ -21,11 +21,62 @@
|
|||||||
#define BEAST_UTILITY_JOURNAL_H_INCLUDED
|
#define BEAST_UTILITY_JOURNAL_H_INCLUDED
|
||||||
|
|
||||||
#include <xrpl/beast/utility/instrumentation.h>
|
#include <xrpl/beast/utility/instrumentation.h>
|
||||||
|
#include <rapidjson/document.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <deque>
|
||||||
|
#include <utility>
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
#include <sstream>
|
#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 {
|
namespace beast {
|
||||||
|
|
||||||
/** A namespace for easy access to logging severity values. */
|
/** A namespace for easy access to logging severity values. */
|
||||||
@@ -64,75 +115,111 @@ to_string(Severity severity);
|
|||||||
class Journal
|
class Journal
|
||||||
{
|
{
|
||||||
public:
|
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 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:
|
private:
|
||||||
// Severity level / threshold of a Journal message.
|
// Severity level / threshold of a Journal message.
|
||||||
using Severity = severities::Severity;
|
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
|
// Invariant: m_sink always points to a valid Sink
|
||||||
Sink* m_sink = nullptr;
|
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:
|
public:
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
static void
|
static void
|
||||||
enableStructuredJournal(std::unique_ptr<StructuredJournalImpl> impl)
|
enableStructuredJournal();
|
||||||
{
|
|
||||||
m_structuredJournalImpl = std::move(impl);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
disableStructuredJournal()
|
disableStructuredJournal();
|
||||||
{
|
|
||||||
m_structuredJournalImpl = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
isStructuredJournalEnabled()
|
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Abstraction for the underlying message destination. */
|
/** Abstraction for the underlying message destination. */
|
||||||
class Sink
|
class Sink
|
||||||
@@ -214,25 +301,25 @@ public:
|
|||||||
public:
|
public:
|
||||||
ScopedStream(ScopedStream const& other)
|
ScopedStream(ScopedStream const& other)
|
||||||
: ScopedStream(
|
: ScopedStream(
|
||||||
other.m_attributes ? other.m_attributes->clone() : nullptr,
|
other.m_attributes,
|
||||||
other.m_sink,
|
other.m_sink,
|
||||||
other.m_level)
|
other.m_level)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedStream(
|
ScopedStream(
|
||||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
std::optional<JsonLogAttributes> attributes,
|
||||||
Sink& sink,
|
Sink& sink,
|
||||||
Severity level);
|
Severity level);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
ScopedStream(
|
ScopedStream(
|
||||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
std::optional<JsonLogAttributes> attributes,
|
||||||
Stream const& stream,
|
Stream const& stream,
|
||||||
T const& t);
|
T const& t);
|
||||||
|
|
||||||
ScopedStream(
|
ScopedStream(
|
||||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
std::optional<JsonLogAttributes> attributes,
|
||||||
Stream const& stream,
|
Stream const& stream,
|
||||||
std::ostream& manip(std::ostream&));
|
std::ostream& manip(std::ostream&));
|
||||||
|
|
||||||
@@ -255,7 +342,7 @@ public:
|
|||||||
operator<<(T const& t) const;
|
operator<<(T const& t) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<StructuredLogAttributes> m_attributes;
|
std::optional<JsonLogAttributes> m_attributes;
|
||||||
Sink& m_sink;
|
Sink& m_sink;
|
||||||
Severity const m_level;
|
Severity const m_level;
|
||||||
std::ostringstream mutable m_ostream;
|
std::ostringstream mutable m_ostream;
|
||||||
@@ -291,7 +378,7 @@ public:
|
|||||||
Constructor is inlined so checking active() very inexpensive.
|
Constructor is inlined so checking active() very inexpensive.
|
||||||
*/
|
*/
|
||||||
Stream(
|
Stream(
|
||||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
std::optional<JsonLogAttributes> attributes,
|
||||||
Sink& sink,
|
Sink& sink,
|
||||||
Severity level)
|
Severity level)
|
||||||
: m_attributes(std::move(attributes)), m_sink(sink), m_level(level)
|
: m_attributes(std::move(attributes)), m_sink(sink), m_level(level)
|
||||||
@@ -304,7 +391,7 @@ public:
|
|||||||
/** Construct or copy another Stream. */
|
/** Construct or copy another Stream. */
|
||||||
Stream(Stream const& other)
|
Stream(Stream const& other)
|
||||||
: Stream(
|
: Stream(
|
||||||
other.m_attributes ? other.m_attributes->clone() : nullptr,
|
other.m_attributes,
|
||||||
other.m_sink,
|
other.m_sink,
|
||||||
other.m_level)
|
other.m_level)
|
||||||
{
|
{
|
||||||
@@ -353,7 +440,7 @@ public:
|
|||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<StructuredLogAttributes> m_attributes;
|
std::optional<JsonLogAttributes> m_attributes;
|
||||||
Sink& m_sink;
|
Sink& m_sink;
|
||||||
Severity m_level;
|
Severity m_level;
|
||||||
};
|
};
|
||||||
@@ -372,47 +459,29 @@ public:
|
|||||||
/** Journal has no default constructor. */
|
/** Journal has no default constructor. */
|
||||||
Journal() = delete;
|
Journal() = delete;
|
||||||
|
|
||||||
Journal(Journal const& other) : Journal(other, nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Journal(
|
Journal(
|
||||||
Journal const& other,
|
Journal const& other,
|
||||||
std::unique_ptr<StructuredLogAttributes> attributes)
|
std::optional<JsonLogAttributes> attributes = std::nullopt)
|
||||||
: m_sink(other.m_sink)
|
: m_sink(other.m_sink)
|
||||||
{
|
{
|
||||||
if (attributes)
|
if (attributes.has_value())
|
||||||
m_attributes = std::move(attributes);
|
m_attributes = std::move(attributes.value());
|
||||||
if (other.m_attributes)
|
if (other.m_attributes.has_value())
|
||||||
{
|
{
|
||||||
if (m_attributes)
|
if (m_attributes.has_value())
|
||||||
m_attributes->combine(other.m_attributes);
|
m_attributes = JsonLogAttributes::combine(
|
||||||
|
other.m_attributes->contextValues_,
|
||||||
|
m_attributes->contextValues_
|
||||||
|
);
|
||||||
else
|
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. */
|
/** Create a journal that writes to the specified sink. */
|
||||||
Journal(
|
explicit Journal(
|
||||||
Sink& sink,
|
Sink& sink,
|
||||||
std::string const& name = {},
|
std::string const& name = {},
|
||||||
std::unique_ptr<StructuredLogAttributes> attributes = {})
|
std::optional<JsonLogAttributes> attributes = std::nullopt)
|
||||||
: m_sink(&sink)
|
: m_sink(&sink)
|
||||||
{
|
{
|
||||||
if (attributes)
|
if (attributes)
|
||||||
@@ -425,9 +494,11 @@ public:
|
|||||||
Journal&
|
Journal&
|
||||||
operator=(Journal const& other)
|
operator=(Journal const& other)
|
||||||
{
|
{
|
||||||
|
if (&other == this)
|
||||||
|
return *this;
|
||||||
|
|
||||||
m_sink = other.m_sink;
|
m_sink = other.m_sink;
|
||||||
if (other.m_attributes)
|
m_attributes = other.m_attributes;
|
||||||
m_attributes = other.m_attributes->clone();
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,8 +506,7 @@ public:
|
|||||||
operator=(Journal&& other) noexcept
|
operator=(Journal&& other) noexcept
|
||||||
{
|
{
|
||||||
m_sink = other.m_sink;
|
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;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,7 +522,7 @@ public:
|
|||||||
stream(Severity level) const
|
stream(Severity level) const
|
||||||
{
|
{
|
||||||
return Stream(
|
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.
|
/** Returns `true` if any message would be logged at this severity level.
|
||||||
@@ -470,10 +540,10 @@ public:
|
|||||||
Stream
|
Stream
|
||||||
trace(std::source_location location = std::source_location::current()) const
|
trace(std::source_location location = std::source_location::current()) const
|
||||||
{
|
{
|
||||||
if (m_structuredJournalImpl)
|
if (m_jsonLogsEnabled)
|
||||||
m_structuredJournalImpl->initMessageContext(location);
|
initMessageContext(location);
|
||||||
return {
|
return {
|
||||||
m_attributes ? m_attributes->clone() : nullptr,
|
m_attributes,
|
||||||
*m_sink,
|
*m_sink,
|
||||||
severities::kTrace};
|
severities::kTrace};
|
||||||
}
|
}
|
||||||
@@ -481,10 +551,10 @@ public:
|
|||||||
Stream
|
Stream
|
||||||
debug(std::source_location location = std::source_location::current()) const
|
debug(std::source_location location = std::source_location::current()) const
|
||||||
{
|
{
|
||||||
if (m_structuredJournalImpl)
|
if (m_jsonLogsEnabled)
|
||||||
m_structuredJournalImpl->initMessageContext(location);
|
initMessageContext(location);
|
||||||
return {
|
return {
|
||||||
m_attributes ? m_attributes->clone() : nullptr,
|
m_attributes,
|
||||||
*m_sink,
|
*m_sink,
|
||||||
severities::kDebug};
|
severities::kDebug};
|
||||||
}
|
}
|
||||||
@@ -492,10 +562,10 @@ public:
|
|||||||
Stream
|
Stream
|
||||||
info(std::source_location location = std::source_location::current()) const
|
info(std::source_location location = std::source_location::current()) const
|
||||||
{
|
{
|
||||||
if (m_structuredJournalImpl)
|
if (m_jsonLogsEnabled)
|
||||||
m_structuredJournalImpl->initMessageContext(location);
|
initMessageContext(location);
|
||||||
return {
|
return {
|
||||||
m_attributes ? m_attributes->clone() : nullptr,
|
m_attributes,
|
||||||
*m_sink,
|
*m_sink,
|
||||||
severities::kInfo};
|
severities::kInfo};
|
||||||
}
|
}
|
||||||
@@ -503,10 +573,12 @@ public:
|
|||||||
Stream
|
Stream
|
||||||
warn(std::source_location location = std::source_location::current()) const
|
warn(std::source_location location = std::source_location::current()) const
|
||||||
{
|
{
|
||||||
if (m_structuredJournalImpl)
|
const char* a = "a";
|
||||||
m_structuredJournalImpl->initMessageContext(location);
|
rapidjson::Value v{a, 1};
|
||||||
|
if (m_jsonLogsEnabled)
|
||||||
|
initMessageContext(location);
|
||||||
return {
|
return {
|
||||||
m_attributes ? m_attributes->clone() : nullptr,
|
m_attributes,
|
||||||
*m_sink,
|
*m_sink,
|
||||||
severities::kWarning};
|
severities::kWarning};
|
||||||
}
|
}
|
||||||
@@ -514,10 +586,10 @@ public:
|
|||||||
Stream
|
Stream
|
||||||
error(std::source_location location = std::source_location::current()) const
|
error(std::source_location location = std::source_location::current()) const
|
||||||
{
|
{
|
||||||
if (m_structuredJournalImpl)
|
if (m_jsonLogsEnabled)
|
||||||
m_structuredJournalImpl->initMessageContext(location);
|
initMessageContext(location);
|
||||||
return {
|
return {
|
||||||
m_attributes ? m_attributes->clone() : nullptr,
|
m_attributes,
|
||||||
*m_sink,
|
*m_sink,
|
||||||
severities::kError};
|
severities::kError};
|
||||||
}
|
}
|
||||||
@@ -525,14 +597,25 @@ public:
|
|||||||
Stream
|
Stream
|
||||||
fatal(std::source_location location = std::source_location::current()) const
|
fatal(std::source_location location = std::source_location::current()) const
|
||||||
{
|
{
|
||||||
if (m_structuredJournalImpl)
|
if (m_jsonLogsEnabled)
|
||||||
m_structuredJournalImpl->initMessageContext(location);
|
initMessageContext(location);
|
||||||
return {
|
return {
|
||||||
m_attributes ? m_attributes->clone() : nullptr,
|
m_attributes,
|
||||||
*m_sink,
|
*m_sink,
|
||||||
severities::kFatal};
|
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__
|
#ifndef __INTELLISENSE__
|
||||||
@@ -548,7 +631,7 @@ static_assert(std::is_nothrow_destructible<Journal>::value == true, "");
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Journal::ScopedStream::ScopedStream(
|
Journal::ScopedStream::ScopedStream(
|
||||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
std::optional<JsonLogAttributes> attributes,
|
||||||
Stream const& stream,
|
Stream const& stream,
|
||||||
T const& t)
|
T const& t)
|
||||||
: ScopedStream(std::move(attributes), stream.sink(), stream.level())
|
: ScopedStream(std::move(attributes), stream.sink(), stream.level())
|
||||||
@@ -570,7 +653,7 @@ template <typename T>
|
|||||||
Journal::ScopedStream
|
Journal::ScopedStream
|
||||||
Journal::Stream::operator<<(T const& t) const
|
Journal::Stream::operator<<(T const& t) const
|
||||||
{
|
{
|
||||||
return {m_attributes ? m_attributes->clone() : nullptr, *this, t};
|
return {m_attributes, *this, t};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@@ -642,4 +725,127 @@ using logwstream = basic_logstream<wchar_t>;
|
|||||||
|
|
||||||
} // namespace beast
|
} // 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
|
#endif
|
||||||
|
|||||||
@@ -32,7 +32,6 @@
|
|||||||
#include <xrpl/resource/Fees.h>
|
#include <xrpl/resource/Fees.h>
|
||||||
#include <xrpl/resource/Gossip.h>
|
#include <xrpl/resource/Gossip.h>
|
||||||
#include <xrpl/resource/detail/Import.h>
|
#include <xrpl/resource/detail/Import.h>
|
||||||
#include <xrpl/telemetry/JsonLogs.h>
|
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
#include <xrpl/server/Port.h>
|
#include <xrpl/server/Port.h>
|
||||||
#include <xrpl/server/detail/LowestLayer.h>
|
#include <xrpl/server/detail/LowestLayer.h>
|
||||||
#include <xrpl/server/detail/io_list.h>
|
#include <xrpl/server/detail/io_list.h>
|
||||||
#include <xrpl/telemetry/JsonLogs.h>
|
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
|
||||||
@@ -86,11 +85,11 @@ BasePeer<Handler, Impl>::BasePeer(
|
|||||||
, remote_address_(remote_address)
|
, remote_address_(remote_address)
|
||||||
, j_(journal,
|
, j_(journal,
|
||||||
log::attributes(
|
log::attributes(
|
||||||
{{"PeerID",
|
log::attr("PeerID",
|
||||||
[] {
|
[] {
|
||||||
static std::atomic<unsigned> id{0};
|
static std::atomic<unsigned> id{0};
|
||||||
return "##" + std::to_string(++id) + " ";
|
return "##" + std::to_string(++id) + " ";
|
||||||
}()}}))
|
}())))
|
||||||
, work_(boost::asio::make_work_guard(executor))
|
, work_(boost::asio::make_work_guard(executor))
|
||||||
, strand_(boost::asio::make_strand(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 {
|
namespace ripple {
|
||||||
|
|
||||||
std::unique_ptr<beast::Journal::StructuredLogAttributes>
|
|
||||||
Logs::globalLogAttributes_;
|
|
||||||
|
|
||||||
Logs::Sink::Sink(
|
Logs::Sink::Sink(
|
||||||
std::string const& partition,
|
std::string const& partition,
|
||||||
beast::severities::Severity thresh,
|
beast::severities::Severity thresh,
|
||||||
@@ -162,16 +159,9 @@ Logs::operator[](std::string const& name)
|
|||||||
beast::Journal
|
beast::Journal
|
||||||
Logs::journal(
|
Logs::journal(
|
||||||
std::string const& name,
|
std::string const& name,
|
||||||
std::unique_ptr<beast::Journal::StructuredLogAttributes> attributes)
|
std::optional<beast::Journal::JsonLogAttributes> attributes)
|
||||||
{
|
{
|
||||||
if (globalLogAttributes_)
|
return beast::Journal{get(name), name, std::move(attributes)};
|
||||||
{
|
|
||||||
if (attributes)
|
|
||||||
attributes->combine(globalLogAttributes_);
|
|
||||||
else
|
|
||||||
attributes = globalLogAttributes_->clone();
|
|
||||||
}
|
|
||||||
return beast::Journal(get(name), name, std::move(attributes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
beast::severities::Severity
|
beast::severities::Severity
|
||||||
|
|||||||
@@ -19,13 +19,22 @@
|
|||||||
|
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#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 <ios>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace beast {
|
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 "";
|
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)
|
Journal::Sink::Sink(Severity thresh, bool console)
|
||||||
: thresh_(thresh), m_console(console)
|
: thresh_(thresh), m_console(console)
|
||||||
{
|
{
|
||||||
@@ -153,7 +340,7 @@ Journal::Sink::threshold(Severity thresh)
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
Journal::ScopedStream::ScopedStream(
|
Journal::ScopedStream::ScopedStream(
|
||||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
std::optional<JsonLogAttributes> attributes,
|
||||||
Sink& sink,
|
Sink& sink,
|
||||||
Severity level)
|
Severity level)
|
||||||
: m_attributes(std::move(attributes)), m_sink(sink), m_level(level)
|
: m_attributes(std::move(attributes)), m_sink(sink), m_level(level)
|
||||||
@@ -163,7 +350,7 @@ Journal::ScopedStream::ScopedStream(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Journal::ScopedStream::ScopedStream(
|
Journal::ScopedStream::ScopedStream(
|
||||||
std::unique_ptr<StructuredLogAttributes> attributes,
|
std::optional<JsonLogAttributes> attributes,
|
||||||
Stream const& stream,
|
Stream const& stream,
|
||||||
std::ostream& manip(std::ostream&))
|
std::ostream& manip(std::ostream&))
|
||||||
: ScopedStream(std::move(attributes), stream.sink(), stream.level())
|
: ScopedStream(std::move(attributes), stream.sink(), stream.level())
|
||||||
@@ -177,21 +364,9 @@ Journal::ScopedStream::~ScopedStream()
|
|||||||
if (!s.empty())
|
if (!s.empty())
|
||||||
{
|
{
|
||||||
if (s == "\n")
|
if (s == "\n")
|
||||||
{
|
m_sink.write(m_level, formatLog("", m_level, m_attributes));
|
||||||
if (m_structuredJournalImpl)
|
|
||||||
m_structuredJournalImpl->flush(
|
|
||||||
&m_sink, m_level, "", m_attributes.get());
|
|
||||||
else
|
|
||||||
m_sink.write(m_level, "");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
m_sink.write(m_level, formatLog(s, m_level, m_attributes));
|
||||||
if (m_structuredJournalImpl)
|
|
||||||
m_structuredJournalImpl->flush(
|
|
||||||
&m_sink, m_level, s, m_attributes.get());
|
|
||||||
else
|
|
||||||
m_sink.write(m_level, s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +381,7 @@ Journal::ScopedStream::operator<<(std::ostream& manip(std::ostream&)) const
|
|||||||
Journal::ScopedStream
|
Journal::ScopedStream
|
||||||
Journal::Stream::operator<<(std::ostream& manip(std::ostream&)) const
|
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
|
} // 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);
|
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
|
void
|
||||||
run() override
|
run() override
|
||||||
{
|
{
|
||||||
correct_order();
|
// correct_order();
|
||||||
incorrect_order();
|
// incorrect_order();
|
||||||
thread_specific_storage();
|
// thread_specific_storage();
|
||||||
|
test_yield_and_stop();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
|
|
||||||
#include <xrpl/beast/utility/WrappedSink.h>
|
#include <xrpl/beast/utility/WrappedSink.h>
|
||||||
#include <xrpl/protocol/PublicKey.h>
|
#include <xrpl/protocol/PublicKey.h>
|
||||||
#include <xrpl/telemetry/JsonLogs.h>
|
|
||||||
|
|
||||||
#include <boost/container/flat_map.hpp>
|
#include <boost/container/flat_map.hpp>
|
||||||
#include <boost/container/flat_set.hpp>
|
#include <boost/container/flat_set.hpp>
|
||||||
@@ -284,7 +283,7 @@ struct Peer
|
|||||||
TrustGraph<Peer*>& tg,
|
TrustGraph<Peer*>& tg,
|
||||||
CollectorRefs& c,
|
CollectorRefs& c,
|
||||||
beast::Journal jIn)
|
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)
|
, consensus(s.clock(), *this, j)
|
||||||
, id{i}
|
, id{i}
|
||||||
, key{id, 0}
|
, key{id, 0}
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ include(xrpl_add_test)
|
|||||||
|
|
||||||
# Test requirements.
|
# Test requirements.
|
||||||
find_package(doctest REQUIRED)
|
find_package(doctest REQUIRED)
|
||||||
|
find_package(RapidJSON REQUIRED)
|
||||||
|
|
||||||
# Common library dependencies for the rest of the tests.
|
# Common library dependencies for the rest of the tests.
|
||||||
add_library(xrpl.imports.test INTERFACE)
|
add_library(xrpl.imports.test INTERFACE)
|
||||||
target_link_libraries(xrpl.imports.test INTERFACE doctest::doctest xrpl.libxrpl)
|
target_link_libraries(xrpl.imports.test INTERFACE doctest::doctest rapidjson xrpl.libxrpl)
|
||||||
|
|
||||||
# One test for each module.
|
# One test for each module.
|
||||||
xrpl_add_test(basics)
|
xrpl_add_test(basics)
|
||||||
|
|||||||
@@ -18,9 +18,8 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
#include <xrpl/json/json_reader.h>
|
|
||||||
#include <xrpl/telemetry/JsonLogs.h>
|
|
||||||
|
|
||||||
|
#include <rapidjson/document.h>
|
||||||
#include <doctest/doctest.h>
|
#include <doctest/doctest.h>
|
||||||
|
|
||||||
using namespace ripple;
|
using namespace ripple;
|
||||||
@@ -108,8 +107,7 @@ TEST_CASE("Test format output")
|
|||||||
|
|
||||||
TEST_CASE("Test format output when structured logs are enabled")
|
TEST_CASE("Test format output when structured logs are enabled")
|
||||||
{
|
{
|
||||||
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
|
beast::Journal::enableStructuredJournal();
|
||||||
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
|
|
||||||
|
|
||||||
std::string output;
|
std::string output;
|
||||||
Logs::format(output, "Message", beast::severities::kDebug, "Test");
|
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")
|
TEST_CASE("Enable json logs")
|
||||||
{
|
{
|
||||||
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
|
|
||||||
|
|
||||||
std::stringstream logStream;
|
std::stringstream logStream;
|
||||||
|
|
||||||
MockLogs logs{logStream, beast::severities::kAll};
|
MockLogs logs{logStream, beast::severities::kAll};
|
||||||
@@ -133,78 +129,429 @@ TEST_CASE("Enable json logs")
|
|||||||
|
|
||||||
logStream.str("");
|
logStream.str("");
|
||||||
|
|
||||||
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
|
beast::Journal::enableStructuredJournal();
|
||||||
|
|
||||||
logs.journal("Test").debug() << "\n";
|
logs.journal("Test").debug() << "\n";
|
||||||
|
|
||||||
Json::Reader reader;
|
rapidjson::Document doc;
|
||||||
Json::Value jsonLog;
|
doc.Parse(logStream.str().c_str());
|
||||||
bool result = reader.parse(logStream.str(), jsonLog);
|
|
||||||
|
|
||||||
CHECK(result);
|
CHECK(doc.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
|
||||||
|
|
||||||
CHECK(jsonLog.isObject());
|
CHECK(doc.IsObject());
|
||||||
CHECK(jsonLog.isMember("Message"));
|
CHECK(doc.HasMember("Message"));
|
||||||
CHECK(jsonLog["Message"].isString());
|
CHECK(doc["Message"].IsString());
|
||||||
CHECK(jsonLog["Message"].asString() == "");
|
CHECK(doc["Message"].GetString() == std::string{""});
|
||||||
beast::Journal::disableStructuredJournal();
|
beast::Journal::disableStructuredJournal();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Global attributes")
|
TEST_CASE("Global attributes")
|
||||||
{
|
{
|
||||||
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
|
|
||||||
|
|
||||||
std::stringstream logStream;
|
std::stringstream logStream;
|
||||||
|
|
||||||
MockLogs logs{logStream, beast::severities::kAll};
|
MockLogs logs{logStream, beast::severities::kAll};
|
||||||
|
|
||||||
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
|
beast::Journal::enableStructuredJournal();
|
||||||
MockLogs::setGlobalAttributes(log::attributes({{"Field1", "Value1"}}));
|
beast::Journal::addGlobalAttributes(log::attributes(log::attr("Field1", "Value1")));
|
||||||
|
|
||||||
logs.journal("Test").debug() << "Test";
|
logs.journal("Test").debug() << "Test";
|
||||||
|
|
||||||
Json::Reader reader;
|
rapidjson::Document jsonLog;
|
||||||
Json::Value jsonLog;
|
jsonLog.Parse(logStream.str().c_str());
|
||||||
bool result = reader.parse(logStream.str(), jsonLog);
|
|
||||||
|
|
||||||
CHECK(result);
|
CHECK(jsonLog.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
|
||||||
|
|
||||||
CHECK(jsonLog.isObject());
|
CHECK(jsonLog.IsObject());
|
||||||
CHECK(jsonLog.isMember("Field1"));
|
CHECK(jsonLog.HasMember("Field1"));
|
||||||
CHECK(jsonLog["Field1"].isString());
|
CHECK(jsonLog["Field1"].IsString());
|
||||||
CHECK(jsonLog["Field1"].asString() == "Value1");
|
CHECK(jsonLog["Field1"].GetString() == std::string{"Value1"});
|
||||||
beast::Journal::disableStructuredJournal();
|
beast::Journal::disableStructuredJournal();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Global attributes inheritable")
|
TEST_CASE("Global attributes inheritable")
|
||||||
{
|
{
|
||||||
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
|
|
||||||
|
|
||||||
std::stringstream logStream;
|
std::stringstream logStream;
|
||||||
|
|
||||||
MockLogs logs{logStream, beast::severities::kAll};
|
MockLogs logs{logStream, beast::severities::kAll};
|
||||||
|
|
||||||
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
|
beast::Journal::enableStructuredJournal();
|
||||||
MockLogs::setGlobalAttributes(log::attributes({{"Field1", "Value1"}}));
|
beast::Journal::addGlobalAttributes(log::attributes(log::attr("Field1", "Value1")));
|
||||||
|
|
||||||
logs.journal(
|
logs.journal(
|
||||||
"Test",
|
"Test",
|
||||||
log::attributes({{"Field1", "Value3"}, {"Field2", "Value2"}}))
|
log::attributes(log::attr("Field1", "Value3"), log::attr("Field2", "Value2")))
|
||||||
.debug()
|
.debug()
|
||||||
<< "Test";
|
<< "Test";
|
||||||
|
|
||||||
Json::Reader reader;
|
rapidjson::Document jsonLog;
|
||||||
Json::Value jsonLog;
|
jsonLog.Parse(logStream.str().c_str());
|
||||||
bool result = reader.parse(logStream.str(), jsonLog);
|
|
||||||
|
|
||||||
CHECK(result);
|
CHECK(jsonLog.GetParseError() == rapidjson::ParseErrorCode::kParseErrorNone);
|
||||||
|
|
||||||
CHECK(jsonLog.isObject());
|
CHECK(jsonLog.IsObject());
|
||||||
CHECK(jsonLog.isMember("Field1"));
|
CHECK(jsonLog.HasMember("Field1"));
|
||||||
CHECK(jsonLog["Field1"].isString());
|
CHECK(jsonLog["Field1"].IsString());
|
||||||
// Field1 should be overwritten to Value3
|
// Field1 should be overwritten to Value3
|
||||||
CHECK(jsonLog["Field1"].asString() == "Value3");
|
CHECK(jsonLog["Field1"].GetString() == std::string{"Value3"});
|
||||||
CHECK(jsonLog["Field2"].isString());
|
CHECK(jsonLog["Field2"].IsString());
|
||||||
CHECK(jsonLog["Field2"].asString() == "Value2");
|
CHECK(jsonLog["Field2"].GetString() == std::string{"Value2"});
|
||||||
beast::Journal::disableStructuredJournal();
|
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,
|
bool const validating,
|
||||||
beast::Journal j,
|
beast::Journal j,
|
||||||
std::source_location location)
|
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)
|
, location_(location)
|
||||||
{
|
{
|
||||||
if (!validating && !j.info())
|
if (!validating && !j.info())
|
||||||
|
|||||||
@@ -69,7 +69,6 @@
|
|||||||
#include <xrpl/protocol/Protocol.h>
|
#include <xrpl/protocol/Protocol.h>
|
||||||
#include <xrpl/protocol/STParsedJSON.h>
|
#include <xrpl/protocol/STParsedJSON.h>
|
||||||
#include <xrpl/resource/Fees.h>
|
#include <xrpl/resource/Fees.h>
|
||||||
#include <xrpl/telemetry/JsonLogs.h>
|
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/asio/steady_timer.hpp>
|
#include <boost/asio/steady_timer.hpp>
|
||||||
@@ -835,8 +834,8 @@ public:
|
|||||||
beast::Journal
|
beast::Journal
|
||||||
journal(
|
journal(
|
||||||
std::string const& name,
|
std::string const& name,
|
||||||
std::unique_ptr<beast::Journal::StructuredLogAttributes> attributes =
|
std::optional<beast::Journal::JsonLogAttributes> attributes =
|
||||||
{}) override;
|
std::nullopt) override;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -1220,9 +1219,9 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline)
|
|||||||
<< ", Instance Cookie: "
|
<< ", Instance Cookie: "
|
||||||
<< log::param("InstanceCookie", instanceCookie_);
|
<< log::param("InstanceCookie", instanceCookie_);
|
||||||
|
|
||||||
Logs::setGlobalAttributes(log::attributes(
|
beast::Journal::addGlobalAttributes(log::attributes(
|
||||||
{{"RippledVersion", BuildInfo::getFullVersionString()},
|
log::attr("RippledVersion", BuildInfo::getFullVersionString()),
|
||||||
{"InstanceCookie", to_string(instanceCookie_)}}));
|
log::attr("InstanceCookie", to_string(instanceCookie_))));
|
||||||
|
|
||||||
if (numberOfThreads(*config_) < 2)
|
if (numberOfThreads(*config_) < 2)
|
||||||
{
|
{
|
||||||
@@ -2176,7 +2175,7 @@ ApplicationImp::serverOkay(std::string& reason)
|
|||||||
beast::Journal
|
beast::Journal
|
||||||
ApplicationImp::journal(
|
ApplicationImp::journal(
|
||||||
std::string const& name,
|
std::string const& name,
|
||||||
std::unique_ptr<beast::Journal::StructuredLogAttributes> attributes)
|
std::optional<beast::Journal::JsonLogAttributes> attributes)
|
||||||
{
|
{
|
||||||
return logs_->journal(name, std::move(attributes));
|
return logs_->journal(name, std::move(attributes));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,8 +260,8 @@ public:
|
|||||||
virtual beast::Journal
|
virtual beast::Journal
|
||||||
journal(
|
journal(
|
||||||
std::string const& name,
|
std::string const& name,
|
||||||
std::unique_ptr<beast::Journal::StructuredLogAttributes> attributes =
|
std::optional<beast::Journal::JsonLogAttributes> attributes =
|
||||||
{}) = 0;
|
std::nullopt) = 0;
|
||||||
|
|
||||||
/* Returns the number of file descriptors the application needs */
|
/* Returns the number of file descriptors the application needs */
|
||||||
virtual int
|
virtual int
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
#include <xrpl/basics/Log.h>
|
#include <xrpl/basics/Log.h>
|
||||||
#include <xrpl/beast/core/CurrentThreadName.h>
|
#include <xrpl/beast/core/CurrentThreadName.h>
|
||||||
#include <xrpl/protocol/BuildInfo.h>
|
#include <xrpl/protocol/BuildInfo.h>
|
||||||
#include <xrpl/telemetry/JsonLogs.h>
|
|
||||||
|
|
||||||
#include <boost/asio/io_context.hpp>
|
#include <boost/asio/io_context.hpp>
|
||||||
#include <boost/process/v1/args.hpp>
|
#include <boost/process/v1/args.hpp>
|
||||||
@@ -797,10 +796,10 @@ run(int argc, char** argv)
|
|||||||
|
|
||||||
if (config->LOG_STYLE == LogStyle::Json)
|
if (config->LOG_STYLE == LogStyle::Json)
|
||||||
{
|
{
|
||||||
auto structuredJournal = std::make_unique<log::JsonStructuredJournal>();
|
beast::Journal::enableStructuredJournal();
|
||||||
beast::Journal::enableStructuredJournal(std::move(structuredJournal));
|
beast::Journal::addGlobalAttributes(log::attributes(
|
||||||
Logs::setGlobalAttributes(log::attributes(
|
log::attr("Application", "rippled"),
|
||||||
{{"Application", "rippled"}, {"NetworkID", config->NETWORK_ID}}));
|
log::attr("NetworkID", config->NETWORK_ID)));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto logs = std::make_unique<Logs>(thresh);
|
auto logs = std::make_unique<Logs>(thresh);
|
||||||
|
|||||||
@@ -1190,6 +1190,10 @@ NetworkOPsImp::strOperatingMode(OperatingMode const mode, bool const admin)
|
|||||||
void
|
void
|
||||||
NetworkOPsImp::submitTransaction(std::shared_ptr<STTx const> const& iTrans)
|
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())
|
if (isNeedNetworkLedger())
|
||||||
{
|
{
|
||||||
// Nothing we can do if we've never been in sync
|
// 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
|
bool
|
||||||
NetworkOPsImp::preProcessTransaction(std::shared_ptr<Transaction>& transaction)
|
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());
|
auto const newFlags = app_.getHashRouter().getFlags(transaction->getID());
|
||||||
|
|
||||||
if ((newFlags & HashRouterFlags::BAD) != HashRouterFlags::UNDEFINED)
|
if ((newFlags & HashRouterFlags::BAD) != HashRouterFlags::UNDEFINED)
|
||||||
|
|||||||
@@ -209,10 +209,10 @@ Transactor::Transactor(ApplyContext& ctx)
|
|||||||
: ctx_(ctx)
|
: ctx_(ctx)
|
||||||
, account_(ctx.tx.getAccountID(sfAccount))
|
, account_(ctx.tx.getAccountID(sfAccount))
|
||||||
, j_(ctx.journal,
|
, j_(ctx.journal,
|
||||||
log::attributes({
|
log::attributes(
|
||||||
{"TransactionID", to_string(ctx_.tx.getTransactionID())},
|
log::attr("TransactionID", to_string(ctx_.tx.getTransactionID())),
|
||||||
{"AccountID", to_string(account_)},
|
log::attr("AccountID", to_string(account_))
|
||||||
}))
|
))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,11 @@ public:
|
|||||||
, rules(rules_)
|
, rules(rules_)
|
||||||
, flags(flags_)
|
, flags(flags_)
|
||||||
, parentBatchId(parentBatchId_)
|
, 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(
|
XRPL_ASSERT(
|
||||||
(flags_ & tapBATCH) == tapBATCH, "Batch apply flag should be set");
|
(flags_ & tapBATCH) == tapBATCH, "Batch apply flag should be set");
|
||||||
@@ -101,7 +105,11 @@ public:
|
|||||||
, flags(flags_)
|
, flags(flags_)
|
||||||
, tx(tx_)
|
, tx(tx_)
|
||||||
, parentBatchId(parentBatchId_)
|
, 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(
|
XRPL_ASSERT(
|
||||||
parentBatchId.has_value() == ((flags_ & tapBATCH) == tapBATCH),
|
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.
|
/** Wrap the passed closure with a reference counter.
|
||||||
|
|
||||||
@param closure Closure that accepts Args_t parameters and returns Ret_t.
|
@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/net/IPEndpoint.h>
|
||||||
#include <xrpl/beast/utility/Journal.h>
|
#include <xrpl/beast/utility/Journal.h>
|
||||||
#include <xrpl/protocol/SystemParameters.h> // VFALCO Breaks levelization
|
#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
|
#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);
|
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_;
|
--jq_.nSuspend_;
|
||||||
}
|
}
|
||||||
auto saved = detail::getLocalValues().release();
|
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
|
// That said, since we're outside the Coro's stack, we need to
|
||||||
// decrement the nSuspend that the Coro's call to yield caused.
|
// decrement the nSuspend that the Coro's call to yield caused.
|
||||||
std::lock_guard lock(jq_.m_mutex);
|
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_;
|
--jq_.nSuspend_;
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
finished_ = true;
|
finished_ = true;
|
||||||
|
|||||||
@@ -304,9 +304,9 @@ JobQueue::stop()
|
|||||||
// but there may still be some threads between the return of
|
// but there may still be some threads between the return of
|
||||||
// `Job::doJob` and the return of `JobQueue::processTask`. That is why
|
// `Job::doJob` and the return of `JobQueue::processTask`. That is why
|
||||||
// we must wait on the condition variable to make these assertions.
|
// 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(
|
cv_.wait(
|
||||||
lock, [this] { return m_processCount == 0 && m_jobSet.empty(); });
|
lock, [this] { return m_processCount == 0 && nSuspend_ == 0 && m_jobSet.empty(); });
|
||||||
XRPL_ASSERT(
|
XRPL_ASSERT(
|
||||||
m_processCount == 0,
|
m_processCount == 0,
|
||||||
"ripple::JobQueue::stop : all processes completed");
|
"ripple::JobQueue::stop : all processes completed");
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ ConnectAttempt::ConnectAttempt(
|
|||||||
: Child(overlay)
|
: Child(overlay)
|
||||||
, app_(app)
|
, app_(app)
|
||||||
, id_(id)
|
, id_(id)
|
||||||
, journal_(journal, log::attributes({{"NodeID", id}}))
|
, journal_(journal, log::attributes(log::attr("NodeID", id)))
|
||||||
, remote_endpoint_(remote_endpoint)
|
, remote_endpoint_(remote_endpoint)
|
||||||
, usage_(usage)
|
, usage_(usage)
|
||||||
, strand_(boost::asio::make_strand(io_context))
|
, strand_(boost::asio::make_strand(io_context))
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ OverlayImpl::onHandoff(
|
|||||||
endpoint_type remote_endpoint)
|
endpoint_type remote_endpoint)
|
||||||
{
|
{
|
||||||
auto const id = next_id_++;
|
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;
|
Handoff handoff;
|
||||||
if (processRequest(request, handoff))
|
if (processRequest(request, handoff))
|
||||||
|
|||||||
@@ -85,15 +85,15 @@ PeerImp::PeerImp(
|
|||||||
, journal_(
|
, journal_(
|
||||||
app_.journal("Peer"),
|
app_.journal("Peer"),
|
||||||
log::attributes(
|
log::attributes(
|
||||||
{{"NodeID", id},
|
log::attr("NodeID", id),
|
||||||
{"RemoteAddress", to_string(slot->remote_endpoint())},
|
log::attr("RemoteAddress", to_string(slot->remote_endpoint())),
|
||||||
{"PublicKey", toBase58(TokenType::NodePublic, publicKey)}}))
|
log::attr("PublicKey", toBase58(TokenType::NodePublic, publicKey))))
|
||||||
, p_journal_(
|
, p_journal_(
|
||||||
app_.journal("Protocol"),
|
app_.journal("Protocol"),
|
||||||
log::attributes(
|
log::attributes(
|
||||||
{{"NodeID", id},
|
log::attr("NodeID", id),
|
||||||
{"RemoteAddress", to_string(slot->remote_endpoint())},
|
log::attr("RemoteAddress", to_string(slot->remote_endpoint())),
|
||||||
{"PublicKey", toBase58(TokenType::NodePublic, publicKey)}}))
|
log::attr("PublicKey", toBase58(TokenType::NodePublic, publicKey))))
|
||||||
, stream_ptr_(std::move(stream_ptr))
|
, stream_ptr_(std::move(stream_ptr))
|
||||||
, socket_(stream_ptr_->next_layer().socket())
|
, socket_(stream_ptr_->next_layer().socket())
|
||||||
, stream_(*stream_ptr_)
|
, stream_(*stream_ptr_)
|
||||||
@@ -1392,6 +1392,12 @@ PeerImp::handleTransaction(
|
|||||||
{
|
{
|
||||||
auto stx = std::make_shared<STTx const>(sit);
|
auto stx = std::make_shared<STTx const>(sit);
|
||||||
uint256 txID = stx->getTransactionID();
|
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
|
// Charge strongly for attempting to relay a txn with tfInnerBatchTxn
|
||||||
// LCOV_EXCL_START
|
// LCOV_EXCL_START
|
||||||
|
|||||||
@@ -830,15 +830,15 @@ PeerImp::PeerImp(
|
|||||||
, journal_(
|
, journal_(
|
||||||
app_.journal("Peer"),
|
app_.journal("Peer"),
|
||||||
log::attributes(
|
log::attributes(
|
||||||
{{"NodeID", id},
|
log::attr("NodeID", id),
|
||||||
{"RemoteAddress", to_string(slot->remote_endpoint())},
|
log::attr("RemoteAddress", to_string(slot->remote_endpoint())),
|
||||||
{"PublicKey", toBase58(TokenType::NodePublic, publicKey)}}))
|
log::attr("PublicKey", toBase58(TokenType::NodePublic, publicKey))))
|
||||||
, p_journal_(
|
, p_journal_(
|
||||||
app_.journal("Protocol"),
|
app_.journal("Protocol"),
|
||||||
log::attributes(
|
log::attributes(
|
||||||
{{"NodeID", id},
|
log::attr("NodeID", id),
|
||||||
{"RemoteAddress", to_string(slot->remote_endpoint())},
|
log::attr("RemoteAddress", to_string(slot->remote_endpoint())),
|
||||||
{"PublicKey", toBase58(TokenType::NodePublic, publicKey)}}))
|
log::attr("PublicKey", toBase58(TokenType::NodePublic, publicKey))))
|
||||||
, stream_ptr_(std::move(stream_ptr))
|
, stream_ptr_(std::move(stream_ptr))
|
||||||
, socket_(stream_ptr_->next_layer().socket())
|
, socket_(stream_ptr_->next_layer().socket())
|
||||||
, stream_(*stream_ptr_)
|
, stream_(*stream_ptr_)
|
||||||
|
|||||||
Reference in New Issue
Block a user