diff --git a/src/libxrpl/beast/utility/beast_Journal.cpp b/src/libxrpl/beast/utility/beast_Journal.cpp index e6c067d286..1b4f9b375a 100644 --- a/src/libxrpl/beast/utility/beast_Journal.cpp +++ b/src/libxrpl/beast/utility/beast_Journal.cpp @@ -19,8 +19,6 @@ #include -#include - #include #include #include @@ -30,6 +28,88 @@ 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::globalLogAttributes_; std::shared_mutex Journal::globalLogAttributesMutex_; bool Journal::jsonLogsEnabled_ = false; @@ -196,9 +276,10 @@ Journal::JsonLogContext::start( writer().writeString(severityStr); auto nowMs = std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch()); + std::chrono::system_clock::now().time_since_epoch()) + .count(); writer().writeKey("Tm"); - writer().writeString(date::format("%Y-%b-%d %T %Z", nowMs)); + writer().writeString(fastTimestampToString(nowMs)); writer().endObject(); diff --git a/src/tests/libxrpl/basics/log.cpp b/src/tests/libxrpl/basics/log.cpp index a0bcb7ef82..90755e2681 100644 --- a/src/tests/libxrpl/basics/log.cpp +++ b/src/tests/libxrpl/basics/log.cpp @@ -55,7 +55,7 @@ private: void write( beast::severities::Severity level, - beast::Journal::StringBuffer text) override + std::string const& text) override { logs_.write(level, partition_, text, false); } @@ -63,7 +63,7 @@ private: void writeAlways( beast::severities::Severity level, - beast::Journal::StringBuffer text) override + std::string const& text) override { logs_.write(level, partition_, text, false); } @@ -89,19 +89,17 @@ public: write( beast::severities::Severity level, std::string const& partition, - beast::Journal::StringBuffer text, + std::string const& text, bool console) { std::string s; - std::string_view result = text.str(); + std::string_view result = text; if (!beast::Journal::isStructuredJournalEnabled()) { - format(s, text.str(), level, partition); - text.str() = s; - result = text.str(); + format(s, text, level, partition); + result = s; } logStream_.append(result); - beast::Journal::returnStringBuffer(std::move(text)); } }; @@ -363,18 +361,18 @@ public: } void - write(beast::severities::Severity level, beast::Journal::StringBuffer text) + write(beast::severities::Severity level, std::string const& text) override { - strm_ << text.str(); + strm_ << text; } void writeAlways( beast::severities::Severity level, - beast::Journal::StringBuffer text) override + std::string const& text) override { - strm_ << text.str(); + strm_ << text; } };