mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-04 19:25:51 +00:00
Compare commits
70 Commits
2.6.0-rc2
...
a1q123456/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1aa403ebd1 | ||
|
|
1f6598539a | ||
|
|
b6d01adfda | ||
|
|
f439be39bd | ||
|
|
7c2832161c | ||
|
|
de6ff088a7 | ||
|
|
e46715bbc3 | ||
|
|
2491b28fcd | ||
|
|
e898d98e0a | ||
|
|
0f3becc95a | ||
|
|
fe1e13c3ff | ||
|
|
0dba54bcb6 | ||
|
|
f4c717d392 | ||
|
|
ce18ae9542 | ||
|
|
424f6203c0 | ||
|
|
e401dcb2f1 | ||
|
|
01a4416219 | ||
|
|
b75e7884e7 | ||
|
|
15527ea863 | ||
|
|
e5dbcab3e6 | ||
|
|
d130b68b96 | ||
|
|
1331d6568c | ||
|
|
ce5553c98f | ||
|
|
55fcd4c9a4 | ||
|
|
1da97a4c13 | ||
|
|
f627543a0c | ||
|
|
089aace3b7 | ||
|
|
c85ccd9c66 | ||
|
|
2bb39e8ea1 | ||
|
|
c60a91e36e | ||
|
|
67c1e7ce56 | ||
|
|
1af7e2ba5c | ||
|
|
53ab451b39 | ||
|
|
6ab02caa22 | ||
|
|
f4dde4405c | ||
|
|
284b825a5f | ||
|
|
f7c043bd04 | ||
|
|
dbb14191cb | ||
|
|
37aa933462 | ||
|
|
ddfcf49e2b | ||
|
|
1f3f2a1dc5 | ||
|
|
3cb3966f81 | ||
|
|
71b568d355 | ||
|
|
53c0e7cace | ||
|
|
dc344e4114 | ||
|
|
fbacf83334 | ||
|
|
8f37c8a52e | ||
|
|
98c671cc78 | ||
|
|
1de3fb0450 | ||
|
|
257ea88396 | ||
|
|
6e88693caa | ||
|
|
c4464f5122 | ||
|
|
df07f92ed7 | ||
|
|
bade7a9a10 | ||
|
|
bb7e7ad430 | ||
|
|
57d57705a3 | ||
|
|
6ae1ad0c52 | ||
|
|
e5978a388c | ||
|
|
9d8243200f | ||
|
|
eab74be499 | ||
|
|
27ab6d3ddc | ||
|
|
7fa0a89b0c | ||
|
|
c742c669e7 | ||
|
|
7806cac657 | ||
|
|
ea04c71579 | ||
|
|
3cf201de6a | ||
|
|
9d98389df6 | ||
|
|
f18a37f65d | ||
|
|
0dca5025f1 | ||
|
|
ceb0ce5634 |
@@ -10,9 +10,6 @@ Loop: xrpld.app xrpld.core
|
||||
Loop: xrpld.app xrpld.ledger
|
||||
xrpld.app > xrpld.ledger
|
||||
|
||||
Loop: xrpld.app xrpld.net
|
||||
xrpld.app > xrpld.net
|
||||
|
||||
Loop: xrpld.app xrpld.overlay
|
||||
xrpld.overlay > xrpld.app
|
||||
|
||||
@@ -25,15 +22,9 @@ Loop: xrpld.app xrpld.rpc
|
||||
Loop: xrpld.app xrpld.shamap
|
||||
xrpld.app > xrpld.shamap
|
||||
|
||||
Loop: xrpld.core xrpld.net
|
||||
xrpld.net > xrpld.core
|
||||
|
||||
Loop: xrpld.core xrpld.perflog
|
||||
xrpld.perflog == xrpld.core
|
||||
|
||||
Loop: xrpld.net xrpld.rpc
|
||||
xrpld.rpc ~= xrpld.net
|
||||
|
||||
Loop: xrpld.overlay xrpld.rpc
|
||||
xrpld.rpc ~= xrpld.overlay
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ libxrpl.basics > xrpl.basics
|
||||
libxrpl.crypto > xrpl.basics
|
||||
libxrpl.json > xrpl.basics
|
||||
libxrpl.json > xrpl.json
|
||||
libxrpl.net > xrpl.basics
|
||||
libxrpl.net > xrpl.net
|
||||
libxrpl.protocol > xrpl.basics
|
||||
libxrpl.protocol > xrpl.json
|
||||
libxrpl.protocol > xrpl.protocol
|
||||
@@ -62,9 +64,9 @@ test.jtx > xrpl.basics
|
||||
test.jtx > xrpld.app
|
||||
test.jtx > xrpld.core
|
||||
test.jtx > xrpld.ledger
|
||||
test.jtx > xrpld.net
|
||||
test.jtx > xrpld.rpc
|
||||
test.jtx > xrpl.json
|
||||
test.jtx > xrpl.net
|
||||
test.jtx > xrpl.protocol
|
||||
test.jtx > xrpl.resource
|
||||
test.jtx > xrpl.server
|
||||
@@ -109,7 +111,6 @@ test.rpc > test.toplevel
|
||||
test.rpc > xrpl.basics
|
||||
test.rpc > xrpld.app
|
||||
test.rpc > xrpld.core
|
||||
test.rpc > xrpld.net
|
||||
test.rpc > xrpld.overlay
|
||||
test.rpc > xrpld.rpc
|
||||
test.rpc > xrpl.json
|
||||
@@ -134,6 +135,7 @@ test.toplevel > xrpl.json
|
||||
test.unit_test > xrpl.basics
|
||||
tests.libxrpl > xrpl.basics
|
||||
xrpl.json > xrpl.basics
|
||||
xrpl.net > xrpl.basics
|
||||
xrpl.protocol > xrpl.basics
|
||||
xrpl.protocol > xrpl.json
|
||||
xrpl.resource > xrpl.basics
|
||||
@@ -149,6 +151,7 @@ xrpld.app > xrpld.consensus
|
||||
xrpld.app > xrpld.nodestore
|
||||
xrpld.app > xrpld.perflog
|
||||
xrpld.app > xrpl.json
|
||||
xrpld.app > xrpl.net
|
||||
xrpld.app > xrpl.protocol
|
||||
xrpld.app > xrpl.resource
|
||||
xrpld.conditions > xrpl.basics
|
||||
@@ -158,14 +161,11 @@ xrpld.consensus > xrpl.json
|
||||
xrpld.consensus > xrpl.protocol
|
||||
xrpld.core > xrpl.basics
|
||||
xrpld.core > xrpl.json
|
||||
xrpld.core > xrpl.net
|
||||
xrpld.core > xrpl.protocol
|
||||
xrpld.ledger > xrpl.basics
|
||||
xrpld.ledger > xrpl.json
|
||||
xrpld.ledger > xrpl.protocol
|
||||
xrpld.net > xrpl.basics
|
||||
xrpld.net > xrpl.json
|
||||
xrpld.net > xrpl.protocol
|
||||
xrpld.net > xrpl.resource
|
||||
xrpld.nodestore > xrpl.basics
|
||||
xrpld.nodestore > xrpld.core
|
||||
xrpld.nodestore > xrpld.unity
|
||||
@@ -189,6 +189,7 @@ xrpld.rpc > xrpld.core
|
||||
xrpld.rpc > xrpld.ledger
|
||||
xrpld.rpc > xrpld.nodestore
|
||||
xrpld.rpc > xrpl.json
|
||||
xrpld.rpc > xrpl.net
|
||||
xrpld.rpc > xrpl.protocol
|
||||
xrpld.rpc > xrpl.resource
|
||||
xrpld.rpc > xrpl.server
|
||||
|
||||
@@ -99,6 +99,15 @@ target_link_libraries(xrpl.libxrpl.protocol PUBLIC
|
||||
add_module(xrpl resource)
|
||||
target_link_libraries(xrpl.libxrpl.resource PUBLIC xrpl.libxrpl.protocol)
|
||||
|
||||
# Level 06
|
||||
add_module(xrpl net)
|
||||
target_link_libraries(xrpl.libxrpl.net PUBLIC
|
||||
xrpl.libxrpl.basics
|
||||
xrpl.libxrpl.json
|
||||
xrpl.libxrpl.protocol
|
||||
xrpl.libxrpl.resource
|
||||
)
|
||||
|
||||
add_module(xrpl server)
|
||||
target_link_libraries(xrpl.libxrpl.server PUBLIC xrpl.libxrpl.protocol)
|
||||
|
||||
@@ -121,6 +130,7 @@ target_link_modules(xrpl PUBLIC
|
||||
protocol
|
||||
resource
|
||||
server
|
||||
net
|
||||
)
|
||||
|
||||
# All headers in libxrpl are in modules.
|
||||
|
||||
@@ -19,6 +19,7 @@ install (
|
||||
xrpl.libxrpl.protocol
|
||||
xrpl.libxrpl.resource
|
||||
xrpl.libxrpl.server
|
||||
xrpl.libxrpl.net
|
||||
xrpl.libxrpl
|
||||
antithesis-sdk-cpp
|
||||
EXPORT RippleExports
|
||||
|
||||
@@ -26,10 +26,13 @@
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
@@ -68,11 +71,10 @@ private:
|
||||
operator=(Sink const&) = delete;
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text)
|
||||
override;
|
||||
write(beast::severities::Severity level, std::string_view text) override;
|
||||
|
||||
void
|
||||
writeAlways(beast::severities::Severity level, std::string const& text)
|
||||
writeAlways(beast::severities::Severity level, std::string_view text)
|
||||
override;
|
||||
};
|
||||
|
||||
@@ -130,27 +132,8 @@ private:
|
||||
Does nothing if there is no associated system file.
|
||||
*/
|
||||
void
|
||||
write(char const* text);
|
||||
write(std::string_view str);
|
||||
|
||||
/** write to the log file and append an end of line marker.
|
||||
Does nothing if there is no associated system file.
|
||||
*/
|
||||
void
|
||||
writeln(char const* text);
|
||||
|
||||
/** Write to the log file using std::string. */
|
||||
/** @{ */
|
||||
void
|
||||
write(std::string const& str)
|
||||
{
|
||||
write(str.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
writeln(std::string const& str)
|
||||
{
|
||||
writeln(str.c_str());
|
||||
}
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
@@ -158,7 +141,7 @@ private:
|
||||
boost::filesystem::path m_path;
|
||||
};
|
||||
|
||||
std::mutex mutable mutex_;
|
||||
std::mutex mutable sinkSetMutex_;
|
||||
std::map<
|
||||
std::string,
|
||||
std::unique_ptr<beast::Journal::Sink>,
|
||||
@@ -168,6 +151,15 @@ private:
|
||||
File file_;
|
||||
bool silent_ = false;
|
||||
|
||||
// Batching members
|
||||
mutable std::mutex batchMutex_;
|
||||
static constexpr size_t BATCH_BUFFER_SIZE = 64 * 1024; // 64KB buffer
|
||||
std::array<char, BATCH_BUFFER_SIZE> batchBuffer_{};
|
||||
std::span<char> writeBuffer_; // Points to available write space
|
||||
std::span<char> readBuffer_; // Points to data ready to flush
|
||||
std::chrono::steady_clock::time_point lastFlush_ =
|
||||
std::chrono::steady_clock::now();
|
||||
|
||||
public:
|
||||
Logs(beast::severities::Severity level);
|
||||
|
||||
@@ -175,7 +167,7 @@ public:
|
||||
Logs&
|
||||
operator=(Logs const&) = delete;
|
||||
|
||||
virtual ~Logs() = default;
|
||||
virtual ~Logs(); // Need to flush on destruction
|
||||
|
||||
bool
|
||||
open(boost::filesystem::path const& pathToLogFile);
|
||||
@@ -186,8 +178,19 @@ public:
|
||||
beast::Journal::Sink&
|
||||
operator[](std::string const& name);
|
||||
|
||||
template <typename AttributesFactory>
|
||||
beast::Journal
|
||||
journal(std::string const& name);
|
||||
journal(std::string const& name, AttributesFactory&& factory)
|
||||
{
|
||||
return beast::Journal{
|
||||
get(name), name, std::forward<AttributesFactory>(factory)};
|
||||
}
|
||||
|
||||
beast::Journal
|
||||
journal(std::string const& name)
|
||||
{
|
||||
return beast::Journal{get(name), name};
|
||||
}
|
||||
|
||||
beast::severities::Severity
|
||||
threshold() const;
|
||||
@@ -202,12 +205,15 @@ public:
|
||||
write(
|
||||
beast::severities::Severity level,
|
||||
std::string const& partition,
|
||||
std::string const& text,
|
||||
std::string_view text,
|
||||
bool console);
|
||||
|
||||
std::string
|
||||
rotate();
|
||||
|
||||
void
|
||||
flushBatch();
|
||||
|
||||
/**
|
||||
* Set flag to write logs to stderr (false) or not (true).
|
||||
*
|
||||
@@ -237,6 +243,13 @@ public:
|
||||
static LogSeverity
|
||||
fromString(std::string const& s);
|
||||
|
||||
static void
|
||||
format(
|
||||
std::string& output,
|
||||
std::string_view message,
|
||||
beast::severities::Severity severity,
|
||||
std::string const& partition);
|
||||
|
||||
private:
|
||||
enum {
|
||||
// Maximum line length for log messages.
|
||||
@@ -244,12 +257,8 @@ private:
|
||||
maximumMessageCharacters = 12 * 1024
|
||||
};
|
||||
|
||||
static void
|
||||
format(
|
||||
std::string& output,
|
||||
std::string const& message,
|
||||
beast::severities::Severity severity,
|
||||
std::string const& partition);
|
||||
void
|
||||
flushBatchUnsafe();
|
||||
};
|
||||
|
||||
// Wraps a Journal::Stream to skip evaluation of
|
||||
|
||||
@@ -22,10 +22,254 @@
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <charconv>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <source_location>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#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&);
|
||||
};
|
||||
|
||||
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 ripple::log
|
||||
|
||||
namespace beast {
|
||||
|
||||
namespace detail {
|
||||
|
||||
class SimpleJsonWriter
|
||||
{
|
||||
public:
|
||||
explicit SimpleJsonWriter(std::string& buffer) : buffer_(buffer)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
startObject() const
|
||||
{
|
||||
buffer_.push_back('{');
|
||||
}
|
||||
void
|
||||
endObject() const
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
if (buffer_.back() == ',')
|
||||
buffer_.pop_back();
|
||||
buffer_.append("},"sv);
|
||||
}
|
||||
void
|
||||
writeKey(std::string_view key) const
|
||||
{
|
||||
writeString(key);
|
||||
buffer_.back() = ':';
|
||||
}
|
||||
void
|
||||
startArray() const
|
||||
{
|
||||
buffer_.push_back('[');
|
||||
}
|
||||
void
|
||||
endArray() const
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
if (buffer_.back() == ',')
|
||||
buffer_.pop_back();
|
||||
buffer_.append("],"sv);
|
||||
}
|
||||
void
|
||||
writeString(std::string_view str) const
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
buffer_.push_back('"');
|
||||
escape(str, buffer_);
|
||||
buffer_.append("\","sv);
|
||||
}
|
||||
std::string_view
|
||||
writeInt(std::int32_t val) const
|
||||
{
|
||||
return pushNumber(val, buffer_);
|
||||
}
|
||||
std::string_view
|
||||
writeInt(std::int64_t val) const
|
||||
{
|
||||
return pushNumber(val, buffer_);
|
||||
}
|
||||
std::string_view
|
||||
writeUInt(std::uint32_t val) const
|
||||
{
|
||||
return pushNumber(val, buffer_);
|
||||
}
|
||||
std::string_view
|
||||
writeUInt(std::uint64_t val) const
|
||||
{
|
||||
return pushNumber(val, buffer_);
|
||||
}
|
||||
std::string_view
|
||||
writeDouble(double val) const
|
||||
{
|
||||
return pushNumber(val, buffer_);
|
||||
}
|
||||
std::string_view
|
||||
writeBool(bool val) const
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
auto str = val ? "true,"sv : "false,"sv;
|
||||
buffer_.append(str);
|
||||
return str;
|
||||
}
|
||||
void
|
||||
writeNull() const
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
buffer_.append("null,"sv);
|
||||
}
|
||||
void
|
||||
writeRaw(std::string_view str) const
|
||||
{
|
||||
buffer_.append(str);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string_view
|
||||
finish()
|
||||
{
|
||||
return std::string_view{buffer_.c_str(), buffer_.size() - 1};
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static std::string_view
|
||||
pushNumber(T val, std::string& str)
|
||||
{
|
||||
thread_local char buffer[128];
|
||||
auto result = std::to_chars(std::begin(buffer), std::end(buffer), val);
|
||||
auto ptr = result.ptr;
|
||||
*ptr = ',';
|
||||
auto len = ptr - std::begin(buffer);
|
||||
str.append(buffer, len + 1);
|
||||
return {buffer, static_cast<size_t>(len)};
|
||||
}
|
||||
|
||||
static void
|
||||
escape(std::string_view str, std::string& buffer)
|
||||
{
|
||||
static constexpr char HEX[] = "0123456789ABCDEF";
|
||||
|
||||
char const* p = str.data();
|
||||
char const* end = p + str.size();
|
||||
char const* chunk = p;
|
||||
|
||||
while (p < end)
|
||||
{
|
||||
auto c = static_cast<unsigned char>(*p);
|
||||
|
||||
// JSON requires escaping for <0x20 and the two specials below.
|
||||
bool needsEscape = (c < 0x20) || (c == '"') || (c == '\\');
|
||||
|
||||
if (!needsEscape)
|
||||
{
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Flush the preceding safe run in one go.
|
||||
if (chunk != p)
|
||||
buffer.append(chunk, p - chunk);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
buffer.append("\\\"", 2);
|
||||
break;
|
||||
case '\\':
|
||||
buffer.append("\\\\", 2);
|
||||
break;
|
||||
case '\b':
|
||||
buffer.append("\\b", 2);
|
||||
break;
|
||||
case '\f':
|
||||
buffer.append("\\f", 2);
|
||||
break;
|
||||
case '\n':
|
||||
buffer.append("\\n", 2);
|
||||
break;
|
||||
case '\r':
|
||||
buffer.append("\\r", 2);
|
||||
break;
|
||||
case '\t':
|
||||
buffer.append("\\t", 2);
|
||||
break;
|
||||
default: {
|
||||
// Other C0 controls -> \u00XX (JSON compliant)
|
||||
char buf[6]{
|
||||
'\\', 'u', '0', '0', HEX[(c >> 4) & 0xF], HEX[c & 0xF]};
|
||||
buffer.append(buf, 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++p;
|
||||
chunk = p;
|
||||
}
|
||||
|
||||
// Flush trailing safe run
|
||||
if (chunk != p)
|
||||
buffer.append(chunk, p - chunk);
|
||||
}
|
||||
|
||||
std::string& buffer_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/** A namespace for easy access to logging severity values. */
|
||||
namespace severities {
|
||||
/** Severity level / threshold of a Journal message. */
|
||||
@@ -42,6 +286,9 @@ enum Severity {
|
||||
kDisabled,
|
||||
kNone = kDisabled
|
||||
};
|
||||
|
||||
std::string_view
|
||||
to_string(Severity severity);
|
||||
} // namespace severities
|
||||
|
||||
/** A generic endpoint for log messages.
|
||||
@@ -59,18 +306,80 @@ enum Severity {
|
||||
class Journal
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
friend std::ostream&
|
||||
ripple::log::operator<<(
|
||||
std::ostream& os,
|
||||
ripple::log::LogField<T> const& param);
|
||||
|
||||
template <typename T>
|
||||
friend std::ostream&
|
||||
ripple::log::operator<<(
|
||||
std::ostream& os,
|
||||
ripple::log::LogParameter<T> const& param);
|
||||
|
||||
class Sink;
|
||||
|
||||
class JsonLogContext
|
||||
{
|
||||
std::string buffer_;
|
||||
detail::SimpleJsonWriter messageParamsWriter_;
|
||||
|
||||
public:
|
||||
JsonLogContext() : messageParamsWriter_(buffer_)
|
||||
{
|
||||
buffer_.reserve(1024 * 5);
|
||||
}
|
||||
|
||||
detail::SimpleJsonWriter&
|
||||
writer()
|
||||
{
|
||||
return messageParamsWriter_;
|
||||
}
|
||||
|
||||
void
|
||||
reset(
|
||||
std::source_location location,
|
||||
severities::Severity severity,
|
||||
std::string_view moduleName,
|
||||
std::string_view journalAttributesJson) noexcept;
|
||||
};
|
||||
|
||||
private:
|
||||
// Severity level / threshold of a Journal message.
|
||||
using Severity = severities::Severity;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_attributesJson;
|
||||
static std::string globalLogAttributesJson_;
|
||||
static std::shared_mutex globalLogAttributesMutex_;
|
||||
static bool m_jsonLogsEnabled;
|
||||
|
||||
static thread_local JsonLogContext currentJsonLogContext_;
|
||||
|
||||
// Invariant: m_sink always points to a valid Sink
|
||||
Sink* m_sink;
|
||||
Sink* m_sink = nullptr;
|
||||
|
||||
void
|
||||
initMessageContext(
|
||||
std::source_location location,
|
||||
severities::Severity severity) const;
|
||||
|
||||
static std::string_view
|
||||
formatLog(std::string const& message);
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
enableStructuredJournal();
|
||||
|
||||
static void
|
||||
disableStructuredJournal();
|
||||
|
||||
static bool
|
||||
isStructuredJournalEnabled();
|
||||
|
||||
/** Abstraction for the underlying message destination. */
|
||||
class Sink
|
||||
{
|
||||
@@ -111,7 +420,7 @@ public:
|
||||
level is below the current threshold().
|
||||
*/
|
||||
virtual void
|
||||
write(Severity level, std::string const& text) = 0;
|
||||
write(Severity level, std::string_view text) = 0;
|
||||
|
||||
/** Bypass filter and write text to the sink at the specified severity.
|
||||
* Always write the message, but maintain the same formatting as if
|
||||
@@ -121,7 +430,7 @@ public:
|
||||
* @param text Text to write to sink.
|
||||
*/
|
||||
virtual void
|
||||
writeAlways(Severity level, std::string const& text) = 0;
|
||||
writeAlways(Severity level, std::string_view text) = 0;
|
||||
|
||||
private:
|
||||
Severity thresh_;
|
||||
@@ -287,11 +596,70 @@ public:
|
||||
/** Journal has no default constructor. */
|
||||
Journal() = delete;
|
||||
|
||||
/** Create a journal that writes to the specified sink. */
|
||||
explicit Journal(Sink& sink) : m_sink(&sink)
|
||||
Journal(Journal const& other)
|
||||
: m_name(other.m_name)
|
||||
, m_attributesJson(other.m_attributesJson)
|
||||
, m_sink(other.m_sink)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename TAttributesFactory>
|
||||
Journal(Journal const& other, TAttributesFactory&& attributesFactory)
|
||||
: m_name(other.m_name), m_sink(other.m_sink)
|
||||
{
|
||||
std::string buffer{other.m_attributesJson};
|
||||
detail::SimpleJsonWriter writer{buffer};
|
||||
if (other.m_attributesJson.empty())
|
||||
{
|
||||
writer.startObject();
|
||||
}
|
||||
attributesFactory(writer);
|
||||
m_attributesJson = std::move(buffer);
|
||||
}
|
||||
|
||||
/** Create a journal that writes to the specified sink. */
|
||||
explicit Journal(Sink& sink, std::string const& name = {})
|
||||
: m_name(name), m_sink(&sink)
|
||||
{
|
||||
}
|
||||
|
||||
/** Create a journal that writes to the specified sink. */
|
||||
template <typename TAttributesFactory>
|
||||
explicit Journal(
|
||||
Sink& sink,
|
||||
std::string const& name,
|
||||
TAttributesFactory&& attributesFactory)
|
||||
: m_name(name), m_sink(&sink)
|
||||
{
|
||||
std::string buffer;
|
||||
buffer.reserve(128);
|
||||
detail::SimpleJsonWriter writer{buffer};
|
||||
writer.startObject();
|
||||
attributesFactory(writer);
|
||||
m_attributesJson = std::move(buffer);
|
||||
}
|
||||
|
||||
Journal&
|
||||
operator=(Journal const& other)
|
||||
{
|
||||
if (&other == this)
|
||||
return *this; // LCOV_EXCL_LINE
|
||||
|
||||
m_sink = other.m_sink;
|
||||
m_name = other.m_name;
|
||||
m_attributesJson = other.m_attributesJson;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Journal&
|
||||
operator=(Journal&& other) noexcept
|
||||
{
|
||||
m_sink = other.m_sink;
|
||||
m_name = std::move(other.m_name);
|
||||
m_attributesJson = std::move(other.m_attributesJson);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Returns the Sink associated with this Journal. */
|
||||
Sink&
|
||||
sink() const
|
||||
@@ -301,8 +669,12 @@ public:
|
||||
|
||||
/** Returns a stream for this sink, with the specified severity level. */
|
||||
Stream
|
||||
stream(Severity level) const
|
||||
stream(
|
||||
Severity level,
|
||||
std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location, level);
|
||||
return Stream(*m_sink, level);
|
||||
}
|
||||
|
||||
@@ -319,41 +691,75 @@ public:
|
||||
/** Severity stream access functions. */
|
||||
/** @{ */
|
||||
Stream
|
||||
trace() const
|
||||
trace(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location, severities::kTrace);
|
||||
return {*m_sink, severities::kTrace};
|
||||
}
|
||||
|
||||
Stream
|
||||
debug() const
|
||||
debug(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location, severities::kDebug);
|
||||
return {*m_sink, severities::kDebug};
|
||||
}
|
||||
|
||||
Stream
|
||||
info() const
|
||||
info(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location, severities::kInfo);
|
||||
return {*m_sink, severities::kInfo};
|
||||
}
|
||||
|
||||
Stream
|
||||
warn() const
|
||||
warn(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location, severities::kWarning);
|
||||
return {*m_sink, severities::kWarning};
|
||||
}
|
||||
|
||||
Stream
|
||||
error() const
|
||||
error(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location, severities::kError);
|
||||
return {*m_sink, severities::kError};
|
||||
}
|
||||
|
||||
Stream
|
||||
fatal() const
|
||||
fatal(std::source_location location = std::source_location::current()) const
|
||||
{
|
||||
if (m_jsonLogsEnabled)
|
||||
initMessageContext(location, severities::kFatal);
|
||||
return {*m_sink, severities::kFatal};
|
||||
}
|
||||
/** @} */
|
||||
|
||||
static void
|
||||
resetGlobalAttributes()
|
||||
{
|
||||
std::unique_lock lock(globalLogAttributesMutex_);
|
||||
globalLogAttributesJson_.clear();
|
||||
}
|
||||
|
||||
template <typename TAttributesFactory>
|
||||
static void
|
||||
addGlobalAttributes(TAttributesFactory&& factory)
|
||||
{
|
||||
std::unique_lock lock(globalLogAttributesMutex_);
|
||||
globalLogAttributesJson_.reserve(128);
|
||||
auto isEmpty = globalLogAttributesJson_.empty();
|
||||
detail::SimpleJsonWriter writer{globalLogAttributesJson_};
|
||||
if (isEmpty)
|
||||
{
|
||||
writer.startObject();
|
||||
}
|
||||
factory(writer);
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef __INTELLISENSE__
|
||||
@@ -368,7 +774,7 @@ static_assert(std::is_nothrow_destructible<Journal>::value == true, "");
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename T>
|
||||
Journal::ScopedStream::ScopedStream(Journal::Stream const& stream, T const& t)
|
||||
Journal::ScopedStream::ScopedStream(Stream const& stream, T const& t)
|
||||
: ScopedStream(stream.sink(), stream.level())
|
||||
{
|
||||
m_ostream << t;
|
||||
@@ -388,7 +794,7 @@ template <typename T>
|
||||
Journal::ScopedStream
|
||||
Journal::Stream::operator<<(T const& t) const
|
||||
{
|
||||
return ScopedStream(*this, t);
|
||||
return {*this, t};
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
@@ -460,4 +866,206 @@ using logwstream = basic_logstream<wchar_t>;
|
||||
|
||||
} // namespace beast
|
||||
|
||||
namespace ripple::log {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
concept ToCharsFormattable = requires(T val) {
|
||||
{
|
||||
to_chars(std::declval<char*>(), std::declval<char*>(), val)
|
||||
} -> std::convertible_to<std::to_chars_result>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
concept StreamFormattable = requires(T val) {
|
||||
{
|
||||
std::declval<std::ostream&>() << val
|
||||
} -> std::convertible_to<std::ostream&>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
setJsonValue(
|
||||
beast::detail::SimpleJsonWriter& writer,
|
||||
char const* name,
|
||||
T&& value,
|
||||
std::ostream* outStream)
|
||||
{
|
||||
using ValueType = std::decay_t<T>;
|
||||
writer.writeKey(name);
|
||||
if constexpr (std::is_same_v<ValueType, bool>)
|
||||
{
|
||||
auto sv = writer.writeBool(value);
|
||||
if (outStream)
|
||||
{
|
||||
outStream->write(sv.data(), sv.size());
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_integral_v<ValueType>)
|
||||
{
|
||||
std::string_view sv;
|
||||
if constexpr (std::is_signed_v<ValueType>)
|
||||
{
|
||||
if constexpr (sizeof(ValueType) > 4)
|
||||
{
|
||||
sv = writer.writeInt(static_cast<std::int64_t>(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
sv = writer.writeInt(static_cast<std::int32_t>(value));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (sizeof(ValueType) > 4)
|
||||
{
|
||||
sv = writer.writeUInt(static_cast<std::uint64_t>(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
sv = writer.writeUInt(static_cast<std::uint32_t>(value));
|
||||
}
|
||||
}
|
||||
if (outStream)
|
||||
{
|
||||
outStream->write(sv.data(), sv.size());
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_floating_point_v<ValueType>)
|
||||
{
|
||||
auto sv = writer.writeDouble(value);
|
||||
|
||||
if (outStream)
|
||||
{
|
||||
outStream->write(sv.data(), sv.size());
|
||||
}
|
||||
}
|
||||
else if constexpr (
|
||||
std::is_same_v<ValueType, char const*> ||
|
||||
std::is_same_v<ValueType, char*>)
|
||||
{
|
||||
writer.writeString(value);
|
||||
if (outStream)
|
||||
{
|
||||
outStream->write(value, std::strlen(value));
|
||||
}
|
||||
}
|
||||
else if constexpr (
|
||||
std::is_same_v<ValueType, std::string> ||
|
||||
std::is_same_v<ValueType, std::string_view>)
|
||||
{
|
||||
writer.writeString(value);
|
||||
if (outStream)
|
||||
{
|
||||
outStream->write(value.data(), value.size());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (ToCharsFormattable<ValueType>)
|
||||
{
|
||||
char buffer[1024];
|
||||
std::to_chars_result result =
|
||||
to_chars(std::begin(buffer), std::end(buffer), value);
|
||||
if (result.ec == std::errc{})
|
||||
{
|
||||
std::string_view sv{std::begin(buffer), result.ptr};
|
||||
writer.writeString(sv);
|
||||
if (outStream)
|
||||
{
|
||||
outStream->write(sv.data(), sv.size());
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (StreamFormattable<ValueType>)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss.imbue(std::locale::classic());
|
||||
oss << value;
|
||||
|
||||
auto str = oss.str();
|
||||
|
||||
writer.writeString(str);
|
||||
|
||||
if (outStream)
|
||||
{
|
||||
outStream->write(
|
||||
str.c_str(), static_cast<std::streamsize>(str.size()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static_assert(
|
||||
ToCharsFormattable<ValueType> || StreamFormattable<ValueType>);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, LogParameter<T> const& param)
|
||||
{
|
||||
if (!beast::Journal::m_jsonLogsEnabled)
|
||||
{
|
||||
os << param.value_;
|
||||
return os;
|
||||
}
|
||||
detail::setJsonValue(
|
||||
beast::Journal::currentJsonLogContext_.writer(),
|
||||
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_.writer(),
|
||||
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]] auto
|
||||
attributes(Pair&&... pairs)
|
||||
{
|
||||
return [&](beast::detail::SimpleJsonWriter& writer) {
|
||||
(detail::setJsonValue(writer, pairs.first, pairs.second, nullptr), ...);
|
||||
};
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
} // namespace ripple::log
|
||||
|
||||
#endif
|
||||
|
||||
@@ -88,17 +88,17 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text) override
|
||||
write(beast::severities::Severity level, std::string_view text) override
|
||||
{
|
||||
using beast::Journal;
|
||||
sink_.write(level, prefix_ + text);
|
||||
sink_.write(level, prefix_ + std::string{text});
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(severities::Severity level, std::string const& text) override
|
||||
writeAlways(severities::Severity level, std::string_view text) override
|
||||
{
|
||||
using beast::Journal;
|
||||
sink_.writeAlways(level, prefix_ + text);
|
||||
sink_.writeAlways(level, prefix_ + std::string{text});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
#ifndef RIPPLE_NET_HTTPCLIENT_H_INCLUDED
|
||||
#define RIPPLE_NET_HTTPCLIENT_H_INCLUDED
|
||||
|
||||
#include <xrpld/core/Config.h>
|
||||
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
@@ -44,7 +43,11 @@ public:
|
||||
static constexpr auto maxClientHeaderBytes = kilobytes(32);
|
||||
|
||||
static void
|
||||
initializeSSLContext(Config const& config, beast::Journal j);
|
||||
initializeSSLContext(
|
||||
std::string const& sslVerifyDir,
|
||||
std::string const& sslVerifyFile,
|
||||
bool sslVerify,
|
||||
beast::Journal j);
|
||||
|
||||
static void
|
||||
get(bool bSSL,
|
||||
@@ -20,11 +20,10 @@
|
||||
#ifndef RIPPLE_NET_HTTPCLIENTSSLCONTEXT_H_INCLUDED
|
||||
#define RIPPLE_NET_HTTPCLIENTSSLCONTEXT_H_INCLUDED
|
||||
|
||||
#include <xrpld/core/Config.h>
|
||||
#include <xrpld/net/RegisterSSLCerts.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/net/RegisterSSLCerts.h>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
@@ -37,31 +36,33 @@ class HTTPClientSSLContext
|
||||
{
|
||||
public:
|
||||
explicit HTTPClientSSLContext(
|
||||
Config const& config,
|
||||
std::string const& sslVerifyDir,
|
||||
std::string const& sslVerifyFile,
|
||||
bool sslVerify,
|
||||
beast::Journal j,
|
||||
boost::asio::ssl::context_base::method method =
|
||||
boost::asio::ssl::context::sslv23)
|
||||
: ssl_context_{method}, j_(j), verify_{config.SSL_VERIFY}
|
||||
: ssl_context_{method}, j_(j), verify_{sslVerify}
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
if (config.SSL_VERIFY_FILE.empty())
|
||||
if (sslVerifyFile.empty())
|
||||
{
|
||||
registerSSLCerts(ssl_context_, ec, j_);
|
||||
|
||||
if (ec && config.SSL_VERIFY_DIR.empty())
|
||||
if (ec && sslVerifyDir.empty())
|
||||
Throw<std::runtime_error>(boost::str(
|
||||
boost::format("Failed to set_default_verify_paths: %s") %
|
||||
ec.message()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ssl_context_.load_verify_file(config.SSL_VERIFY_FILE);
|
||||
ssl_context_.load_verify_file(sslVerifyFile);
|
||||
}
|
||||
|
||||
if (!config.SSL_VERIFY_DIR.empty())
|
||||
if (!sslVerifyDir.empty())
|
||||
{
|
||||
ssl_context_.add_verify_path(config.SSL_VERIFY_DIR, ec);
|
||||
ssl_context_.add_verify_path(sslVerifyDir, ec);
|
||||
|
||||
if (ec)
|
||||
Throw<std::runtime_error>(boost::str(
|
||||
@@ -47,7 +47,6 @@ protected:
|
||||
Port const& port_;
|
||||
Handler& handler_;
|
||||
endpoint_type remote_address_;
|
||||
beast::WrappedSink sink_;
|
||||
beast::Journal const j_;
|
||||
|
||||
boost::asio::executor_work_guard<boost::asio::executor> work_;
|
||||
@@ -84,15 +83,15 @@ BasePeer<Handler, Impl>::BasePeer(
|
||||
: port_(port)
|
||||
, handler_(handler)
|
||||
, remote_address_(remote_address)
|
||||
, sink_(
|
||||
journal.sink(),
|
||||
[] {
|
||||
static std::atomic<unsigned> id{0};
|
||||
return "##" + std::to_string(++id) + " ";
|
||||
}())
|
||||
, j_(sink_)
|
||||
, work_(executor)
|
||||
, strand_(executor)
|
||||
, j_(journal,
|
||||
log::attributes(log::attr(
|
||||
"PeerID",
|
||||
[] {
|
||||
static std::atomic<unsigned> id{0};
|
||||
return "##" + std::to_string(++id) + " ";
|
||||
}())))
|
||||
, work_(boost::asio::make_work_guard(executor))
|
||||
, strand_(boost::asio::make_strand(executor))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,11 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace {
|
||||
constexpr auto FLUSH_INTERVAL =
|
||||
std::chrono::milliseconds(10); // Max delay before flush
|
||||
}
|
||||
|
||||
Logs::Sink::Sink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity thresh,
|
||||
@@ -47,7 +52,7 @@ Logs::Sink::Sink(
|
||||
}
|
||||
|
||||
void
|
||||
Logs::Sink::write(beast::severities::Severity level, std::string const& text)
|
||||
Logs::Sink::write(beast::severities::Severity level, std::string_view text)
|
||||
{
|
||||
if (level < threshold())
|
||||
return;
|
||||
@@ -56,9 +61,7 @@ Logs::Sink::write(beast::severities::Severity level, std::string const& text)
|
||||
}
|
||||
|
||||
void
|
||||
Logs::Sink::writeAlways(
|
||||
beast::severities::Severity level,
|
||||
std::string const& text)
|
||||
Logs::Sink::writeAlways(beast::severities::Severity level, std::string_view text)
|
||||
{
|
||||
logs_.write(level, partition_, text, console());
|
||||
}
|
||||
@@ -91,6 +94,9 @@ Logs::File::open(boost::filesystem::path const& path)
|
||||
m_path = path;
|
||||
|
||||
m_stream = std::move(stream);
|
||||
size_t const bufsize = 256 * 1024;
|
||||
static char buf[bufsize];
|
||||
m_stream->rdbuf()->pubsetbuf(buf, bufsize);
|
||||
|
||||
wasOpened = true;
|
||||
}
|
||||
@@ -113,29 +119,27 @@ Logs::File::close()
|
||||
}
|
||||
|
||||
void
|
||||
Logs::File::write(char const* text)
|
||||
Logs::File::write(std::string_view text)
|
||||
{
|
||||
if (m_stream != nullptr)
|
||||
(*m_stream) << text;
|
||||
}
|
||||
|
||||
void
|
||||
Logs::File::writeln(char const* text)
|
||||
{
|
||||
if (m_stream != nullptr)
|
||||
{
|
||||
(*m_stream) << text;
|
||||
(*m_stream) << std::endl;
|
||||
}
|
||||
m_stream->write(text.data(), text.size());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Logs::Logs(beast::severities::Severity thresh)
|
||||
: thresh_(thresh) // default severity
|
||||
, writeBuffer_(
|
||||
batchBuffer_) // Initially, entire buffer is available for writing
|
||||
, readBuffer_(batchBuffer_.data(), 0) // No data ready to flush initially
|
||||
{
|
||||
}
|
||||
|
||||
Logs::~Logs()
|
||||
{
|
||||
flushBatch(); // Ensure all logs are written on shutdown
|
||||
}
|
||||
|
||||
bool
|
||||
Logs::open(boost::filesystem::path const& pathToLogFile)
|
||||
{
|
||||
@@ -145,7 +149,7 @@ Logs::open(boost::filesystem::path const& pathToLogFile)
|
||||
beast::Journal::Sink&
|
||||
Logs::get(std::string const& name)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
std::lock_guard lock(sinkSetMutex_);
|
||||
auto const result = sinks_.emplace(name, makeSink(name, thresh_));
|
||||
return *result.first->second;
|
||||
}
|
||||
@@ -156,12 +160,6 @@ Logs::operator[](std::string const& name)
|
||||
return get(name);
|
||||
}
|
||||
|
||||
beast::Journal
|
||||
Logs::journal(std::string const& name)
|
||||
{
|
||||
return beast::Journal(get(name));
|
||||
}
|
||||
|
||||
beast::severities::Severity
|
||||
Logs::threshold() const
|
||||
{
|
||||
@@ -171,7 +169,7 @@ Logs::threshold() const
|
||||
void
|
||||
Logs::threshold(beast::severities::Severity thresh)
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
std::lock_guard lock(sinkSetMutex_);
|
||||
thresh_ = thresh;
|
||||
for (auto& sink : sinks_)
|
||||
sink.second->threshold(thresh);
|
||||
@@ -181,7 +179,7 @@ std::vector<std::pair<std::string, std::string>>
|
||||
Logs::partition_severities() const
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> list;
|
||||
std::lock_guard lock(mutex_);
|
||||
std::lock_guard lock(sinkSetMutex_);
|
||||
list.reserve(sinks_.size());
|
||||
for (auto const& [name, sink] : sinks_)
|
||||
list.emplace_back(name, toString(fromSeverity(sink->threshold())));
|
||||
@@ -192,24 +190,83 @@ void
|
||||
Logs::write(
|
||||
beast::severities::Severity level,
|
||||
std::string const& partition,
|
||||
std::string const& text,
|
||||
std::string_view text,
|
||||
bool console)
|
||||
{
|
||||
std::string s;
|
||||
format(s, text, level, partition);
|
||||
std::lock_guard lock(mutex_);
|
||||
file_.writeln(s);
|
||||
std::string_view result = text;
|
||||
if (!beast::Journal::isStructuredJournalEnabled())
|
||||
{
|
||||
format(s, text, level, partition);
|
||||
result = s;
|
||||
}
|
||||
|
||||
// Console output still immediate for responsiveness
|
||||
if (!silent_)
|
||||
std::cerr << s << '\n';
|
||||
std::cerr << result << '\n';
|
||||
|
||||
// Add to batch buffer for file output
|
||||
{
|
||||
std::lock_guard lock(batchMutex_);
|
||||
|
||||
size_t logSize = result.size() + 1; // +1 for newline
|
||||
|
||||
// If log won't fit in current write buffer, flush first
|
||||
if (logSize > writeBuffer_.size())
|
||||
{
|
||||
flushBatchUnsafe();
|
||||
}
|
||||
|
||||
// Copy log into write buffer
|
||||
std::copy(result.begin(), result.end(), writeBuffer_.begin());
|
||||
writeBuffer_[result.size()] = '\n';
|
||||
|
||||
// Update spans: expand read buffer, shrink write buffer
|
||||
size_t totalUsed = readBuffer_.size() + logSize;
|
||||
readBuffer_ = std::span<char>(batchBuffer_.data(), totalUsed);
|
||||
writeBuffer_ = std::span<char>(
|
||||
batchBuffer_.data() + totalUsed, batchBuffer_.size() - totalUsed);
|
||||
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
bool shouldFlush = (now - lastFlush_) >= FLUSH_INTERVAL;
|
||||
|
||||
if (shouldFlush)
|
||||
{
|
||||
flushBatchUnsafe();
|
||||
lastFlush_ = now;
|
||||
}
|
||||
}
|
||||
|
||||
// VFALCO TODO Fix console output
|
||||
// if (console)
|
||||
// out_.write_console(s);
|
||||
}
|
||||
|
||||
void
|
||||
Logs::flushBatch()
|
||||
{
|
||||
std::lock_guard lock(batchMutex_);
|
||||
flushBatchUnsafe();
|
||||
}
|
||||
|
||||
void
|
||||
Logs::flushBatchUnsafe()
|
||||
{
|
||||
if (readBuffer_.empty())
|
||||
return;
|
||||
|
||||
// Write the read buffer contents to file in one system call
|
||||
file_.write(std::string_view{readBuffer_.data(), readBuffer_.size()});
|
||||
|
||||
// Reset spans: entire buffer available for writing, nothing to read
|
||||
writeBuffer_ = std::span<char>(batchBuffer_);
|
||||
readBuffer_ = std::span<char>(batchBuffer_.data(), 0);
|
||||
}
|
||||
|
||||
std::string
|
||||
Logs::rotate()
|
||||
{
|
||||
std::lock_guard lock(mutex_);
|
||||
flushBatch(); // Flush pending logs before rotating
|
||||
bool const wasOpened = file_.closeAndReopen();
|
||||
if (wasOpened)
|
||||
return "The log file was closed and reopened.";
|
||||
@@ -326,7 +383,7 @@ Logs::fromString(std::string const& s)
|
||||
void
|
||||
Logs::format(
|
||||
std::string& output,
|
||||
std::string const& message,
|
||||
std::string_view message,
|
||||
beast::severities::Severity severity,
|
||||
std::string const& partition)
|
||||
{
|
||||
|
||||
@@ -19,12 +19,102 @@
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <ios>
|
||||
#include <ostream>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
namespace beast {
|
||||
|
||||
namespace {
|
||||
|
||||
// Fast timestamp to ISO string conversion
|
||||
// Returns string like "2024-01-15T10:30:45.123Z"
|
||||
std::string_view
|
||||
fastTimestampToString(std::int64_t milliseconds_since_epoch)
|
||||
{
|
||||
thread_local char buffer[64]; // "2024-01-15T10:30:45.123Z"
|
||||
|
||||
// Precomputed lookup table for 2-digit numbers 00-99
|
||||
static constexpr char digits[200] = {
|
||||
'0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6',
|
||||
'0', '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3',
|
||||
'1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0',
|
||||
'2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7',
|
||||
'2', '8', '2', '9', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4',
|
||||
'3', '5', '3', '6', '3', '7', '3', '8', '3', '9', '4', '0', '4', '1',
|
||||
'4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8',
|
||||
'4', '9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5',
|
||||
'5', '6', '5', '7', '5', '8', '5', '9', '6', '0', '6', '1', '6', '2',
|
||||
'6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
|
||||
'7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6',
|
||||
'7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', '2', '8', '3',
|
||||
'8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', '9', '0',
|
||||
'9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7',
|
||||
'9', '8', '9', '9'};
|
||||
|
||||
constexpr std::int64_t UNIX_EPOCH_DAYS =
|
||||
719468; // Days from year 0 to 1970-01-01
|
||||
|
||||
std::int64_t seconds = milliseconds_since_epoch / 1000;
|
||||
int ms = milliseconds_since_epoch % 1000;
|
||||
std::int64_t days = seconds / 86400 + UNIX_EPOCH_DAYS;
|
||||
int sec_of_day = seconds % 86400;
|
||||
|
||||
// Calculate year, month, day from days using Gregorian calendar algorithm
|
||||
int era = (days >= 0 ? days : days - 146096) / 146097;
|
||||
int doe = days - era * 146097;
|
||||
int yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
|
||||
int year = yoe + era * 400;
|
||||
int doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
|
||||
int mp = (5 * doy + 2) / 153;
|
||||
int day = doy - (153 * mp + 2) / 5 + 1;
|
||||
int month = mp + (mp < 10 ? 3 : -9);
|
||||
year += (month <= 2);
|
||||
|
||||
// Calculate hour, minute, second
|
||||
int hour = sec_of_day / 3600;
|
||||
int min = (sec_of_day % 3600) / 60;
|
||||
int sec = sec_of_day % 60;
|
||||
|
||||
// Format: "2024-01-15T10:30:45.123Z"
|
||||
buffer[0] = '0' + year / 1000;
|
||||
buffer[1] = '0' + (year / 100) % 10;
|
||||
buffer[2] = '0' + (year / 10) % 10;
|
||||
buffer[3] = '0' + year % 10;
|
||||
buffer[4] = '-';
|
||||
buffer[5] = digits[month * 2];
|
||||
buffer[6] = digits[month * 2 + 1];
|
||||
buffer[7] = '-';
|
||||
buffer[8] = digits[day * 2];
|
||||
buffer[9] = digits[day * 2 + 1];
|
||||
buffer[10] = 'T';
|
||||
buffer[11] = digits[hour * 2];
|
||||
buffer[12] = digits[hour * 2 + 1];
|
||||
buffer[13] = ':';
|
||||
buffer[14] = digits[min * 2];
|
||||
buffer[15] = digits[min * 2 + 1];
|
||||
buffer[16] = ':';
|
||||
buffer[17] = digits[sec * 2];
|
||||
buffer[18] = digits[sec * 2 + 1];
|
||||
buffer[19] = '.';
|
||||
buffer[20] = '0' + ms / 100;
|
||||
buffer[21] = '0' + (ms / 10) % 10;
|
||||
buffer[22] = '0' + ms % 10;
|
||||
buffer[23] = 'Z';
|
||||
|
||||
return {buffer, 24};
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
std::string Journal::globalLogAttributesJson_;
|
||||
std::shared_mutex Journal::globalLogAttributesMutex_;
|
||||
bool Journal::m_jsonLogsEnabled = false;
|
||||
thread_local Journal::JsonLogContext Journal::currentJsonLogContext_{};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// A Sink that does nothing.
|
||||
@@ -66,12 +156,12 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
write(severities::Severity, std::string const&) override
|
||||
write(severities::Severity, std::string_view) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(severities::Severity, std::string const&) override
|
||||
writeAlways(severities::Severity, std::string_view) override
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -87,6 +177,160 @@ Journal::getNullSink()
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::string_view
|
||||
severities::to_string(Severity severity)
|
||||
{
|
||||
using namespace std::string_view_literals;
|
||||
switch (severity)
|
||||
{
|
||||
case kDisabled:
|
||||
return "disabled"sv;
|
||||
case kTrace:
|
||||
return "trace"sv;
|
||||
case kDebug:
|
||||
return "debug"sv;
|
||||
case kInfo:
|
||||
return "info"sv;
|
||||
case kWarning:
|
||||
return "warning"sv;
|
||||
case kError:
|
||||
return "error"sv;
|
||||
case kFatal:
|
||||
return "fatal"sv;
|
||||
default:
|
||||
UNREACHABLE("Unexpected severity value!");
|
||||
}
|
||||
return ""sv;
|
||||
}
|
||||
|
||||
void
|
||||
Journal::JsonLogContext::reset(
|
||||
std::source_location location,
|
||||
severities::Severity severity,
|
||||
std::string_view moduleName,
|
||||
std::string_view journalAttributesJson) noexcept
|
||||
{
|
||||
struct ThreadIdStringInitializer
|
||||
{
|
||||
std::string value;
|
||||
ThreadIdStringInitializer()
|
||||
{
|
||||
std::stringstream threadIdStream;
|
||||
threadIdStream.imbue(std::locale::classic());
|
||||
threadIdStream << std::this_thread::get_id();
|
||||
value = threadIdStream.str();
|
||||
}
|
||||
};
|
||||
thread_local ThreadIdStringInitializer const threadId;
|
||||
|
||||
buffer_.clear();
|
||||
|
||||
writer().startObject();
|
||||
|
||||
if (!journalAttributesJson.empty())
|
||||
{
|
||||
writer().writeKey("JournalParams");
|
||||
writer().writeRaw(journalAttributesJson);
|
||||
writer().endObject();
|
||||
}
|
||||
|
||||
{
|
||||
std::shared_lock lock(globalLogAttributesMutex_);
|
||||
if (!globalLogAttributesJson_.empty())
|
||||
{
|
||||
writer().writeKey("GlobalParams");
|
||||
writer().writeRaw(globalLogAttributesJson_);
|
||||
writer().endObject();
|
||||
}
|
||||
}
|
||||
|
||||
writer().writeKey("ModuleName");
|
||||
writer().writeString(moduleName);
|
||||
writer().writeKey("Metadata");
|
||||
writer().startObject();
|
||||
|
||||
writer().writeKey("Function");
|
||||
writer().writeString(location.function_name());
|
||||
|
||||
writer().writeKey("File");
|
||||
std::string_view fileName = location.file_name();
|
||||
constexpr size_t KEEP_CHARS = 10;
|
||||
std::string_view trimmedFileName = (fileName.size() > KEEP_CHARS)
|
||||
? fileName.substr(fileName.size() - KEEP_CHARS)
|
||||
: fileName;
|
||||
writer().writeString(trimmedFileName);
|
||||
|
||||
writer().writeKey("Line");
|
||||
writer().writeUInt(location.line());
|
||||
|
||||
writer().writeKey("ThreadId");
|
||||
writer().writeString(threadId.value);
|
||||
|
||||
auto severityStr = to_string(severity);
|
||||
writer().writeKey("Level");
|
||||
writer().writeString(severityStr);
|
||||
|
||||
auto nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
writer().writeKey("Timestamp");
|
||||
writer().writeInt(nowMs);
|
||||
writer().writeKey("Time");
|
||||
writer().writeString(fastTimestampToString(nowMs));
|
||||
|
||||
writer().endObject();
|
||||
|
||||
writer().writeKey("MessageParams");
|
||||
writer().startObject();
|
||||
}
|
||||
|
||||
void
|
||||
Journal::initMessageContext(
|
||||
std::source_location location,
|
||||
severities::Severity severity) const
|
||||
{
|
||||
currentJsonLogContext_.reset(location, severity, m_name, m_attributesJson);
|
||||
}
|
||||
|
||||
std::string_view
|
||||
Journal::formatLog(std::string const& message)
|
||||
{
|
||||
if (!m_jsonLogsEnabled)
|
||||
{
|
||||
return message;
|
||||
}
|
||||
|
||||
auto& writer = currentJsonLogContext_.writer();
|
||||
|
||||
writer.endObject();
|
||||
|
||||
writer.writeKey("Message");
|
||||
writer.writeString(message);
|
||||
|
||||
writer.endObject();
|
||||
|
||||
return writer.finish();
|
||||
}
|
||||
|
||||
void
|
||||
Journal::enableStructuredJournal()
|
||||
{
|
||||
m_jsonLogsEnabled = true;
|
||||
}
|
||||
|
||||
void
|
||||
Journal::disableStructuredJournal()
|
||||
{
|
||||
m_jsonLogsEnabled = false;
|
||||
resetGlobalAttributes();
|
||||
}
|
||||
|
||||
bool
|
||||
Journal::isStructuredJournalEnabled()
|
||||
{
|
||||
return m_jsonLogsEnabled;
|
||||
}
|
||||
|
||||
Journal::Sink::Sink(Severity thresh, bool console)
|
||||
: thresh_(thresh), m_console(console)
|
||||
{
|
||||
@@ -143,13 +387,13 @@ Journal::ScopedStream::ScopedStream(
|
||||
|
||||
Journal::ScopedStream::~ScopedStream()
|
||||
{
|
||||
std::string const& s(m_ostream.str());
|
||||
std::string s = m_ostream.str();
|
||||
if (!s.empty())
|
||||
{
|
||||
if (s == "\n")
|
||||
m_sink.write(m_level, "");
|
||||
m_sink.write(m_level, formatLog(""));
|
||||
else
|
||||
m_sink.write(m_level, s);
|
||||
m_sink.write(m_level, formatLog(s));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +408,7 @@ Journal::ScopedStream::operator<<(std::ostream& manip(std::ostream&)) const
|
||||
Journal::ScopedStream
|
||||
Journal::Stream::operator<<(std::ostream& manip(std::ostream&)) const
|
||||
{
|
||||
return ScopedStream(*this, manip);
|
||||
return {*this, manip};
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -17,12 +17,11 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/net/AutoSocket.h>
|
||||
#include <xrpld/net/HTTPClient.h>
|
||||
#include <xrpld/net/HTTPClientSSLContext.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/core/LexicalCast.h>
|
||||
#include <xrpl/net/AutoSocket.h>
|
||||
#include <xrpl/net/HTTPClient.h>
|
||||
#include <xrpl/net/HTTPClientSSLContext.h>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
@@ -36,9 +35,13 @@ namespace ripple {
|
||||
static std::optional<HTTPClientSSLContext> httpClientSSLContext;
|
||||
|
||||
void
|
||||
HTTPClient::initializeSSLContext(Config const& config, beast::Journal j)
|
||||
HTTPClient::initializeSSLContext(
|
||||
std::string const& sslVerifyDir,
|
||||
std::string const& sslVerifyFile,
|
||||
bool sslVerify,
|
||||
beast::Journal j)
|
||||
{
|
||||
httpClientSSLContext.emplace(config, j);
|
||||
httpClientSSLContext.emplace(sslVerifyDir, sslVerifyFile, sslVerify, j);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/net/RegisterSSLCerts.h>
|
||||
#include <xrpl/net/RegisterSSLCerts.h>
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
#include <boost/asio/ssl/error.hpp>
|
||||
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 197 KiB |
|
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
@@ -48,14 +48,14 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
write(severities::Severity level, std::string const&) override
|
||||
write(severities::Severity level, std::string_view) override
|
||||
{
|
||||
if (level >= threshold())
|
||||
++m_count;
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(severities::Severity level, std::string const&) override
|
||||
writeAlways(severities::Severity level, std::string_view) override
|
||||
{
|
||||
++m_count;
|
||||
}
|
||||
|
||||
@@ -178,7 +178,6 @@ struct Peer
|
||||
using NodeKey = Validation::NodeKey;
|
||||
|
||||
//! Logging support that prefixes messages with the peer ID
|
||||
beast::WrappedSink sink;
|
||||
beast::Journal j;
|
||||
|
||||
//! Generic consensus
|
||||
@@ -284,8 +283,7 @@ struct Peer
|
||||
TrustGraph<Peer*>& tg,
|
||||
CollectorRefs& c,
|
||||
beast::Journal jIn)
|
||||
: sink(jIn, "Peer " + to_string(i) + ": ")
|
||||
, j(sink)
|
||||
: j(jIn, log::attributes(log::attr("Peer", "Peer " + to_string(i))))
|
||||
, consensus(s.clock(), *this, j)
|
||||
, id{i}
|
||||
, key{id, 0}
|
||||
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text) override
|
||||
write(beast::severities::Severity level, std::string_view text) override
|
||||
{
|
||||
if (level < threshold())
|
||||
return;
|
||||
@@ -59,8 +59,7 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(beast::severities::Severity level, std::string const& text)
|
||||
override
|
||||
writeAlways(beast::severities::Severity level, std::string_view text) override
|
||||
{
|
||||
std::cout << clock_.now().time_since_epoch().count() << " " << text
|
||||
<< std::endl;
|
||||
|
||||
@@ -57,15 +57,14 @@ class CaptureLogs : public Logs
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text)
|
||||
override
|
||||
write(beast::severities::Severity level, std::string_view text) override
|
||||
{
|
||||
std::lock_guard lock(strmMutex_);
|
||||
strm_ << text;
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(beast::severities::Severity level, std::string const& text)
|
||||
writeAlways(beast::severities::Severity level, std::string_view text)
|
||||
override
|
||||
{
|
||||
std::lock_guard lock(strmMutex_);
|
||||
|
||||
@@ -45,18 +45,17 @@ class CheckMessageLogs : public Logs
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text)
|
||||
override
|
||||
write(beast::severities::Severity level, std::string_view text) override
|
||||
{
|
||||
if (text.find(owner_.msg_) != std::string::npos)
|
||||
*owner_.pFound_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(beast::severities::Severity level, std::string const& text)
|
||||
writeAlways(beast::severities::Severity level, std::string_view text)
|
||||
override
|
||||
{
|
||||
write(level, text);
|
||||
write(level, std::move(text));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
|
||||
#include <xrpld/app/ledger/LedgerMaster.h>
|
||||
#include <xrpld/app/misc/NetworkOPs.h>
|
||||
#include <xrpld/net/HTTPClient.h>
|
||||
#include <xrpld/net/RPCCall.h>
|
||||
#include <xrpld/rpc/RPCCall.h>
|
||||
|
||||
#include <xrpl/basics/Slice.h>
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/json/to_string.h>
|
||||
#include <xrpl/net/HTTPClient.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Serializer.h>
|
||||
@@ -74,7 +74,11 @@ Env::AppBundle::AppBundle(
|
||||
auto timeKeeper_ = std::make_unique<ManualTimeKeeper>();
|
||||
timeKeeper = timeKeeper_.get();
|
||||
// Hack so we don't have to call Config::setup
|
||||
HTTPClient::initializeSSLContext(*config, debugLog());
|
||||
HTTPClient::initializeSSLContext(
|
||||
config->SSL_VERIFY_DIR,
|
||||
config->SSL_VERIFY_FILE,
|
||||
config->SSL_VERIFY,
|
||||
debugLog());
|
||||
owned = make_Application(
|
||||
std::move(config), std::move(logs), std::move(timeKeeper_));
|
||||
app = owned.get();
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include <test/jtx/utility.h>
|
||||
|
||||
#include <xrpld/net/RPCCall.h>
|
||||
#include <xrpld/rpc/RPCCall.h>
|
||||
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/json/Object.h>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/utility.h>
|
||||
|
||||
#include <xrpld/net/RPCCall.h>
|
||||
#include <xrpld/rpc/RPCCall.h>
|
||||
#include <xrpld/rpc/detail/RPCHelpers.h>
|
||||
|
||||
#include <xrpl/beast/unit_test.h>
|
||||
|
||||
@@ -89,8 +89,7 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text)
|
||||
override
|
||||
write(beast::severities::Severity level, std::string_view text) override
|
||||
{
|
||||
if (level < threshold())
|
||||
return;
|
||||
@@ -99,7 +98,7 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(beast::severities::Severity level, std::string const& text)
|
||||
writeAlways(beast::severities::Severity level, std::string_view text)
|
||||
override
|
||||
{
|
||||
suite_.log << text << std::endl;
|
||||
|
||||
@@ -49,27 +49,24 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text) override;
|
||||
write(beast::severities::Severity level, std::string_view text) override;
|
||||
|
||||
void
|
||||
writeAlways(beast::severities::Severity level, std::string const& text)
|
||||
override;
|
||||
writeAlways(beast::severities::Severity level, std::string_view text) override;
|
||||
};
|
||||
|
||||
inline void
|
||||
SuiteJournalSink::write(
|
||||
beast::severities::Severity level,
|
||||
std::string const& text)
|
||||
SuiteJournalSink::write(beast::severities::Severity level, std::string_view text)
|
||||
{
|
||||
// Only write the string if the level at least equals the threshold.
|
||||
if (level >= threshold())
|
||||
writeAlways(level, text);
|
||||
writeAlways(level, std::move(text));
|
||||
}
|
||||
|
||||
inline void
|
||||
SuiteJournalSink::writeAlways(
|
||||
beast::severities::Severity level,
|
||||
std::string const& text)
|
||||
std::string_view text)
|
||||
{
|
||||
using namespace beast::severities;
|
||||
|
||||
@@ -137,16 +134,15 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text) override
|
||||
write(beast::severities::Severity level, std::string_view text) override
|
||||
{
|
||||
if (level < threshold())
|
||||
return;
|
||||
writeAlways(level, text);
|
||||
writeAlways(level, std::move(text));
|
||||
}
|
||||
|
||||
inline void
|
||||
writeAlways(beast::severities::Severity level, std::string const& text)
|
||||
override
|
||||
writeAlways(beast::severities::Severity level, std::string_view text) override
|
||||
{
|
||||
strm_ << text << std::endl;
|
||||
}
|
||||
|
||||
852
src/tests/libxrpl/basics/log.cpp
Normal file
852
src/tests/libxrpl/basics/log.cpp
Normal file
@@ -0,0 +1,852 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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 <boost/json.hpp>
|
||||
|
||||
#include <doctest/doctest.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <numbers>
|
||||
|
||||
using namespace ripple;
|
||||
|
||||
class MockLogs : public Logs
|
||||
{
|
||||
private:
|
||||
class Sink : public beast::Journal::Sink
|
||||
{
|
||||
private:
|
||||
MockLogs& logs_;
|
||||
std::string partition_;
|
||||
|
||||
public:
|
||||
Sink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity thresh,
|
||||
MockLogs& logs)
|
||||
: beast::Journal::Sink(thresh, false)
|
||||
, logs_(logs)
|
||||
, partition_(partition)
|
||||
{
|
||||
}
|
||||
|
||||
Sink(Sink const&) = delete;
|
||||
Sink&
|
||||
operator=(Sink const&) = delete;
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string_view text) override
|
||||
{
|
||||
logs_.write(level, partition_, text, false);
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(beast::severities::Severity level, std::string_view text)
|
||||
override
|
||||
{
|
||||
logs_.write(level, partition_, text, false);
|
||||
}
|
||||
};
|
||||
|
||||
std::string& logStream_;
|
||||
|
||||
public:
|
||||
MockLogs(std::string& logStream, beast::severities::Severity level)
|
||||
: Logs(level), logStream_(logStream)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<beast::Journal::Sink>
|
||||
makeSink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity startingLevel) override
|
||||
{
|
||||
return std::make_unique<Sink>(partition, startingLevel, *this);
|
||||
}
|
||||
|
||||
void
|
||||
write(
|
||||
beast::severities::Severity level,
|
||||
std::string const& partition,
|
||||
std::string_view text,
|
||||
bool console)
|
||||
{
|
||||
std::string s;
|
||||
std::string_view result = text;
|
||||
if (!beast::Journal::isStructuredJournalEnabled())
|
||||
{
|
||||
format(s, text, level, partition);
|
||||
result = s;
|
||||
}
|
||||
logStream_.append(result);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE("Text logs")
|
||||
{
|
||||
std::string logStream;
|
||||
|
||||
MockLogs logs{logStream, beast::severities::kAll};
|
||||
|
||||
logs.journal("Test").debug() << "Test";
|
||||
|
||||
CHECK(logStream.find("Test") != std::string::npos);
|
||||
|
||||
logStream.clear();
|
||||
|
||||
logs.journal("Test").debug() << "\n";
|
||||
|
||||
CHECK(logStream.find("\n") == std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("Test format output")
|
||||
{
|
||||
std::string output;
|
||||
Logs::format(output, "Message", beast::severities::kDebug, "Test");
|
||||
CHECK(output.find("Message") != std::string::npos);
|
||||
CHECK(output != "Message");
|
||||
}
|
||||
|
||||
TEST_CASE("Enable json logs")
|
||||
{
|
||||
std::string logStream;
|
||||
|
||||
MockLogs logs{logStream, beast::severities::kAll};
|
||||
|
||||
logs.journal("Test ").debug() << "Test123";
|
||||
|
||||
CHECK(logStream.find("Test123") != std::string::npos);
|
||||
|
||||
logStream.clear();
|
||||
|
||||
beast::Journal::enableStructuredJournal();
|
||||
|
||||
logs.journal("Test").debug() << "\n";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto doc = boost::json::parse(logStream, ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(doc.is_object());
|
||||
CHECK(doc.as_object().contains("Message"));
|
||||
CHECK(doc.as_object()["Message"].is_string());
|
||||
CHECK(doc.as_object()["Message"].get_string() == "");
|
||||
beast::Journal::disableStructuredJournal();
|
||||
}
|
||||
|
||||
TEST_CASE("Global attributes")
|
||||
{
|
||||
std::string logStream;
|
||||
|
||||
MockLogs logs{logStream, beast::severities::kAll};
|
||||
|
||||
beast::Journal::enableStructuredJournal();
|
||||
beast::Journal::addGlobalAttributes(
|
||||
log::attributes(log::attr("Field1", "Value1")));
|
||||
|
||||
logs.journal("Test").debug() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto jsonLog = boost::json::parse(logStream, ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(jsonLog.is_object());
|
||||
CHECK(jsonLog.as_object().contains("GlobalParams"));
|
||||
CHECK(jsonLog.as_object()["GlobalParams"].is_object());
|
||||
CHECK(jsonLog.as_object()["GlobalParams"].as_object().contains("Field1"));
|
||||
CHECK(
|
||||
jsonLog.as_object()["GlobalParams"].as_object()["Field1"].is_string());
|
||||
CHECK(
|
||||
jsonLog.as_object()["GlobalParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_string() == "Value1");
|
||||
beast::Journal::disableStructuredJournal();
|
||||
}
|
||||
|
||||
TEST_CASE("Global attributes inheritable")
|
||||
{
|
||||
std::string logStream;
|
||||
|
||||
MockLogs logs{logStream, beast::severities::kAll};
|
||||
|
||||
beast::Journal::enableStructuredJournal();
|
||||
beast::Journal::addGlobalAttributes(
|
||||
log::attributes(log::attr("Field1", "Value1")));
|
||||
|
||||
logs.journal(
|
||||
"Test",
|
||||
log::attributes(
|
||||
log::attr("Field1", "Value3"), log::attr("Field2", "Value2")))
|
||||
.debug()
|
||||
<< "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto jsonLog = boost::json::parse(logStream, ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(jsonLog.is_object());
|
||||
CHECK(jsonLog.as_object()["GlobalParams"].as_object().contains("Field1"));
|
||||
CHECK(
|
||||
jsonLog.as_object()["GlobalParams"].as_object()["Field1"].is_string());
|
||||
CHECK(
|
||||
jsonLog.as_object()["GlobalParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_string() == "Value1");
|
||||
CHECK(
|
||||
jsonLog.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_string() == "Value3");
|
||||
CHECK(
|
||||
jsonLog.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.get_string() == "Value2");
|
||||
beast::Journal::disableStructuredJournal();
|
||||
}
|
||||
|
||||
TEST_CASE("Test JsonWriter")
|
||||
{
|
||||
{
|
||||
std::string buffer;
|
||||
beast::detail::SimpleJsonWriter writer{buffer};
|
||||
|
||||
writer.writeString("\n\r\t123\b\f123");
|
||||
CHECK(writer.finish() == "\"\\n\\r\\t123\\b\\f123\"");
|
||||
}
|
||||
|
||||
{
|
||||
std::string buffer;
|
||||
beast::detail::SimpleJsonWriter writer{buffer};
|
||||
|
||||
writer.writeString("\t");
|
||||
CHECK(writer.finish() == "\"\\t\"");
|
||||
}
|
||||
|
||||
{
|
||||
std::string buffer;
|
||||
beast::detail::SimpleJsonWriter writer{buffer};
|
||||
|
||||
writer.writeString(std::string_view{"\0", 1});
|
||||
CHECK(writer.finish() == "\"\\u0000\"");
|
||||
}
|
||||
|
||||
{
|
||||
std::string buffer;
|
||||
beast::detail::SimpleJsonWriter writer{buffer};
|
||||
|
||||
writer.writeString("\"\\");
|
||||
CHECK(writer.finish() == "\"\\\"\\\\\"");
|
||||
}
|
||||
|
||||
{
|
||||
std::string buffer;
|
||||
beast::detail::SimpleJsonWriter writer{buffer};
|
||||
|
||||
writer.startArray();
|
||||
writer.writeBool(true);
|
||||
writer.writeBool(false);
|
||||
writer.writeNull();
|
||||
writer.endArray();
|
||||
CHECK(writer.finish() == "[true,false,null]");
|
||||
}
|
||||
}
|
||||
|
||||
namespace test_detail {
|
||||
struct ToCharsStruct
|
||||
{
|
||||
};
|
||||
|
||||
std::to_chars_result
|
||||
to_chars(char* first, char* last, ToCharsStruct)
|
||||
{
|
||||
*first = '0';
|
||||
return std::to_chars_result{first + 1, std::errc{}};
|
||||
}
|
||||
|
||||
struct StreamStruct
|
||||
{
|
||||
};
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, StreamStruct)
|
||||
{
|
||||
os << "0";
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace test_detail
|
||||
|
||||
TEST_CASE("Test setJsonValue")
|
||||
{
|
||||
std::ostringstream stringBuf;
|
||||
std::string buffer;
|
||||
beast::detail::SimpleJsonWriter writer{buffer};
|
||||
writer.startObject();
|
||||
|
||||
log::detail::setJsonValue<bool>(writer, "testBool", true, &stringBuf);
|
||||
log::detail::setJsonValue<std::int32_t>(
|
||||
writer, "testInt32", -1, &stringBuf);
|
||||
log::detail::setJsonValue<std::uint32_t>(
|
||||
writer, "testUInt32", 1, &stringBuf);
|
||||
log::detail::setJsonValue<std::int64_t>(
|
||||
writer, "testInt64", -1, &stringBuf);
|
||||
log::detail::setJsonValue<std::uint64_t>(
|
||||
writer, "testUInt64", 1, &stringBuf);
|
||||
log::detail::setJsonValue<double>(writer, "testDouble", 1.1, &stringBuf);
|
||||
log::detail::setJsonValue<char const*>(
|
||||
writer, "testCharStar", "Char*", &stringBuf);
|
||||
log::detail::setJsonValue<std::string>(
|
||||
writer, "testStdString", "StdString", &stringBuf);
|
||||
log::detail::setJsonValue<std::string_view>(
|
||||
writer, "testStdStringView", "StdStringView", &stringBuf);
|
||||
log::detail::setJsonValue<test_detail::ToCharsStruct>(
|
||||
writer, "testToChars", {}, &stringBuf);
|
||||
log::detail::setJsonValue<test_detail::StreamStruct>(
|
||||
writer, "testStream", {}, &stringBuf);
|
||||
writer.endObject();
|
||||
|
||||
CHECK(
|
||||
writer.finish() ==
|
||||
R"AAA({"testBool":true,"testInt32":-1,"testUInt32":1,"testInt64":-1,"testUInt64":1,"testDouble":1.1,"testCharStar":"Char*","testStdString":"StdString","testStdStringView":"StdStringView","testToChars":"0","testStream":"0"})AAA");
|
||||
}
|
||||
|
||||
TEST_CASE("Test json logging not enabled")
|
||||
{
|
||||
std::string logStream;
|
||||
|
||||
MockLogs logs{logStream, beast::severities::kAll};
|
||||
|
||||
beast::Journal::disableStructuredJournal();
|
||||
beast::Journal::addGlobalAttributes(
|
||||
log::attributes(log::attr("Field1", "Value1")));
|
||||
|
||||
logs.journal("Test123").debug()
|
||||
<< "Test " << log::param(" Field1", "Value1")
|
||||
<< log::field("Field2", "Value2");
|
||||
|
||||
CHECK(logStream.find("Test Value1") != std::string::npos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_view text) override
|
||||
{
|
||||
strm_ << text;
|
||||
}
|
||||
|
||||
void
|
||||
writeAlways(beast::severities::Severity level, std::string_view text) override
|
||||
{
|
||||
strm_ << text;
|
||||
}
|
||||
};
|
||||
|
||||
class JsonLogStreamFixture
|
||||
{
|
||||
public:
|
||||
JsonLogStreamFixture()
|
||||
: sink_(beast::severities::kAll, logStream_)
|
||||
, j_(sink_, "Test", log::attributes(log::attr("Field1", "Value1")))
|
||||
{
|
||||
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, "Test json log fields")
|
||||
{
|
||||
beast::Journal::addGlobalAttributes(
|
||||
log::attributes(log::attr("Field2", "Value2")));
|
||||
journal().debug() << std::boolalpha << true << std::noboolalpha << " Test "
|
||||
<< std::boolalpha << false
|
||||
<< log::field("Field3", "Value3");
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(logValue.is_object());
|
||||
CHECK(logValue.as_object().contains("GlobalParams"));
|
||||
CHECK(logValue.as_object().contains("JournalParams"));
|
||||
CHECK(logValue.as_object().contains("Metadata"));
|
||||
CHECK(logValue.as_object().contains("Message"));
|
||||
|
||||
CHECK(logValue.as_object()["GlobalParams"].is_object());
|
||||
CHECK(logValue.as_object()["JournalParams"].is_object());
|
||||
CHECK(logValue.as_object()["Metadata"].is_object());
|
||||
CHECK(logValue.as_object()["Message"].is_string());
|
||||
|
||||
CHECK(logValue.as_object()["Metadata"].as_object().contains("Function"));
|
||||
CHECK(logValue.as_object()["Metadata"].as_object().contains("File"));
|
||||
CHECK(logValue.as_object()["Metadata"].as_object().contains("Line"));
|
||||
CHECK(logValue.as_object()["Metadata"].as_object().contains("ThreadId"));
|
||||
CHECK(logValue.as_object()["Metadata"].as_object().contains("Level"));
|
||||
CHECK(logValue.as_object()["Metadata"].as_object().contains("Time"));
|
||||
|
||||
CHECK(logValue.as_object()["Metadata"].as_object()["Function"].is_string());
|
||||
CHECK(logValue.as_object()["Metadata"].as_object()["File"].is_string());
|
||||
CHECK(logValue.as_object()["Metadata"].as_object()["Line"].is_number());
|
||||
|
||||
CHECK(
|
||||
logValue.as_object()["Message"].get_string() ==
|
||||
std::string{"true Test false"});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test json log levels")
|
||||
{
|
||||
{
|
||||
stream().str("");
|
||||
journal().trace() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(
|
||||
logValue.as_object()["Metadata"]
|
||||
.as_object()["Level"]
|
||||
.get_string() ==
|
||||
beast::severities::to_string(beast::severities::kTrace));
|
||||
}
|
||||
|
||||
{
|
||||
stream().str("");
|
||||
journal().debug() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(
|
||||
logValue.as_object()["Metadata"]
|
||||
.as_object()["Level"]
|
||||
.get_string() ==
|
||||
beast::severities::to_string(beast::severities::kDebug));
|
||||
}
|
||||
|
||||
{
|
||||
stream().str("");
|
||||
journal().info() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(
|
||||
logValue.as_object()["Metadata"]
|
||||
.as_object()["Level"]
|
||||
.get_string() ==
|
||||
beast::severities::to_string(beast::severities::kInfo));
|
||||
}
|
||||
|
||||
{
|
||||
stream().str("");
|
||||
journal().warn() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(
|
||||
logValue.as_object()["Metadata"]
|
||||
.as_object()["Level"]
|
||||
.get_string() ==
|
||||
beast::severities::to_string(beast::severities::kWarning));
|
||||
}
|
||||
|
||||
{
|
||||
stream().str("");
|
||||
journal().error() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(
|
||||
logValue.as_object()["Metadata"]
|
||||
.as_object()["Level"]
|
||||
.get_string() ==
|
||||
beast::severities::to_string(beast::severities::kError));
|
||||
}
|
||||
|
||||
{
|
||||
stream().str("");
|
||||
journal().fatal() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(
|
||||
logValue.as_object()["Metadata"]
|
||||
.as_object()["Level"]
|
||||
.get_string() ==
|
||||
beast::severities::to_string(beast::severities::kFatal));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test json log stream")
|
||||
{
|
||||
journal().stream(beast::severities::kError) << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(
|
||||
logValue.as_object()["Metadata"].as_object()["Level"].get_string() ==
|
||||
beast::severities::to_string(beast::severities::kError));
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test json log params")
|
||||
{
|
||||
journal().debug() << "Test: " << log::param("Field1", 1) << ", "
|
||||
<< log::param(
|
||||
"Field2",
|
||||
std::numeric_limits<std::uint64_t>::max())
|
||||
<< ", " << log::param("Field3", std::numbers::pi);
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(logValue.as_object()["MessageParams"].is_object());
|
||||
CHECK(logValue.as_object()["MessageParams"]
|
||||
.as_object()["Field1"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["MessageParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_int64() == 1);
|
||||
CHECK(logValue.as_object()["MessageParams"]
|
||||
.as_object()["Field2"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["MessageParams"]
|
||||
.as_object()["Field2"]
|
||||
.get_uint64() == std::numeric_limits<std::uint64_t>::max());
|
||||
auto field3Val = logValue.as_object()["MessageParams"]
|
||||
.as_object()["Field3"]
|
||||
.get_double();
|
||||
auto difference = std::abs(field3Val - std::numbers::pi);
|
||||
CHECK(difference < 1e-4);
|
||||
CHECK(logValue.as_object()["Message"].is_string());
|
||||
CHECK(
|
||||
logValue.as_object()["Message"].get_string() ==
|
||||
std::string{"Test: 1, 18446744073709551615, 3.141592653589793"});
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test json log fields")
|
||||
{
|
||||
journal().debug() << "Test" << log::field("Field1", 1)
|
||||
<< log::field(
|
||||
"Field2",
|
||||
std::numeric_limits<std::uint64_t>::max());
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(logValue.as_object()["MessageParams"].is_object());
|
||||
CHECK(logValue.as_object()["MessageParams"]
|
||||
.as_object()["Field1"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["MessageParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_int64() == 1);
|
||||
// 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.as_object()["MessageParams"]
|
||||
.as_object()["Field2"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["MessageParams"]
|
||||
.as_object()["Field2"]
|
||||
.get_uint64() == std::numeric_limits<std::uint64_t>::max());
|
||||
CHECK(logValue.as_object()["Message"].is_string());
|
||||
CHECK(logValue.as_object()["Message"].get_string() == "Test");
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test journal attributes")
|
||||
{
|
||||
beast::Journal j{
|
||||
journal(),
|
||||
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
|
||||
|
||||
j.debug() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.is_string());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_string() == std::string{"Value1"});
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.get_int64() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test journal attributes inheritable")
|
||||
{
|
||||
beast::Journal j{
|
||||
journal(),
|
||||
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
|
||||
beast::Journal j2{j, log::attributes(log::attr("Field3", "Value3"))};
|
||||
|
||||
j2.debug() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.is_string());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_string() == std::string{"Value1"});
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field3"]
|
||||
.is_string());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field3"]
|
||||
.get_string() == std::string{"Value3"});
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.get_int64() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(JsonLogStreamFixture, "Test copying journal")
|
||||
{
|
||||
{
|
||||
beast::Journal j{
|
||||
journal(),
|
||||
log::attributes(
|
||||
log::attr("Field1", "Value1"), log::attr("Field2", 2))};
|
||||
beast::Journal j2{j};
|
||||
|
||||
j2.debug() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.is_string());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_string() == std::string{"Value1"});
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.get_int64() == 2);
|
||||
}
|
||||
{
|
||||
stream().str("");
|
||||
beast::Journal j{journal().sink()};
|
||||
beast::Journal j2{
|
||||
j,
|
||||
log::attributes(
|
||||
log::attr("Field1", "Value1"), log::attr("Field2", 2))};
|
||||
|
||||
j2.debug() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.is_string());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_string() == std::string{"Value1"});
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.get_int64() == 2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(
|
||||
JsonLogStreamFixture,
|
||||
"Test journal attributes inheritable after moving")
|
||||
{
|
||||
beast::Journal j{
|
||||
journal(),
|
||||
log::attributes(log::attr("Field1", "Value1"), log::attr("Field2", 2))};
|
||||
beast::Journal j2{j, log::attributes(log::attr("Field3", "Value3"))};
|
||||
|
||||
j2.debug() << "Test";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.is_string());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_string() == std::string{"Value1"});
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field3"]
|
||||
.is_string());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field3"]
|
||||
.get_string() == std::string{"Value3"});
|
||||
// Field2 should be overwritten to 0
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.get_int64() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(
|
||||
JsonLogStreamFixture,
|
||||
"Test journal attributes inheritable after copy assignment")
|
||||
{
|
||||
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";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.is_string());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_string() == std::string{"Value1"});
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.get_int64() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE_FIXTURE(
|
||||
JsonLogStreamFixture,
|
||||
"Test journal attributes inheritable after move assignment")
|
||||
{
|
||||
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";
|
||||
|
||||
boost::system::error_code ec;
|
||||
auto logValue = boost::json::parse(stream().str(), ec);
|
||||
CHECK(ec == boost::system::errc::success);
|
||||
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.is_string());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field1"]
|
||||
.get_string() == std::string{"Value1"});
|
||||
CHECK(logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.is_number());
|
||||
CHECK(
|
||||
logValue.as_object()["JournalParams"]
|
||||
.as_object()["Field2"]
|
||||
.get_int64() == 2);
|
||||
}
|
||||
@@ -1107,7 +1107,8 @@ RCLConsensus::startRound(
|
||||
RclConsensusLogger::RclConsensusLogger(
|
||||
char const* label,
|
||||
bool const validating,
|
||||
beast::Journal j)
|
||||
beast::Journal j,
|
||||
std::source_location location)
|
||||
: j_(j)
|
||||
{
|
||||
if (!validating && !j.info())
|
||||
@@ -1125,11 +1126,28 @@ RclConsensusLogger::~RclConsensusLogger()
|
||||
return;
|
||||
auto const duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start_);
|
||||
|
||||
std::stringstream outSs;
|
||||
outSs << header_ << "duration " << (duration.count() / 1000) << '.'
|
||||
<< std::setw(3) << std::setfill('0') << (duration.count() % 1000)
|
||||
<< "s. " << ss_->str();
|
||||
j_.sink().writeAlways(beast::severities::kInfo, outSs.str());
|
||||
|
||||
if (beast::Journal::isStructuredJournalEnabled())
|
||||
{
|
||||
thread_local std::string buffer;
|
||||
buffer.reserve(1024);
|
||||
buffer.clear();
|
||||
beast::detail::SimpleJsonWriter writer{buffer};
|
||||
writer.startObject();
|
||||
writer.writeKey("Message");
|
||||
writer.writeString(outSs.str());
|
||||
writer.endObject();
|
||||
j_.sink().writeAlways(beast::severities::kInfo, writer.finish());
|
||||
}
|
||||
else
|
||||
{
|
||||
j_.sink().writeAlways(beast::severities::kInfo, outSs.str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -553,12 +553,14 @@ class RclConsensusLogger
|
||||
beast::Journal j_;
|
||||
std::unique_ptr<std::stringstream> ss_;
|
||||
std::chrono::steady_clock::time_point start_;
|
||||
std::source_location location_;
|
||||
|
||||
public:
|
||||
explicit RclConsensusLogger(
|
||||
char const* label,
|
||||
bool validating,
|
||||
beast::Journal j);
|
||||
beast::Journal j,
|
||||
std::source_location location = std::source_location::current());
|
||||
~RclConsensusLogger();
|
||||
|
||||
std::unique_ptr<std::stringstream> const&
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_APP_LEDGER_BOOKLISTENERS_H_INCLUDED
|
||||
#define RIPPLE_APP_LEDGER_BOOKLISTENERS_H_INCLUDED
|
||||
|
||||
#include <xrpld/net/InfoSub.h>
|
||||
#include <xrpld/rpc/InfoSub.h>
|
||||
|
||||
#include <xrpl/protocol/MultiApiJson.h>
|
||||
|
||||
|
||||
@@ -832,9 +832,6 @@ public:
|
||||
bool
|
||||
serverOkay(std::string& reason) override;
|
||||
|
||||
beast::Journal
|
||||
journal(std::string const& name) override;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
bool
|
||||
@@ -1212,8 +1209,11 @@ ApplicationImp::setup(boost::program_options::variables_map const& cmdline)
|
||||
}
|
||||
|
||||
JLOG(m_journal.info()) << "Process starting: "
|
||||
<< BuildInfo::getFullVersionString()
|
||||
<< ", Instance Cookie: " << instanceCookie_;
|
||||
<< log::param(
|
||||
"RippledVersion",
|
||||
BuildInfo::getFullVersionString())
|
||||
<< ", Instance Cookie: "
|
||||
<< log::param("InstanceCookie", instanceCookie_);
|
||||
|
||||
if (numberOfThreads(*config_) < 2)
|
||||
{
|
||||
@@ -1642,6 +1642,7 @@ ApplicationImp::run()
|
||||
perfLog_->stop();
|
||||
|
||||
JLOG(m_journal.info()) << "Done.";
|
||||
logs_->flushBatch();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2160,12 +2161,6 @@ ApplicationImp::serverOkay(std::string& reason)
|
||||
return true;
|
||||
}
|
||||
|
||||
beast::Journal
|
||||
ApplicationImp::journal(std::string const& name)
|
||||
{
|
||||
return logs_->journal(name);
|
||||
}
|
||||
|
||||
void
|
||||
ApplicationImp::setMaxDisallowedLedger()
|
||||
{
|
||||
|
||||
@@ -257,8 +257,18 @@ public:
|
||||
virtual bool
|
||||
serverOkay(std::string& reason) = 0;
|
||||
|
||||
virtual beast::Journal
|
||||
journal(std::string const& name) = 0;
|
||||
template <typename TAttributesFactory>
|
||||
beast::Journal
|
||||
journal(std::string const& name, TAttributesFactory&& factory)
|
||||
{
|
||||
return logs().journal(name, std::forward<TAttributesFactory>(factory));
|
||||
}
|
||||
|
||||
beast::Journal
|
||||
journal(std::string const& name)
|
||||
{
|
||||
return logs().journal(name);
|
||||
}
|
||||
|
||||
/* Returns the number of file descriptors the application needs */
|
||||
virtual int
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
|
||||
#include <xrpld/app/main/Application.h>
|
||||
#include <xrpld/core/JobQueue.h>
|
||||
#include <xrpld/net/InfoSub.h>
|
||||
#include <xrpld/rpc/Context.h>
|
||||
#include <xrpld/rpc/GRPCHandlers.h>
|
||||
#include <xrpld/rpc/InfoSub.h>
|
||||
#include <xrpld/rpc/Role.h>
|
||||
#include <xrpld/rpc/detail/Handler.h>
|
||||
#include <xrpld/rpc/detail/RPCHelpers.h>
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include <xrpld/core/Config.h>
|
||||
#include <xrpld/core/ConfigSections.h>
|
||||
#include <xrpld/core/TimeKeeper.h>
|
||||
#include <xrpld/net/RPCCall.h>
|
||||
#include <xrpld/rpc/RPCCall.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/beast/core/CurrentThreadName.h>
|
||||
@@ -788,6 +788,11 @@ run(int argc, char** argv)
|
||||
else if (vm.count("verbose"))
|
||||
thresh = kTrace;
|
||||
|
||||
// if (config->LOG_STYLE == LogStyle::Json)
|
||||
// {
|
||||
// beast::Journal::enableStructuredJournal();
|
||||
// }
|
||||
|
||||
auto logs = std::make_unique<Logs>(thresh);
|
||||
|
||||
// No arguments. Run server.
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <xrpld/app/ledger/Ledger.h>
|
||||
#include <xrpld/core/JobQueue.h>
|
||||
#include <xrpld/ledger/ReadView.h>
|
||||
#include <xrpld/net/InfoSub.h>
|
||||
#include <xrpld/rpc/InfoSub.h>
|
||||
|
||||
#include <xrpl/protocol/STValidation.h>
|
||||
#include <xrpl/protocol/messages.h>
|
||||
|
||||
@@ -33,7 +33,12 @@ WorkSSL::WorkSSL(
|
||||
bool lastStatus,
|
||||
callback_type cb)
|
||||
: WorkBase(host, path, port, ios, lastEndpoint, lastStatus, cb)
|
||||
, context_(config, j, boost::asio::ssl::context::tlsv12_client)
|
||||
, context_(
|
||||
config.SSL_VERIFY_DIR,
|
||||
config.SSL_VERIFY_FILE,
|
||||
config.SSL_VERIFY,
|
||||
j,
|
||||
boost::asio::ssl::context::tlsv12_client)
|
||||
, stream_(socket_, context_.context())
|
||||
{
|
||||
auto ec = context_.preConnectVerify(stream_, host_);
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
|
||||
#include <xrpld/app/misc/detail/WorkBase.h>
|
||||
#include <xrpld/core/Config.h>
|
||||
#include <xrpld/net/HTTPClientSSLContext.h>
|
||||
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/net/HTTPClientSSLContext.h>
|
||||
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <xrpld/app/ledger/Ledger.h>
|
||||
#include <xrpld/app/paths/Pathfinder.h>
|
||||
#include <xrpld/app/paths/RippleLineCache.h>
|
||||
#include <xrpld/net/InfoSub.h>
|
||||
#include <xrpld/rpc/InfoSub.h>
|
||||
|
||||
#include <xrpl/basics/base_uint.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
|
||||
@@ -77,6 +77,16 @@ struct FeeSetup
|
||||
* values.) */
|
||||
};
|
||||
|
||||
/**
|
||||
* We support producing plain text logs and structured json logs.
|
||||
*/
|
||||
namespace LogStyle {
|
||||
enum LogStyle { LogFmt, Json };
|
||||
|
||||
LogStyle
|
||||
fromString(std::string const&);
|
||||
}; // namespace LogStyle
|
||||
|
||||
// This entire derived class is deprecated.
|
||||
// For new config information use the style implied
|
||||
// in the base class. For existing config information
|
||||
@@ -299,6 +309,9 @@ public:
|
||||
|
||||
std::optional<std::size_t> VALIDATOR_LIST_THRESHOLD;
|
||||
|
||||
// Set it to LogStyle::Json to get structured json logs.
|
||||
LogStyle::LogStyle LOG_STYLE = LogStyle::LogFmt;
|
||||
|
||||
public:
|
||||
Config();
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ struct ConfigSection
|
||||
#define SECTION_CLUSTER_NODES "cluster_nodes"
|
||||
#define SECTION_COMPRESSION "compression"
|
||||
#define SECTION_DEBUG_LOGFILE "debug_logfile"
|
||||
#define SECTION_LOG_STYLE "log_style"
|
||||
#define SECTION_ELB_SUPPORT "elb_support"
|
||||
#define SECTION_FEE_DEFAULT "fee_default"
|
||||
#define SECTION_FETCH_DEPTH "fetch_depth"
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include <xrpld/core/Config.h>
|
||||
#include <xrpld/core/ConfigSections.h>
|
||||
#include <xrpld/net/HTTPClient.h>
|
||||
|
||||
#include <xrpl/basics/FileUtilities.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
@@ -27,6 +26,7 @@
|
||||
#include <xrpl/basics/contract.h>
|
||||
#include <xrpl/beast/core/LexicalCast.h>
|
||||
#include <xrpl/json/json_reader.h>
|
||||
#include <xrpl/net/HTTPClient.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/SystemParameters.h>
|
||||
|
||||
@@ -409,7 +409,8 @@ Config::setup(
|
||||
legacy("database_path", boost::filesystem::absolute(dataDir).string());
|
||||
}
|
||||
|
||||
HTTPClient::initializeSSLContext(*this, j_);
|
||||
HTTPClient::initializeSSLContext(
|
||||
this->SSL_VERIFY_DIR, this->SSL_VERIFY_FILE, this->SSL_VERIFY, j_);
|
||||
|
||||
if (RUN_STANDALONE)
|
||||
LEDGER_HISTORY = 0;
|
||||
@@ -689,6 +690,11 @@ Config::loadFromString(std::string const& fileContents)
|
||||
if (getSingleSection(secConfig, SECTION_DEBUG_LOGFILE, strTemp, j_))
|
||||
DEBUG_LOGFILE = strTemp;
|
||||
|
||||
if (getSingleSection(secConfig, SECTION_LOG_STYLE, strTemp, j_))
|
||||
LOG_STYLE = LogStyle::fromString(strTemp);
|
||||
|
||||
LOG_STYLE = LogStyle::Json;
|
||||
|
||||
if (getSingleSection(secConfig, SECTION_SWEEP_INTERVAL, strTemp, j_))
|
||||
{
|
||||
SWEEP_INTERVAL = beast::lexicalCastThrow<std::size_t>(strTemp);
|
||||
@@ -1077,6 +1083,14 @@ Config::loadFromString(std::string const& fileContents)
|
||||
}
|
||||
}
|
||||
|
||||
LogStyle::LogStyle
|
||||
LogStyle::fromString(std::string const& str)
|
||||
{
|
||||
if (str == "json")
|
||||
return Json;
|
||||
return LogFmt;
|
||||
}
|
||||
|
||||
boost::filesystem::path
|
||||
Config::getDebugLogFile() const
|
||||
{
|
||||
|
||||
@@ -39,8 +39,7 @@ ConnectAttempt::ConnectAttempt(
|
||||
: Child(overlay)
|
||||
, app_(app)
|
||||
, id_(id)
|
||||
, sink_(journal, OverlayImpl::makePrefix(id))
|
||||
, journal_(sink_)
|
||||
, journal_(journal, log::attributes(log::attr("NodeID", id)))
|
||||
, remote_endpoint_(remote_endpoint)
|
||||
, usage_(usage)
|
||||
, strand_(io_service)
|
||||
|
||||
@@ -46,7 +46,6 @@ private:
|
||||
|
||||
Application& app_;
|
||||
std::uint32_t const id_;
|
||||
beast::WrappedSink sink_;
|
||||
beast::Journal const journal_;
|
||||
endpoint_type remote_endpoint_;
|
||||
Resource::Consumer usage_;
|
||||
|
||||
@@ -165,8 +165,8 @@ OverlayImpl::onHandoff(
|
||||
endpoint_type remote_endpoint)
|
||||
{
|
||||
auto const id = next_id_++;
|
||||
beast::WrappedSink sink(app_.logs()["Peer"], makePrefix(id));
|
||||
beast::Journal journal(sink);
|
||||
auto journal =
|
||||
app_.journal("Peer", log::attributes(log::attr("NodeID", id)));
|
||||
|
||||
Handoff handoff;
|
||||
if (processRequest(request, handoff))
|
||||
@@ -332,14 +332,6 @@ OverlayImpl::isPeerUpgrade(http_request_type const& request)
|
||||
return !versions.empty();
|
||||
}
|
||||
|
||||
std::string
|
||||
OverlayImpl::makePrefix(std::uint32_t id)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "[" << std::setfill('0') << std::setw(3) << id << "] ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::shared_ptr<Writer>
|
||||
OverlayImpl::makeRedirectResponse(
|
||||
std::shared_ptr<PeerFinder::Slot> const& slot,
|
||||
|
||||
@@ -341,9 +341,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string
|
||||
makePrefix(std::uint32_t id);
|
||||
|
||||
void
|
||||
reportInboundTraffic(TrafficCount::category cat, int bytes);
|
||||
|
||||
|
||||
@@ -77,10 +77,18 @@ PeerImp::PeerImp(
|
||||
: Child(overlay)
|
||||
, app_(app)
|
||||
, id_(id)
|
||||
, sink_(app_.journal("Peer"), makePrefix(id))
|
||||
, p_sink_(app_.journal("Protocol"), makePrefix(id))
|
||||
, journal_(sink_)
|
||||
, p_journal_(p_sink_)
|
||||
, journal_(
|
||||
app_.journal("Peer"),
|
||||
log::attributes(
|
||||
log::attr("NodeID", id),
|
||||
log::attr("RemoteAddress", to_string(slot->remote_endpoint()))
|
||||
))
|
||||
, p_journal_(
|
||||
app_.journal("Protocol"),
|
||||
log::attributes(
|
||||
log::attr("NodeID", id),
|
||||
log::attr("RemoteAddress", to_string(slot->remote_endpoint()))
|
||||
))
|
||||
, stream_ptr_(std::move(stream_ptr))
|
||||
, socket_(stream_ptr_->next_layer().socket())
|
||||
, stream_(*stream_ptr_)
|
||||
@@ -678,14 +686,6 @@ PeerImp::cancelTimer()
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
std::string
|
||||
PeerImp::makePrefix(id_t id)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "[" << std::setfill('0') << std::setw(3) << id << "] ";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void
|
||||
PeerImp::onTimer(error_code const& ec)
|
||||
{
|
||||
|
||||
@@ -71,8 +71,6 @@ private:
|
||||
|
||||
Application& app_;
|
||||
id_t const id_;
|
||||
beast::WrappedSink sink_;
|
||||
beast::WrappedSink p_sink_;
|
||||
beast::Journal const journal_;
|
||||
beast::Journal const p_journal_;
|
||||
std::unique_ptr<stream_type> stream_ptr_;
|
||||
@@ -456,9 +454,6 @@ private:
|
||||
void
|
||||
cancelTimer();
|
||||
|
||||
static std::string
|
||||
makePrefix(id_t id);
|
||||
|
||||
// Called when the timer wait completes
|
||||
void
|
||||
onTimer(boost::system::error_code const& ec);
|
||||
@@ -662,10 +657,18 @@ PeerImp::PeerImp(
|
||||
: Child(overlay)
|
||||
, app_(app)
|
||||
, id_(id)
|
||||
, sink_(app_.journal("Peer"), makePrefix(id))
|
||||
, p_sink_(app_.journal("Protocol"), makePrefix(id))
|
||||
, journal_(sink_)
|
||||
, p_journal_(p_sink_)
|
||||
, journal_(
|
||||
app_.journal("Peer"),
|
||||
log::attributes(
|
||||
log::attr("NodeID", id),
|
||||
log::attr("RemoteAddress", to_string(slot->remote_endpoint()))
|
||||
))
|
||||
, p_journal_(
|
||||
app_.journal("Protocol"),
|
||||
log::attributes(
|
||||
log::attr("NodeID", id),
|
||||
log::attr("RemoteAddress", to_string(slot->remote_endpoint())
|
||||
)))
|
||||
, stream_ptr_(std::move(stream_ptr))
|
||||
, socket_(stream_ptr_->next_layer().socket())
|
||||
, stream_(*stream_ptr_)
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#define RIPPLE_RPC_CONTEXT_H_INCLUDED
|
||||
|
||||
#include <xrpld/core/JobQueue.h>
|
||||
#include <xrpld/net/InfoSub.h>
|
||||
#include <xrpld/rpc/InfoSub.h>
|
||||
#include <xrpld/rpc/Role.h>
|
||||
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#define RIPPLE_NET_RPCSUB_H_INCLUDED
|
||||
|
||||
#include <xrpld/core/JobQueue.h>
|
||||
#include <xrpld/net/InfoSub.h>
|
||||
#include <xrpld/rpc/InfoSub.h>
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/net/InfoSub.h>
|
||||
#include <xrpld/rpc/InfoSub.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -17,12 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/app/main/Application.h>
|
||||
#include <xrpld/core/Config.h>
|
||||
#include <xrpld/net/HTTPClient.h>
|
||||
#include <xrpld/net/RPCCall.h>
|
||||
#include <xrpld/rpc/RPCCall.h>
|
||||
#include <xrpld/rpc/ServerHandler.h>
|
||||
#include <xrpld/rpc/detail/RPCHelpers.h>
|
||||
|
||||
#include <xrpl/basics/ByteUtilities.h>
|
||||
#include <xrpl/basics/Log.h>
|
||||
@@ -33,7 +29,10 @@
|
||||
#include <xrpl/json/json_forwards.h>
|
||||
#include <xrpl/json/json_reader.h>
|
||||
#include <xrpl/json/to_string.h>
|
||||
#include <xrpl/net/HTTPClient.h>
|
||||
#include <xrpl/protocol/ApiVersion.h>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
#include <xrpl/protocol/PublicKey.h>
|
||||
#include <xrpl/protocol/RPCErr.h>
|
||||
#include <xrpl/protocol/SystemParameters.h>
|
||||
#include <xrpl/protocol/UintTypes.h>
|
||||
@@ -160,7 +159,7 @@ private:
|
||||
std::string const& strPk,
|
||||
TokenType type = TokenType::AccountPublic)
|
||||
{
|
||||
if (parseBase58<PublicKey>(type, strPk))
|
||||
if (parseBase58<ripple::PublicKey>(type, strPk))
|
||||
return true;
|
||||
|
||||
auto pkHex = strUnHex(strPk);
|
||||
@@ -1508,7 +1507,7 @@ rpcClient(
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerHandler::Setup setup;
|
||||
ripple::ServerHandler::Setup setup;
|
||||
try
|
||||
{
|
||||
setup = setup_ServerHandler(
|
||||
@@ -24,9 +24,9 @@
|
||||
#include <xrpld/app/misc/NetworkOPs.h>
|
||||
#include <xrpld/core/Config.h>
|
||||
#include <xrpld/core/JobQueue.h>
|
||||
#include <xrpld/net/InfoSub.h>
|
||||
#include <xrpld/perflog/PerfLog.h>
|
||||
#include <xrpld/rpc/Context.h>
|
||||
#include <xrpld/rpc/InfoSub.h>
|
||||
#include <xrpld/rpc/RPCHandler.h>
|
||||
#include <xrpld/rpc/Role.h>
|
||||
#include <xrpld/rpc/detail/Handler.h>
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <xrpld/net/RPCCall.h>
|
||||
#include <xrpld/net/RPCSub.h>
|
||||
#include <xrpld/rpc/RPCCall.h>
|
||||
#include <xrpld/rpc/RPCSub.h>
|
||||
|
||||
#include <xrpl/basics/Log.h>
|
||||
#include <xrpl/basics/StringUtilities.h>
|
||||
@@ -20,7 +20,7 @@
|
||||
#ifndef RIPPLE_RPC_WSINFOSUB_H
|
||||
#define RIPPLE_RPC_WSINFOSUB_H
|
||||
|
||||
#include <xrpld/net/InfoSub.h>
|
||||
#include <xrpld/rpc/InfoSub.h>
|
||||
#include <xrpld/rpc/Role.h>
|
||||
|
||||
#include <xrpl/beast/net/IPAddressConversion.h>
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
#include <xrpld/app/main/Application.h>
|
||||
#include <xrpld/app/misc/NetworkOPs.h>
|
||||
#include <xrpld/ledger/ReadView.h>
|
||||
#include <xrpld/net/RPCSub.h>
|
||||
#include <xrpld/rpc/Context.h>
|
||||
#include <xrpld/rpc/RPCSub.h>
|
||||
#include <xrpld/rpc/Role.h>
|
||||
#include <xrpld/rpc/detail/RPCHelpers.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user