summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrik Edin <henrik.edin@mongodb.com>2020-03-09 10:02:02 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-03-16 20:30:55 +0000
commitbc43f398697282a5fedb129d6913ef09244af6fb (patch)
treefbaeea0a6540529cb00ba727670d91f0d0002330
parent5bcfba339f09cfb927c6c734f5ac28c65a337b0c (diff)
downloadmongo-bc43f398697282a5fedb129d6913ef09244af6fb.tar.gz
SERVER-46406 Perf improvements in the logger.
Use fmt::compile and fmt::format_int when possible. (cherry picked from commit 5094b4f2f2ee9de07dc4c3d3c320e967595496f1)
-rw-r--r--src/mongo/bson/bsonelement.cpp2
-rw-r--r--src/mongo/bson/bsonobj.cpp5
-rw-r--r--src/mongo/bson/bsontypes.cpp10
-rw-r--r--src/mongo/bson/bsontypes.h7
-rw-r--r--src/mongo/bson/generator_extended_canonical_2_0_0.h135
-rw-r--r--src/mongo/bson/generator_extended_relaxed_2_0_0.h21
-rw-r--r--src/mongo/db/server_options_helpers.cpp2
-rw-r--r--src/mongo/dbtests/jsontests.cpp6
-rw-r--r--src/mongo/logv2/json_formatter.cpp130
-rw-r--r--src/mongo/util/time_support.cpp20
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