Performance improvements

This commit is contained in:
JCW
2026-04-29 22:39:13 +01:00
parent cd94d7d99b
commit 06193bde5d
2 changed files with 56 additions and 39 deletions

View File

@@ -102,10 +102,10 @@ class Logger
*/
class Pump final
{
std::shared_ptr<spdlog::logger> logger_;
spdlog::logger* logger_;
Severity const severity_;
std::source_location const sourceLocation_;
std::string stream_;
fmt::memory_buffer stream_;
bool const enabled_;
bool const jsonMode_;
std::string parameters_; // accumulated JSON parameter fragments
@@ -113,11 +113,7 @@ class Logger
public:
~Pump();
Pump(
std::shared_ptr<spdlog::logger> logger,
Severity sev,
std::source_location const& loc,
bool jsonMode);
Pump(spdlog::logger* logger, Severity sev, std::source_location const& loc, bool jsonMode);
Pump(Pump&&) = delete;
Pump(Pump const&) = delete;
@@ -142,12 +138,15 @@ class Logger
operator<<(T&& data)
{
if (enabled_)
stream_ += to_string(data);
{
auto const s = to_string(data);
stream_.append(s.data(), s.data() + s.size());
}
return *this;
}
/**
* @brief Appends any fmt-formattable data into the output string.
* @brief Appends any fmt-formattable data into the output buffer.
*
* Fallback for types that do not have an @c xrpl::to_string overload
* but can be formatted by @c fmt::format (e.g. arithmetic types,
@@ -163,14 +162,14 @@ class Logger
operator<<(T&& data)
{
if (enabled_)
fmt::format_to(std::back_inserter(stream_), "{}", std::forward<T>(data));
fmt::format_to(fmt::appender(stream_), "{}", std::forward<T>(data));
return *this;
}
/**
* @brief Captures a structured log parameter.
*
* The parameter value is always appended to the output string.
* The parameter value is always appended to the output buffer.
* In JSON mode, the parameter is also accumulated into the
* parameters string for the "values" object emitted in the
* destructor.
@@ -186,14 +185,15 @@ class Logger
if (!enabled_)
return *this;
// Append the raw string representation to the output stream
// Append the raw string representation to the output buffer
if constexpr (detail::HasToString<T>)
{
stream_ += to_string(p.value());
auto const s = to_string(p.value());
stream_.append(s.data(), s.data() + s.size());
}
else
{
fmt::format_to(std::back_inserter(stream_), "{}", p.value());
fmt::format_to(fmt::appender(stream_), "{}", p.value());
}
if (jsonMode_)

View File

@@ -174,13 +174,14 @@ createPatternFormatter(std::string const& pattern)
* @param message The message to potentially truncate (modified in-place)
*/
static void
truncateMessage(std::string& message)
truncateMessage(fmt::memory_buffer& message)
{
static constexpr std::size_t kMAX_MESSAGE_CHARS = 12 * 1024;
if (message.size() > kMAX_MESSAGE_CHARS)
{
message.resize(kMAX_MESSAGE_CHARS - 3);
message += "...";
static constexpr char kELLIPSIS[] = "...";
message.append(kELLIPSIS, kELLIPSIS + 3);
}
}
@@ -196,25 +197,33 @@ truncateMessage(std::string& message)
* @param output The log message to scrub (modified in-place)
*/
static void
scrubSecrets(std::string& output)
scrubSecrets(fmt::memory_buffer& output)
{
auto scrubber = [&output](char const* token) {
auto first = output.find(token);
// Fast path: if there's no double-quote anywhere in the message,
// none of the JSON-like tokens can possibly match.
std::string_view const view{output.data(), output.size()};
if (view.find('"') == std::string_view::npos)
return;
// We need string operations (find/replace) so convert temporarily.
// This is only reached for messages that contain at least one '"'.
std::string tmp{view};
auto scrubber = [&tmp](char const* token) {
auto first = tmp.find(token);
// If we have found the specified token, then attempt to isolate the
// sensitive data (it's enclosed by double quotes) and mask it off:
if (first != std::string::npos)
{
first = output.find('\"', first + std::strlen(token));
first = tmp.find('\"', first + std::strlen(token));
if (first != std::string::npos)
{
auto last = output.find('\"', ++first);
auto last = tmp.find('\"', ++first);
if (last == std::string::npos)
last = output.size();
last = tmp.size();
output.replace(first, last - first, last - first, '*');
tmp.replace(first, last - first, last - first, '*');
}
}
};
@@ -226,6 +235,10 @@ scrubSecrets(std::string& output)
scrubber("\"master_seed\"");
scrubber("\"master_seed_hex\"");
scrubber("\"passphrase\"");
// Copy the scrubbed result back into the buffer
output.clear();
output.append(tmp.data(), tmp.data() + tmp.size());
}
/**
@@ -538,11 +551,11 @@ Logger::~Logger()
}
Logger::Pump::Pump(
std::shared_ptr<spdlog::logger> logger,
spdlog::logger* logger,
Severity sev,
std::source_location const& loc,
bool jsonMode)
: logger_(std::move(logger))
: logger_(logger)
, severity_(sev)
, sourceLocation_(loc)
, enabled_(logger_ != nullptr && logger_->should_log(toSpdlogLevel(sev)))
@@ -551,7 +564,7 @@ Logger::Pump::Pump(
if (enabled_ && jsonMode_)
{
// Open the quoted message value
stream_ += "\"";
stream_.push_back('"');
}
}
@@ -565,14 +578,15 @@ Logger::Pump::~Pump()
if (jsonMode_)
{
// Close the quoted message value
stream_ += "\"";
stream_.push_back('"');
// Append the parameters object if any were captured
if (!parameters_.empty())
{
stream_ += ", \"values\": {";
stream_ += parameters_;
stream_ += "}";
static constexpr char kVALUES_OPEN[] = ", \"values\": {";
stream_.append(kVALUES_OPEN, kVALUES_OPEN + sizeof(kVALUES_OPEN) - 1);
stream_.append(parameters_.data(), parameters_.data() + parameters_.size());
stream_.push_back('}');
}
}
@@ -580,39 +594,42 @@ Logger::Pump::~Pump()
truncateMessage(stream_);
scrubSecrets(stream_);
logger_->log(sourceLocation, toSpdlogLevel(severity_), stream_);
logger_->log(
sourceLocation,
toSpdlogLevel(severity_),
std::string_view{stream_.data(), stream_.size()});
}
}
Logger::Pump
Logger::trace(std::source_location const& loc) const
{
return {logger_, Severity::TRC, loc, LogServiceState::jsonMode_};
return {logger_.get(), Severity::TRC, loc, LogServiceState::jsonMode_};
}
Logger::Pump
Logger::debug(std::source_location const& loc) const
{
return {logger_, Severity::DBG, loc, LogServiceState::jsonMode_};
return {logger_.get(), Severity::DBG, loc, LogServiceState::jsonMode_};
}
Logger::Pump
Logger::info(std::source_location const& loc) const
{
return {logger_, Severity::NFO, loc, LogServiceState::jsonMode_};
return {logger_.get(), Severity::NFO, loc, LogServiceState::jsonMode_};
}
Logger::Pump
Logger::warn(std::source_location const& loc) const
{
return {logger_, Severity::WRN, loc, LogServiceState::jsonMode_};
return {logger_.get(), Severity::WRN, loc, LogServiceState::jsonMode_};
}
Logger::Pump
Logger::error(std::source_location const& loc) const
{
return {logger_, Severity::ERR, loc, LogServiceState::jsonMode_};
return {logger_.get(), Severity::ERR, loc, LogServiceState::jsonMode_};
}
Logger::Pump
Logger::fatal(std::source_location const& loc) const
{
return {logger_, Severity::FTL, loc, LogServiceState::jsonMode_};
return {logger_.get(), Severity::FTL, loc, LogServiceState::jsonMode_};
}
Logger::Logger(std::shared_ptr<spdlog::logger> logger) : logger_(std::move(logger))