diff options
author | Henrik Edin <henrik.edin@mongodb.com> | 2020-03-09 10:02:02 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-03-13 14:36:35 +0000 |
commit | 5094b4f2f2ee9de07dc4c3d3c320e967595496f1 (patch) | |
tree | ee5aacbd54e4b8454067bfafe0fbd7c604439c9a /src/mongo | |
parent | 8c028c6959290710de551359fb296f655584d43f (diff) | |
download | mongo-5094b4f2f2ee9de07dc4c3d3c320e967595496f1.tar.gz |
SERVER-46406 Perf improvements in the logger.
Use fmt::compile and fmt::format_int when possible.
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/bson/bsonelement.cpp | 2 | ||||
-rw-r--r-- | src/mongo/bson/bsonobj.cpp | 5 | ||||
-rw-r--r-- | src/mongo/bson/bsontypes.cpp | 10 | ||||
-rw-r--r-- | src/mongo/bson/bsontypes.h | 7 | ||||
-rw-r--r-- | src/mongo/bson/generator_extended_canonical_2_0_0.h | 135 | ||||
-rw-r--r-- | src/mongo/bson/generator_extended_relaxed_2_0_0.h | 21 | ||||
-rw-r--r-- | src/mongo/db/server_options_helpers.cpp | 2 | ||||
-rw-r--r-- | src/mongo/dbtests/jsontests.cpp | 6 | ||||
-rw-r--r-- | src/mongo/logv2/json_formatter.cpp | 130 | ||||
-rw-r--r-- | src/mongo/util/time_support.cpp | 20 |
10 files changed, 240 insertions, 98 deletions
diff --git a/src/mongo/bson/bsonelement.cpp b/src/mongo/bson/bsonelement.cpp index 0574c3f8574..62693512426 100644 --- a/src/mongo/bson/bsonelement.cpp +++ b/src/mongo/bson/bsonelement.cpp @@ -94,7 +94,7 @@ BSONObj BSONElement::jsonStringBuffer(JsonStringFormat format, if (format == ExtendedCanonicalV2_0_0) return withGenerator(ExtendedCanonicalV200Generator()); else if (format == ExtendedRelaxedV2_0_0) - return withGenerator(ExtendedRelaxedV200Generator()); + return withGenerator(ExtendedRelaxedV200Generator(dateFormatIsLocalTimezone())); else if (format == LegacyStrict) { return withGenerator(LegacyStrictGenerator()); } else { diff --git a/src/mongo/bson/bsonobj.cpp b/src/mongo/bson/bsonobj.cpp index 284058feecf..4cccfa89d8e 100644 --- a/src/mongo/bson/bsonobj.cpp +++ b/src/mongo/bson/bsonobj.cpp @@ -183,7 +183,8 @@ BSONObj BSONObj::_jsonStringGenerator(const Generator& g, fmt::memory_buffer& buffer, size_t writeLimit) const { if (isEmpty()) { - fmt::format_to(buffer, "{}", isArray ? "[]" : "{}"); + const auto empty = isArray ? "[]"_sd : "{}"_sd; + buffer.append(empty.rawData(), empty.rawData() + empty.size()); return BSONObj(); } buffer.push_back(isArray ? '[' : '{'); @@ -259,7 +260,7 @@ BSONObj BSONObj::jsonStringBuffer(JsonStringFormat format, if (format == ExtendedCanonicalV2_0_0) { return withGenerator(ExtendedCanonicalV200Generator()); } else if (format == ExtendedRelaxedV2_0_0) { - return withGenerator(ExtendedRelaxedV200Generator()); + return withGenerator(ExtendedRelaxedV200Generator(dateFormatIsLocalTimezone())); } else if (format == LegacyStrict) { return withGenerator(LegacyStrictGenerator()); } else { diff --git a/src/mongo/bson/bsontypes.cpp b/src/mongo/bson/bsontypes.cpp index 8bfe513aa20..8a2c1ff7c11 100644 --- a/src/mongo/bson/bsontypes.cpp +++ b/src/mongo/bson/bsontypes.cpp @@ -36,6 +36,9 @@ #include "mongo/util/string_map.h" namespace mongo { +namespace { +bool localTimeZoneForDate = false; +} using namespace fmt::literals; const char kMaxKeyData[] = {7, 0, 0, 0, static_cast<char>(MaxKey), 0, 0}; @@ -207,4 +210,11 @@ bool isValidBinDataType(int type) { } } +void setDateFormatIsLocalTimezone(bool localTimeZone) { + localTimeZoneForDate = localTimeZone; +} +bool dateFormatIsLocalTimezone() { + return localTimeZoneForDate; +} + } // namespace mongo diff --git a/src/mongo/bson/bsontypes.h b/src/mongo/bson/bsontypes.h index 955fed80eec..b2b5b7399e8 100644 --- a/src/mongo/bson/bsontypes.h +++ b/src/mongo/bson/bsontypes.h @@ -268,6 +268,13 @@ struct FormatKind : std::integral_constant<BSONType, value> {}; template <typename T> struct BSONObjAppendFormat; +/** + * Returns whether conversion to JSON should format the Date type as local timezone. + * This is a global setting set by the systemLog.timeStampFormat server option. + */ +void setDateFormatIsLocalTimezone(bool localTimeZone); +bool dateFormatIsLocalTimezone(); + namespace bsontype_detail { /* BSONObjFallbackFormat is the trait that BSONObjAppendFormat falls back to in case there is diff --git a/src/mongo/bson/generator_extended_canonical_2_0_0.h b/src/mongo/bson/generator_extended_canonical_2_0_0.h index 91cb073721f..f0b4f1bcdf2 100644 --- a/src/mongo/bson/generator_extended_canonical_2_0_0.h +++ b/src/mongo/bson/generator_extended_canonical_2_0_0.h @@ -34,7 +34,7 @@ #include "mongo/util/base64.h" #include "mongo/util/str_escape.h" -#include <fmt/format.h> +#include <fmt/compile.h> namespace mongo { class ExtendedCanonicalV200Generator { @@ -60,17 +60,20 @@ public: } void writeInt32(fmt::memory_buffer& buffer, int32_t val) const { - fmt::format_to(buffer, R"({{"$numberInt":"{}"}})", val); + static const auto fmt_str = fmt::compile<int32_t>(R"({{"$numberInt":"{}"}})"); + compiled_format_to(buffer, fmt_str, val); } void writeInt64(fmt::memory_buffer& buffer, int64_t val) const { - fmt::format_to(buffer, R"({{"$numberLong":"{}"}})", val); + static const auto fmt_str = fmt::compile<int64_t>(R"({{"$numberLong":"{}"}})"); + compiled_format_to(buffer, fmt_str, val); } void writeDouble(fmt::memory_buffer& buffer, double val) const { + static const auto fmt_str = fmt::compile<double>(R"({{"$numberDouble":"{}"}})"); if (val >= std::numeric_limits<double>::lowest() && val <= std::numeric_limits<double>::max()) - fmt::format_to(buffer, R"({{"$numberDouble":"{}"}})", val); + compiled_format_to(buffer, fmt_str, val); else if (std::isnan(val)) appendTo(buffer, R"({"$numberDouble":"NaN"})"_sd); else if (std::isinf(val)) { @@ -86,19 +89,24 @@ public: } void writeDecimal128(fmt::memory_buffer& buffer, Decimal128 val) const { + static const auto fmt_str_infinite = + fmt::compile<StringData>(R"({{"$numberDecimal":"{}"}})"); + static const auto fmt_str_decimal = + fmt::compile<std::string>(R"({{"$numberDecimal":"{}"}})"); if (val.isNaN()) appendTo(buffer, R"({"$numberDecimal":"NaN"})"_sd); else if (val.isInfinite()) - fmt::format_to(buffer, - R"({{"$numberDecimal":"{}"}})", - val.isNegative() ? "-Infinity"_sd : "Infinity"_sd); + compiled_format_to( + buffer, fmt_str_infinite, val.isNegative() ? "-Infinity"_sd : "Infinity"_sd); else { - fmt::format_to(buffer, R"({{"$numberDecimal":"{}"}})", val.toString()); + compiled_format_to(buffer, fmt_str_decimal, val.toString()); } } void writeDate(fmt::memory_buffer& buffer, Date_t val) const { - fmt::format_to(buffer, R"({{"$date":{{"$numberLong":"{}"}}}})", val.toMillisSinceEpoch()); + static const auto fmt_str = + fmt::compile<long long>(R"({{"$date":{{"$numberLong":"{}"}}}})"); + compiled_format_to(buffer, fmt_str, val.toMillisSinceEpoch()); } void writeDBRef(fmt::memory_buffer& buffer, StringData ref, OID id) const { @@ -107,44 +115,91 @@ public: str::escapeForJSON(buffer, ref); // OID is a hex string and does not need to be escaped - fmt::format_to(buffer, R"(","$id":"{}"}})", id.toString()); + static const auto fmt_str = fmt::compile<std::string>(R"(","$id":"{}"}})"); + compiled_format_to(buffer, fmt_str, id.toString()); } void writeOID(fmt::memory_buffer& buffer, OID val) const { // OID is a hex string and does not need to be escaped - fmt::format_to(buffer, R"({{"$oid":"{}"}})", val.toString()); + static const auto fmt_str = fmt::compile<uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t>( + R"({{"$oid":"{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}"}})"); + static_assert(OID::kOIDSize == 12); + const uint8_t* data = reinterpret_cast<const uint8_t*>(val.view().view()); + compiled_format_to(buffer, + fmt_str, + data[0], + data[1], + data[2], + data[3], + data[4], + data[5], + data[6], + data[7], + data[8], + data[9], + data[10], + data[11]); } void writeTimestamp(fmt::memory_buffer& buffer, Timestamp val) const { - fmt::format_to( - buffer, R"({{"$timestamp":{{"t":{},"i":{}}}}})", val.getSecs(), val.getInc()); + static const auto fmt_str = + fmt::compile<unsigned int, unsigned int>(R"({{"$timestamp":{{"t":{},"i":{}}}}})"); + compiled_format_to(buffer, fmt_str, val.getSecs(), val.getInc()); } void writeBinData(fmt::memory_buffer& buffer, StringData data, BinDataType type) const { + static const auto fmt_str_uuid = fmt::compile<uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t, + uint8_t>( + R"({{"$uuid":"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}"}})"); + static const auto fmt_str_subtype = fmt::compile<BinDataType>(R"(","subType":"{:x}"}}}})"); if (type == newUUID && data.size() == 16) { - fmt::format_to( - buffer, - R"({{"$uuid":"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}"}})", - static_cast<uint8_t>(data[0]), - static_cast<uint8_t>(data[1]), - static_cast<uint8_t>(data[2]), - static_cast<uint8_t>(data[3]), - static_cast<uint8_t>(data[4]), - static_cast<uint8_t>(data[5]), - static_cast<uint8_t>(data[6]), - static_cast<uint8_t>(data[7]), - static_cast<uint8_t>(data[8]), - static_cast<uint8_t>(data[9]), - static_cast<uint8_t>(data[10]), - static_cast<uint8_t>(data[11]), - static_cast<uint8_t>(data[12]), - static_cast<uint8_t>(data[13]), - static_cast<uint8_t>(data[14]), - static_cast<uint8_t>(data[15])); + compiled_format_to(buffer, + fmt_str_uuid, + static_cast<uint8_t>(data[0]), + static_cast<uint8_t>(data[1]), + static_cast<uint8_t>(data[2]), + static_cast<uint8_t>(data[3]), + static_cast<uint8_t>(data[4]), + static_cast<uint8_t>(data[5]), + static_cast<uint8_t>(data[6]), + static_cast<uint8_t>(data[7]), + static_cast<uint8_t>(data[8]), + static_cast<uint8_t>(data[9]), + static_cast<uint8_t>(data[10]), + static_cast<uint8_t>(data[11]), + static_cast<uint8_t>(data[12]), + static_cast<uint8_t>(data[13]), + static_cast<uint8_t>(data[14]), + static_cast<uint8_t>(data[15])); } else { appendTo(buffer, R"({"$binary":{"base64":")"_sd); base64::encode(buffer, data); - fmt::format_to(buffer, R"(","subType":"{:x}"}}}})", type); + compiled_format_to(buffer, fmt_str_subtype, type); } } @@ -188,5 +243,19 @@ protected: static void appendTo(fmt::memory_buffer& buffer, StringData data) { buffer.append(data.begin(), data.end()); } + + static void appendTo(fmt::memory_buffer& buffer, const fmt::format_int& data) { + buffer.append(data.data(), data.data() + data.size()); + } + + template <typename CompiledFormatStr, typename... Args> + static void compiled_format_to(fmt::memory_buffer& buffer, + const CompiledFormatStr& fmt_str, + const Args&... args) { + fmt::internal::cf::vformat_to<fmt::buffer_context<char>>( + fmt::buffer_range(buffer), + fmt_str, + {fmt::make_format_args<fmt::buffer_context<char>>(args...)}); + } }; } // namespace mongo diff --git a/src/mongo/bson/generator_extended_relaxed_2_0_0.h b/src/mongo/bson/generator_extended_relaxed_2_0_0.h index 20484798e9f..792374217f5 100644 --- a/src/mongo/bson/generator_extended_relaxed_2_0_0.h +++ b/src/mongo/bson/generator_extended_relaxed_2_0_0.h @@ -34,6 +34,8 @@ namespace mongo { class ExtendedRelaxedV200Generator : private ExtendedCanonicalV200Generator { public: + // Use date with local timezone, otherwise UTC. + explicit ExtendedRelaxedV200Generator(bool localDate) : _localDate(localDate) {} using ExtendedCanonicalV200Generator::writeBinData; using ExtendedCanonicalV200Generator::writeBool; using ExtendedCanonicalV200Generator::writeCode; @@ -52,17 +54,20 @@ public: using ExtendedCanonicalV200Generator::writeUndefined; void writeInt32(fmt::memory_buffer& buffer, int32_t val) const { - fmt::format_to(buffer, R"({})", val); + fmt::format_int str(val); + appendTo(buffer, str); } void writeInt64(fmt::memory_buffer& buffer, int64_t val) const { - fmt::format_to(buffer, R"({})", val); + fmt::format_int str(val); + appendTo(buffer, str); } void writeDouble(fmt::memory_buffer& buffer, double val) const { + static const auto fmt_str = fmt::compile<double>(R"({})"); if (val >= std::numeric_limits<double>::lowest() && val <= std::numeric_limits<double>::max()) - fmt::format_to(buffer, R"({})", val); + compiled_format_to(buffer, fmt_str, val); else { ExtendedCanonicalV200Generator::writeDouble(buffer, val); } @@ -76,10 +81,18 @@ public: // handles both the case where Date_t::millis is too large, and the case where // Date_t::millis is negative (before the epoch). if (val.isFormattable()) { - fmt::format_to(buffer, R"({{"$date":"{}"}})", dateToISOStringLocal(val)); + appendTo(buffer, R"({"$date":")"_sd); + if (_localDate) + outputDateAsISOStringLocal(buffer, val); + else + outputDateAsISOStringUTC(buffer, val); + appendTo(buffer, R"("})"); } else { ExtendedCanonicalV200Generator::writeDate(buffer, val); } } + +private: + bool _localDate; }; } // namespace mongo diff --git a/src/mongo/db/server_options_helpers.cpp b/src/mongo/db/server_options_helpers.cpp index 163cb6ce737..46380edfa36 100644 --- a/src/mongo/db/server_options_helpers.cpp +++ b/src/mongo/db/server_options_helpers.cpp @@ -313,9 +313,11 @@ Status storeBaseOptions(const moe::Environment& params) { if (formatterName == "iso8601-utc") { MessageEventDetailsEncoder::setDateFormatter(outputDateAsISOStringUTC); serverGlobalParams.logTimestampFormat = logv2::LogTimestampFormat::kISO8601UTC; + setDateFormatIsLocalTimezone(false); } else if (formatterName == "iso8601-local") { MessageEventDetailsEncoder::setDateFormatter(outputDateAsISOStringLocal); serverGlobalParams.logTimestampFormat = logv2::LogTimestampFormat::kISO8601Local; + setDateFormatIsLocalTimezone(true); } else { StringBuilder sb; sb << "Value of logTimestampFormat must be one of iso8601-utc " diff --git a/src/mongo/dbtests/jsontests.cpp b/src/mongo/dbtests/jsontests.cpp index 5e3819808d2..cabe399bcba 100644 --- a/src/mongo/dbtests/jsontests.cpp +++ b/src/mongo/dbtests/jsontests.cpp @@ -392,8 +392,14 @@ TEST(JsonStringTest, Date) { BSONObj built = b.done(); ASSERT_JSON_EQUALS(R"({ "a" : { "$date" : { "$numberLong" : "0" } } })", built.jsonString(ExtendedCanonicalV2_0_0)); + bool prev = dateFormatIsLocalTimezone(); + setDateFormatIsLocalTimezone(true); ASSERT_JSON_EQUALS(R"({ "a" : { "$date" : "1969-12-31T19:00:00.000-0500" } })", built.jsonString(ExtendedRelaxedV2_0_0)); + setDateFormatIsLocalTimezone(false); + ASSERT_JSON_EQUALS(R"({ "a" : { "$date" : "1970-01-01T00:00:00.000Z" } })", + built.jsonString(ExtendedRelaxedV2_0_0)); + setDateFormatIsLocalTimezone(prev); ASSERT_EQUALS(R"({ "a" : { "$date" : "1969-12-31T19:00:00.000-0500" } })", built.jsonString(LegacyStrict)); diff --git a/src/mongo/logv2/json_formatter.cpp b/src/mongo/logv2/json_formatter.cpp index 2d796f6bbad..2bc619918ac 100644 --- a/src/mongo/logv2/json_formatter.cpp +++ b/src/mongo/logv2/json_formatter.cpp @@ -47,10 +47,21 @@ #include "mongo/util/str_escape.h" #include "mongo/util/time_support.h" +#include <fmt/compile.h> #include <fmt/format.h> namespace mongo::logv2 { namespace { +template <typename CompiledFormatStr, typename... Args> +static void compiled_format_to(fmt::memory_buffer& buffer, + const CompiledFormatStr& fmt_str, + const Args&... args) { + fmt::internal::cf::vformat_to<fmt::buffer_context<char>>( + fmt::buffer_range(buffer), + fmt_str, + {fmt::make_format_args<fmt::buffer_context<char>>(args...)}); +} + struct JSONValueExtractor { JSONValueExtractor(fmt::memory_buffer& buffer, size_t attributeMaxSize) : _buffer(buffer), _attributeMaxSize(attributeMaxSize) {} @@ -135,8 +146,10 @@ struct JSONValueExtractor { void operator()(StringData name, const Duration<Period>& value) { // A suffix is automatically prepended dassert(!name.endsWith(value.mongoUnitSuffix())); - fmt::format_to( - _buffer, R"({}"{}{}":{})", _separator, name, value.mongoUnitSuffix(), value.count()); + static const auto fmt_str = + fmt::compile<StringData, StringData, StringData, int64_t>(R"({}"{}{}":{})"); + compiled_format_to( + _buffer, fmt_str, _separator, name, value.mongoUnitSuffix(), value.count()); _separator = ","_sd; } @@ -155,19 +168,22 @@ struct JSONValueExtractor { private: void storeUnquoted(StringData name) { - fmt::format_to(_buffer, R"({}"{}":)", _separator, name); + static const auto fmt_str = fmt::compile<StringData, StringData>(R"({}"{}":)"); + compiled_format_to(_buffer, fmt_str, _separator, name); _separator = ","_sd; } template <typename T> void storeUnquotedValue(StringData name, const T& value) { - fmt::format_to(_buffer, R"({}"{}":{})", _separator, name, value); + static const auto fmt_str = fmt::compile<StringData, StringData, T>(R"({}"{}":{})"); + compiled_format_to(_buffer, fmt_str, _separator, name, value); _separator = ","_sd; } template <typename T> void storeQuoted(StringData name, const T& value) { - fmt::format_to(_buffer, R"({}"{}":")", _separator, name); + static const auto fmt_str = fmt::compile<StringData, StringData>(R"({}"{}":")"); + compiled_format_to(_buffer, fmt_str, _separator, name); std::size_t before = _buffer.size(); str::escapeForJSON(_buffer, value); if (_attributeMaxSize != 0) { @@ -220,22 +236,13 @@ void JSONFormatter::operator()(boost::log::record_view const& rec, extract<LogSeverity>(attributes::severity(), rec).get().toStringDataCompact(); StringData component = extract<LogComponent>(attributes::component(), rec).get().getNameForLog(); - std::string tag; - LogTag tags = extract<LogTag>(attributes::tags(), rec).get(); - if (tags != LogTag::kNone) { - tag = fmt::format( - ",\"{}\":{}", - constants::kTagsFieldName, - tags.toBSONArray().jsonString(JsonStringFormat::ExtendedRelaxedV2_0_0, 0, true)); - } fmt::memory_buffer buffer; // Put all fields up until the message value - fmt::format_to(buffer, - R"({{)" - R"("{}":{{"$date":")", - constants::kTimestampFieldName); + static const auto fmt_str_open = fmt::compile<StringData>(R"({{)" + R"("{}":{{"$date":")"); + compiled_format_to(buffer, fmt_str_open, constants::kTimestampFieldName); Date_t date = extract<Date_t>(attributes::timeStamp(), rec).get(); switch (_timestampFormat) { case LogTimestampFormat::kISO8601UTC: @@ -245,37 +252,55 @@ void JSONFormatter::operator()(boost::log::record_view const& rec, outputDateAsISOStringLocal(buffer, date); break; }; - fmt::format_to(buffer, - R"("}},)" // close timestamp - R"("{}":"{}"{: <{}})" // severity with padding for the comma - R"("{}":"{}"{: <{}})" // component with padding for the comma - R"("{}":{},)" // id - R"("{}":"{}",)" // context - R"("{}":")", // message - // severity, left align the comma and add padding to create fixed column width - constants::kSeverityFieldName, - severity, - ",", - 3 - severity.size(), - // component, left align the comma and add padding to create fixed column width - constants::kComponentFieldName, - component, - ",", - 9 - component.size(), - // id - constants::kIdFieldName, - extract<int32_t>(attributes::id(), rec).get(), - // context - constants::kContextFieldName, - extract<StringData>(attributes::threadName(), rec).get(), - // message - constants::kMessageFieldName); + static const auto fmt_str_body = + fmt::compile<StringData, + StringData, + StringData, + int, + StringData, + StringData, + StringData, + int, + StringData, + int32_t, + StringData, + StringData, + StringData>(R"("}},)" // close timestamp + R"("{}":"{}"{: <{}})" // severity with padding for the comma + R"("{}":"{}"{: <{}})" // component with padding for the comma + R"("{}":{},)" // id + R"("{}":"{}",)" // context + R"("{}":")" // message + ); + compiled_format_to( + buffer, + fmt_str_body, + // severity, left align the comma and add padding to create fixed column width + constants::kSeverityFieldName, + severity, + ","_sd, + 3 - severity.size(), + // component, left align the comma and add padding to create fixed column width + constants::kComponentFieldName, + component, + ","_sd, + 9 - component.size(), + // id + constants::kIdFieldName, + extract<int32_t>(attributes::id(), rec).get(), + // context + constants::kContextFieldName, + extract<StringData>(attributes::threadName(), rec).get(), + // message + constants::kMessageFieldName); str::escapeForJSON(buffer, extract<StringData>(attributes::message(), rec).get()); buffer.push_back('"'); + static const auto fmt_str_attr = fmt::compile<StringData>(R"(,"{}":{{)"); + static const auto fmt_str_truncated = fmt::compile<StringData>(R"(,"{}":)"); if (!attrs.empty()) { - fmt::format_to(buffer, R"(,"{}":{{)", constants::kAttributesFieldName); + compiled_format_to(buffer, fmt_str_attr, constants::kAttributesFieldName); // comma separated list of attributes (no opening/closing brace are added here) size_t attributeMaxSize = 0; if (extract<LogTruncation>(attributes::truncation(), rec).get() == LogTruncation::Enabled) { @@ -289,24 +314,27 @@ void JSONFormatter::operator()(boost::log::record_view const& rec, buffer.push_back('}'); if (BSONObj truncated = extractor.truncated(); !truncated.isEmpty()) { - fmt::format_to(buffer, R"(,"{}":)", constants::kTruncatedFieldName); + compiled_format_to(buffer, fmt_str_truncated, constants::kTruncatedFieldName); truncated.jsonStringBuffer( JsonStringFormat::ExtendedRelaxedV2_0_0, 0, false, buffer, 0); } if (BSONObj truncatedSizes = extractor.truncatedSizes(); !truncatedSizes.isEmpty()) { - fmt::format_to(buffer, R"(,"{}":)", constants::kTruncatedSizeFieldName); + compiled_format_to(buffer, fmt_str_truncated, constants::kTruncatedSizeFieldName); truncatedSizes.jsonStringBuffer( JsonStringFormat::ExtendedRelaxedV2_0_0, 0, false, buffer, 0); } } - // Add remaining fields - fmt::format_to(buffer, - R"({})" // optional tags - R"(}})", - // tags - tag); + LogTag tags = extract<LogTag>(attributes::tags(), rec).get(); + static const auto fmt_str_tags = fmt::compile<StringData>(R"(,"{}":)"); + if (tags != LogTag::kNone) { + compiled_format_to(buffer, fmt_str_tags, constants::kTagsFieldName); + tags.toBSONArray().jsonStringBuffer( + JsonStringFormat::ExtendedRelaxedV2_0_0, 0, true, buffer); + } + + buffer.push_back('}'); // Write final JSON object to output stream strm.write(buffer.data(), buffer.size()); diff --git a/src/mongo/util/time_support.cpp b/src/mongo/util/time_support.cpp index 2e1c98b88ef..1c7a353d439 100644 --- a/src/mongo/util/time_support.cpp +++ b/src/mongo/util/time_support.cpp @@ -36,6 +36,8 @@ #include <iostream> #include <string> +#include <fmt/compile.h> + #include "mongo/base/init.h" #include "mongo/base/parse_number.h" #include "mongo/bson/util/builder.h" @@ -178,7 +180,10 @@ void _dateToISOString(Date_t date, bool local, DateStringBuffer* result) { dassert(0 < pos); char* cur = buf + pos; int bufRemaining = bufSize - pos; - pos = snprintf(cur, bufRemaining, ".%03d", static_cast<int32_t>(date.asInt64() % 1000)); + static const auto fmt_str_millis = fmt::compile<int32_t>(".{:03}"); + pos = fmt::format_to_n( + cur, bufRemaining, fmt_str_millis, static_cast<int32_t>(date.asInt64() % 1000)) + .size; dassert(bufRemaining > pos && pos > 0); cur += pos; bufRemaining -= pos; @@ -199,12 +204,13 @@ void _dateToISOString(Date_t date, bool local, DateStringBuffer* result) { const long tzOffsetSeconds = msTimeZone * (tzIsWestOfUTC ? 1 : -1); const long tzOffsetHoursPart = tzOffsetSeconds / 3600; const long tzOffsetMinutesPart = (tzOffsetSeconds / 60) % 60; - snprintf(cur, - localTzSubstrLen + 1, - "%c%02ld%02ld", - tzIsWestOfUTC ? '-' : '+', - tzOffsetHoursPart, - tzOffsetMinutesPart); + static const auto fmt_str_time = fmt::compile<char, long, long>("{}{:02}{:02}"); + fmt::format_to_n(cur, + localTzSubstrLen + 1, + fmt_str_time, + tzIsWestOfUTC ? '-' : '+', + tzOffsetHoursPart, + tzOffsetMinutesPart); #else strftime(cur, bufRemaining, "%z", &t); #endif |