summaryrefslogtreecommitdiff
path: root/src/mongo/logv2
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2021-03-12 14:35:50 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-03-17 07:27:12 +0000
commitdc68f885b80e70805eab8c5686ee0941bbdd806b (patch)
treed01370941d5f6b9e4710f2ed6c2bdf9d4a61ab25 /src/mongo/logv2
parent586beac1d4c9d6ba08b986a79e83fc9374b4ead0 (diff)
downloadmongo-dc68f885b80e70805eab8c5686ee0941bbdd806b.tar.gz
SERVER-45445 Upgrade third_party/fmt (6.1.1 -> 7.1.3)
Diffstat (limited to 'src/mongo/logv2')
-rw-r--r--src/mongo/logv2/README.md6
-rw-r--r--src/mongo/logv2/attribute_storage.h28
-rw-r--r--src/mongo/logv2/bson_formatter.cpp1
-rw-r--r--src/mongo/logv2/json_formatter.cpp46
-rw-r--r--src/mongo/logv2/log_attr.h21
-rw-r--r--src/mongo/logv2/log_debug.h50
-rw-r--r--src/mongo/logv2/log_detail.cpp61
-rw-r--r--src/mongo/logv2/log_detail.h4
-rw-r--r--src/mongo/logv2/name_extractor.h52
-rw-r--r--src/mongo/logv2/plain_formatter.cpp107
10 files changed, 159 insertions, 217 deletions
diff --git a/src/mongo/logv2/README.md b/src/mongo/logv2/README.md
index d8f19afd0a4..388abfdaae6 100644
--- a/src/mongo/logv2/README.md
+++ b/src/mongo/logv2/README.md
@@ -785,7 +785,7 @@ feature that we don't want to exclude entirely, but it makes sense to lean on
it only when absolutely necessary.
[relaxed_json_2]: https://github.com/mongodb/specifications/blob/master/source/extended-json.rst
-[libfmt]: https://fmt.dev/6.1.1/index.html
-[libfmt_syn]: https://fmt.dev/6.1.1/syntax.html#formatspec
+[libfmt]: https://fmt.dev/7.1.3/index.html
+[libfmt_syn]: https://fmt.dev/7.1.3/syntax.html#formatspec
[_lastOplogEntryFetcherCallbackForStopTimestamp]: https://github.com/mongodb/mongo/blob/13caf3c499a22c2274bd533043eb7e06e6f8e8a4/src/mongo/db/repl/initial_syncer.cpp#L1500-L1512
-[_summarizeRollback]: https://github.com/mongodb/mongo/blob/13caf3c499a22c2274bd533043eb7e06e6f8e8a4/src/mongo/db/repl/rollback_impl.cpp#L1263-L1305 \ No newline at end of file
+[_summarizeRollback]: https://github.com/mongodb/mongo/blob/13caf3c499a22c2274bd533043eb7e06e6f8e8a4/src/mongo/db/repl/rollback_impl.cpp#L1263-L1305
diff --git a/src/mongo/logv2/attribute_storage.h b/src/mongo/logv2/attribute_storage.h
index 6c03caaa9e5..862e6c8d6a5 100644
--- a/src/mongo/logv2/attribute_storage.h
+++ b/src/mongo/logv2/attribute_storage.h
@@ -553,10 +553,10 @@ private:
class NamedAttribute {
public:
NamedAttribute() = default;
- NamedAttribute(StringData n, long double val) = delete;
+ NamedAttribute(const char* n, long double val) = delete;
template <typename T>
- NamedAttribute(StringData n, const boost::optional<T>& val)
+ NamedAttribute(const char* n, const boost::optional<T>& val)
: NamedAttribute(val ? NamedAttribute(n, *val) : NamedAttribute()) {
if (!val) {
name = n;
@@ -565,9 +565,9 @@ public:
}
template <typename T>
- NamedAttribute(StringData n, const T& val) : name(n), value(mapValue(val)) {}
+ NamedAttribute(const char* n, const T& val) : name(n), value(mapValue(val)) {}
- StringData name;
+ const char* name = nullptr;
stdx::variant<int,
unsigned int,
long long,
@@ -593,8 +593,7 @@ template <typename... Args>
class AttributeStorage {
public:
AttributeStorage(const Args&... args)
- : _data{detail::NamedAttribute(StringData(args.name.data(), args.name.size()),
- args.value)...} {}
+ : _data{detail::NamedAttribute(args.name, args.value)...} {}
private:
static const size_t kNumArgs = sizeof...(Args);
@@ -623,26 +622,26 @@ public:
std::is_enum_v<T> || detail::isDuration<T>,
int> = 0>
void add(const char (&name)[N], T value) {
- _attributes.emplace_back(StringData(name, N - 1), value);
+ _attributes.emplace_back(name, value);
}
template <size_t N>
void add(const char (&name)[N], BSONObj value) {
BSONObj owned = value.getOwned();
- _attributes.emplace_back(StringData(name, N - 1), owned);
+ _attributes.emplace_back(name, owned);
}
template <size_t N>
void add(const char (&name)[N], BSONArray value) {
BSONArray owned = static_cast<BSONArray>(value.getOwned());
- _attributes.emplace_back(StringData(name, N - 1), owned);
+ _attributes.emplace_back(name, owned);
}
template <size_t N,
typename T,
std::enable_if_t<std::is_class_v<T> && !detail::isDuration<T>, int> = 0>
void add(const char (&name)[N], const T& value) {
- _attributes.emplace_back(StringData(name, N - 1), value);
+ _attributes.emplace_back(name, value);
}
template <size_t N,
@@ -652,7 +651,7 @@ public:
template <size_t N>
void add(const char (&name)[N], StringData value) {
- _attributes.emplace_back(StringData(name, N - 1), value);
+ _attributes.emplace_back(name, value);
}
// Deep copies the string instead of taking it by reference
@@ -665,7 +664,7 @@ public:
// Does not have the protections of add() above. Be careful about lifetime of value!
template <size_t N, typename T>
void addUnsafe(const char (&name)[N], const T& value) {
- _attributes.emplace_back(StringData(name, N - 1), value);
+ _attributes.emplace_back(name, value);
}
private:
@@ -711,9 +710,8 @@ public:
// Applies a function to every stored named attribute in order they are captured
template <typename Func>
void apply(Func&& f) const {
- std::for_each(_data, _data + _size, [&f](const detail::NamedAttribute& attr) {
- StringData name = attr.name;
- stdx::visit([name, &f](auto&& val) { f(name, val); }, attr.value);
+ std::for_each(_data, _data + _size, [&](const auto& attr) {
+ stdx::visit([&](auto&& val) { f(attr.name, val); }, attr.value);
});
}
diff --git a/src/mongo/logv2/bson_formatter.cpp b/src/mongo/logv2/bson_formatter.cpp
index 5cf150a02c3..ff3f87493cf 100644
--- a/src/mongo/logv2/bson_formatter.cpp
+++ b/src/mongo/logv2/bson_formatter.cpp
@@ -40,7 +40,6 @@
#include "mongo/logv2/log_component.h"
#include "mongo/logv2/log_severity.h"
#include "mongo/logv2/log_tag.h"
-#include "mongo/logv2/name_extractor.h"
#include "mongo/util/time_support.h"
#include <fmt/format.h>
diff --git a/src/mongo/logv2/json_formatter.cpp b/src/mongo/logv2/json_formatter.cpp
index 98df9bb898c..2dc65831014 100644
--- a/src/mongo/logv2/json_formatter.cpp
+++ b/src/mongo/logv2/json_formatter.cpp
@@ -29,7 +29,6 @@
#include "mongo/logv2/json_formatter.h"
-#include <boost/container/small_vector.hpp>
#include <boost/log/attributes/value_extraction.hpp>
#include <boost/log/expressions/message.hpp>
#include <boost/log/utility/formatting_ostream.hpp>
@@ -38,7 +37,6 @@
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/logv2/attributes.h"
#include "mongo/logv2/constants.h"
-#include "mongo/logv2/name_extractor.h"
#include "mongo/util/str_escape.h"
#include <fmt/compile.h>
@@ -46,21 +44,12 @@
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) {}
- void operator()(StringData name, CustomAttributeValue const& val) {
+ void operator()(const char* name, CustomAttributeValue const& val) {
// Try to format as BSON first if available. Prefer BSONAppend if available as we might only
// want the value and not the whole element.
if (val.BSONAppend) {
@@ -110,7 +99,7 @@ struct JSONValueExtractor {
}
}
- void operator()(StringData name, const BSONObj& val) {
+ void operator()(const char* name, const BSONObj& val) {
// This is a JSON subobject, no quotes needed
storeUnquoted(name);
BSONObj truncated = val.jsonStringBuffer(JsonStringFormat::ExtendedRelaxedV2_0_0,
@@ -121,7 +110,7 @@ struct JSONValueExtractor {
addTruncationReport(name, truncated, val.objsize());
}
- void operator()(StringData name, const BSONArray& val) {
+ void operator()(const char* name, const BSONArray& val) {
// This is a JSON subobject, no quotes needed
storeUnquoted(name);
BSONObj truncated = val.jsonStringBuffer(JsonStringFormat::ExtendedRelaxedV2_0_0,
@@ -132,23 +121,25 @@ struct JSONValueExtractor {
addTruncationReport(name, truncated, val.objsize());
}
- void operator()(StringData name, StringData value) {
+ void operator()(const char* name, StringData value) {
storeQuoted(name, value);
}
template <typename Period>
- void operator()(StringData name, const Duration<Period>& value) {
+ void operator()(const char* name, const Duration<Period>& value) {
// A suffix is automatically prepended
- dassert(!name.endsWith(value.mongoUnitSuffix()));
- static const auto& fmtStr =
- *new auto(fmt::compile<StringData, StringData, StringData, int64_t>(R"({}"{}{}":{})"));
- compiled_format_to(
- _buffer, fmtStr, _separator, name, value.mongoUnitSuffix(), value.count());
+ dassert(!StringData(name).endsWith(value.mongoUnitSuffix()));
+ format_to(std::back_inserter(_buffer),
+ FMT_COMPILE(R"({}"{}{}":{})"),
+ _separator,
+ name,
+ value.mongoUnitSuffix(),
+ value.count());
_separator = ","_sd;
}
template <typename T>
- void operator()(StringData name, const T& value) {
+ void operator()(const char* name, const T& value) {
storeUnquotedValue(name, value);
}
@@ -162,23 +153,20 @@ struct JSONValueExtractor {
private:
void storeUnquoted(StringData name) {
- static const auto& fmtStr = *new auto(fmt::compile<StringData, StringData>(R"({}"{}":)"));
- compiled_format_to(_buffer, fmtStr, _separator, name);
+ format_to(std::back_inserter(_buffer), FMT_COMPILE(R"({}"{}":)"), _separator, name);
_separator = ","_sd;
}
template <typename T>
void storeUnquotedValue(StringData name, const T& value) {
- static const auto& fmtStr =
- *new auto(fmt::compile<StringData, StringData, T>(R"({}"{}":{})"));
- compiled_format_to(_buffer, fmtStr, _separator, name, value);
+ format_to(
+ std::back_inserter(_buffer), FMT_COMPILE(R"({}"{}":{})"), _separator, name, value);
_separator = ","_sd;
}
template <typename T>
void storeQuoted(StringData name, const T& value) {
- static const auto& fmtStr = *new auto(fmt::compile<StringData, StringData>(R"({}"{}":")"));
- compiled_format_to(_buffer, fmtStr, _separator, name);
+ format_to(std::back_inserter(_buffer), FMT_COMPILE(R"({}"{}":")"), _separator, name);
std::size_t before = _buffer.size();
str::escapeForJSON(_buffer, value);
if (_attributeMaxSize != 0) {
diff --git a/src/mongo/logv2/log_attr.h b/src/mongo/logv2/log_attr.h
index 2434b1bd3ce..775823ca566 100644
--- a/src/mongo/logv2/log_attr.h
+++ b/src/mongo/logv2/log_attr.h
@@ -60,11 +60,26 @@ struct IsComposedAttr : std::false_type {};
template <typename... Ts>
struct IsComposedAttr<ComposedAttr<Ts...>> : std::true_type {};
+template <typename T>
+struct NamedArg {
+ const char* name;
+ const T& value;
+};
+
+struct AttrUdl {
+ const char* name;
+
+ template <typename T>
+ NamedArg<T> operator=(T&& v) const {
+ return NamedArg<T>{name, std::forward<T>(v)};
+ }
+};
+
/**
* Helper to make regular attributes composable with combine()
*/
template <typename T>
-auto logAttrs(const fmt::internal::named_arg<T, char>& a) {
+auto logAttrs(const NamedArg<T>& a) {
return a;
}
@@ -121,8 +136,8 @@ auto multipleAttrs(Ts&&... attrs) {
} // namespace logv2
inline namespace literals {
-inline fmt::internal::udl_arg<char> operator"" _attr(const char* s, std::size_t n) {
- return fmt::operator""_a(s, n);
+constexpr logv2::detail::AttrUdl operator"" _attr(const char* name, std::size_t) {
+ return {name};
}
} // namespace literals
} // namespace mongo
diff --git a/src/mongo/logv2/log_debug.h b/src/mongo/logv2/log_debug.h
index b46ad288341..39affd9609c 100644
--- a/src/mongo/logv2/log_debug.h
+++ b/src/mongo/logv2/log_debug.h
@@ -29,44 +29,56 @@
#pragma once
-#include <array>
-#include <fmt/format.h>
#include <utility>
+#include "mongo/base/string_data.h"
+#include "mongo/logv2/log_attr.h"
#include "mongo/logv2/log_detail.h"
namespace mongo {
-namespace logv2::logd_detail {
-
+namespace logv2 {
+namespace detail {
// We want to provide unique names even though we are not using the names.
template <std::size_t I>
-constexpr auto digit = "0123456789"[I];
-template <std::size_t N>
-constexpr auto attrNameData =
- std::array{'d', 'u', 'm', 'm', 'y', digit<(N / 10) % 10>, digit<N % 10>};
+inline constexpr char digit = "0123456789"[I];
template <std::size_t N>
-constexpr auto attrName = fmt::string_view{attrNameData<N>.data(), attrNameData<N>.size()};
+inline constexpr const char attrName[4] = {'_', digit<(N / 10) % 10>, digit<N % 10>, '\0'};
template <std::size_t... Is, typename... Args>
-void logd(std::index_sequence<Is...>, StringData message, const Args&... args) { // NOLINT
- using attrType = fmt::internal::udl_arg<char>;
- auto attributes = detail::makeAttributeStorage((attrType{attrName<Is>} = args)...);
- detail::doUnstructuredLogImpl(LogSeverity::Log(), // NOLINT
- LogOptions{LogComponent::kDefault},
- message,
- attributes);
+auto argAttrs_(std::index_sequence<Is...>, const Args&... args) {
+ return makeAttributeStorage((AttrUdl{attrName<Is>} = args)...);
+}
+
+template <typename... Args>
+auto argAttrs(const Args&... args) {
+ return argAttrs_(std::index_sequence_for<Args...>{}, args...);
}
-} // namespace logv2::logd_detail
+} // namespace detail
/**
* Prototype-only unstructured logging, not allowed to commit to master
*
* Instead of named attributes as arguments, it accepts loggable types directly.
* Will emit a log with a single formatted string as "msg", and no attributes.
+ *
+ * Ex:
+ * #include "mongo/logv2/log_debug.h"
+ * namespace mongo {
+ * void f(int x, double y) {
+ * logd("f called with x={}, y={}", x, y);
+ * }
+ * } // namespace mongo
*/
template <typename... Args>
-void logd(StringData message, const Args&... args) { // NOLINT
- logv2::logd_detail::logd(std::index_sequence_for<Args...>{}, message, args...); // NOLINT
+void logd(StringData message, const Args&... args) { // NOLINT
+ doUnstructuredLogImpl(LogSeverity::Log(), // NOLINT
+ LogOptions{LogComponent::kDefault},
+ message,
+ detail::argAttrs(args...));
}
+} // namespace logv2
+
+using logv2::logd; // NOLINT
+
} // namespace mongo
diff --git a/src/mongo/logv2/log_detail.cpp b/src/mongo/logv2/log_detail.cpp
index d90d44ddf9e..95ea258a5a3 100644
--- a/src/mongo/logv2/log_detail.cpp
+++ b/src/mongo/logv2/log_detail.cpp
@@ -44,61 +44,64 @@
namespace mongo::logv2::detail {
struct UnstructuredValueExtractor {
- void operator()(StringData name, CustomAttributeValue const& val) {
+ void operator()(const char* name, CustomAttributeValue const& val) {
// Prefer string serialization over BSON if available.
if (val.stringSerialize) {
fmt::memory_buffer buffer;
val.stringSerialize(buffer);
- _storage.push_back(fmt::to_string(buffer));
- operator()(name, _storage.back());
+ _addString(name, fmt::to_string(buffer));
} else if (val.toString) {
- _storage.push_back(val.toString());
- operator()(name, _storage.back());
+ _addString(name, val.toString());
} else if (val.BSONAppend) {
BSONObjBuilder builder;
val.BSONAppend(builder, name);
BSONElement element = builder.done().getField(name);
- _storage.push_back(element.toString(false));
- operator()(name, _storage.back());
+ _addString(name, element.toString(false));
} else if (val.BSONSerialize) {
BSONObjBuilder builder;
val.BSONSerialize(builder);
- operator()(name, builder.done());
+ (*this)(name, builder.done());
} else if (val.toBSONArray) {
- operator()(name, val.toBSONArray());
+ (*this)(name, val.toBSONArray());
}
}
- void operator()(StringData name, const BSONObj& val) {
+ void operator()(const char* name, const BSONObj& val) {
StringBuilder ss;
val.toString(ss, false);
- _storage.push_back(ss.str());
- operator()(name, _storage.back());
+ _addString(name, ss.str());
}
- void operator()(StringData name, const BSONArray& val) {
+ void operator()(const char* name, const BSONArray& val) {
StringBuilder ss;
val.toString(ss, true);
- _storage.push_back(ss.str());
- operator()(name, _storage.back());
+ _addString(name, ss.str());
}
template <typename Period>
- void operator()(StringData name, const Duration<Period>& val) {
- _storage.push_back(val.toString());
- operator()(name, _storage.back());
+ void operator()(const char* name, const Duration<Period>& val) {
+ _addString(name, val.toString());
}
template <typename T>
- void operator()(StringData name, const T& val) {
- args.push_back(fmt::internal::make_arg<fmt::format_context>(val));
+ void operator()(const char* name, const T& val) {
+ _args.push_back(fmt::arg(name, std::cref(val)));
}
- boost::container::small_vector<fmt::basic_format_arg<fmt::format_context>,
- constants::kNumStaticAttrs>
- args;
+ void reserve(size_t n) {
+ _args.reserve(n, n);
+ }
+
+ const auto& args() const {
+ return _args;
+ }
private:
+ void _addString(const char* name, std::string&& val) {
+ (*this)(name, _storage.emplace_back(std::move(val)));
+ }
+
+ fmt::dynamic_format_arg_store<fmt::format_context> _args;
std::deque<std::string> _storage;
};
@@ -116,10 +119,7 @@ static void checkUniqueAttrs(int32_t id, const TypeErasedAttributeStorage& attrs
StringData sep;
std::string msg;
for (auto&& a : attrs) {
- msg.append(sep.rawData(), sep.size())
- .append("\"")
- .append(a.name.rawData(), a.name.size())
- .append("\"");
+ msg.append(format(FMT_STRING(R"({}"{}")"), sep, a.name));
sep = ","_sd;
}
uasserted(4793301, format(FMT_STRING("LOGV2 (id={}) attribute collision: [{}]"), id, msg));
@@ -169,11 +169,10 @@ void doUnstructuredLogImpl(LogSeverity const& severity, // NOLINT
TypeErasedAttributeStorage const& attrs) {
UnstructuredValueExtractor extractor;
- extractor.args.reserve(attrs.size());
+ extractor.reserve(attrs.size());
attrs.apply(extractor);
- auto formatted = fmt::vformat(
- to_string_view(message),
- fmt::basic_format_args<fmt::format_context>(extractor.args.data(), extractor.args.size()));
+ auto formatted =
+ fmt::vformat(std::string_view{message.rawData(), message.size()}, extractor.args());
doLogImpl(0, severity, options, formatted, TypeErasedAttributeStorage());
}
diff --git a/src/mongo/logv2/log_detail.h b/src/mongo/logv2/log_detail.h
index 1fcac123c25..53c28ae7152 100644
--- a/src/mongo/logv2/log_detail.h
+++ b/src/mongo/logv2/log_detail.h
@@ -60,7 +60,7 @@ void doLogUnpacked(int32_t id,
LogSeverity const& severity,
LogOptions const& options,
const S& message,
- const fmt::internal::named_arg<Args, char>&... args) {
+ const NamedArg<Args>&... args) {
auto attributes = makeAttributeStorage(args...);
fmt::string_view msg{message};
@@ -73,7 +73,7 @@ void doLogUnpacked(int32_t id,
LogOptions const& options,
const S&, // formatMsg not used
const char (&msg)[N],
- const fmt::internal::named_arg<Args, char>&... args) {
+ const NamedArg<Args>&... args) {
doLogUnpacked(id, severity, options, msg, args...);
}
diff --git a/src/mongo/logv2/name_extractor.h b/src/mongo/logv2/name_extractor.h
deleted file mode 100644
index a4d75395934..00000000000
--- a/src/mongo/logv2/name_extractor.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * Copyright (C) 2019-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-#pragma once
-
-#include "mongo/base/string_data.h"
-#include "mongo/logv2/constants.h"
-
-#include <boost/container/small_vector.hpp>
-#include <boost/optional.hpp>
-#include <fmt/format.h>
-
-namespace mongo::logv2::detail {
-
-struct NameExtractor {
- template <typename T>
- void operator()(StringData name, const T& value) {
- nameArgs.push_back(fmt::internal::make_arg<fmt::format_context>(name));
- }
-
- boost::container::small_vector<fmt::basic_format_arg<fmt::format_context>,
- constants::kNumStaticAttrs>
- nameArgs;
-};
-
-} // namespace mongo::logv2::detail
diff --git a/src/mongo/logv2/plain_formatter.cpp b/src/mongo/logv2/plain_formatter.cpp
index de83f01667e..7f38e74693b 100644
--- a/src/mongo/logv2/plain_formatter.cpp
+++ b/src/mongo/logv2/plain_formatter.cpp
@@ -33,6 +33,7 @@
#include "mongo/logv2/attribute_storage.h"
#include "mongo/logv2/attributes.h"
#include "mongo/logv2/constants.h"
+#include "mongo/stdx/variant.h"
#include "mongo/util/str_escape.h"
#include <boost/container/small_vector.hpp>
@@ -40,29 +41,26 @@
#include <boost/log/expressions/message.hpp>
#include <boost/log/utility/formatting_ostream.hpp>
+#include <any>
#include <deque>
#include <fmt/format.h>
-#include <forward_list>
namespace mongo::logv2 {
namespace {
struct TextValueExtractor {
- void operator()(StringData name, CustomAttributeValue const& val) {
+ void operator()(const char* name, CustomAttributeValue const& val) {
if (val.stringSerialize) {
fmt::memory_buffer buffer;
val.stringSerialize(buffer);
- _storage.push_back(fmt::to_string(buffer));
- operator()(name, StringData(_storage.back()));
+ _addString(name, fmt::to_string(buffer));
} else if (val.toString) {
- _storage.push_back(val.toString());
- operator()(name, StringData(_storage.back()));
+ _addString(name, val.toString());
} else if (val.BSONAppend) {
BSONObjBuilder builder;
val.BSONAppend(builder, name);
BSONElement element = builder.done().getField(name);
- _storage.push_back(element.toString(false));
- operator()(name, _storage.back());
+ _addString(name, element.toString(false));
} else if (val.BSONSerialize) {
BSONObjBuilder builder;
val.BSONSerialize(builder);
@@ -72,82 +70,72 @@ struct TextValueExtractor {
}
}
- void operator()(StringData name, const BSONObj& val) {
- _storage.push_back(val.jsonString(JsonStringFormat::ExtendedRelaxedV2_0_0));
- operator()(name, StringData(_storage.back()));
+ void operator()(const char* name, const BSONObj& val) {
+ _addString(name, val.jsonString(JsonStringFormat::ExtendedRelaxedV2_0_0));
}
- void operator()(StringData name, const BSONArray& val) {
- _storage.push_back(val.jsonString(JsonStringFormat::ExtendedRelaxedV2_0_0, 0, true));
- operator()(name, StringData(_storage.back()));
+ void operator()(const char* name, const BSONArray& val) {
+ _addString(name, val.jsonString(JsonStringFormat::ExtendedRelaxedV2_0_0, 0, true));
}
template <typename Period>
- void operator()(StringData name, const Duration<Period>& val) {
- _storage.push_back(val.toString());
- operator()(name, StringData(_storage.back()));
+ void operator()(const char* name, const Duration<Period>& val) {
+ _addString(name, val.toString());
}
- void operator()(StringData name, bool val) {
- _namedBool.push_front(fmt::arg(fmt::string_view(name.rawData(), name.size()), val));
- add(_namedBool.front());
+ template <typename T>
+ void operator()(const char* name, const T& val) {
+ _add(name, val);
}
- void operator()(StringData name, int val) {
- _namedInt.push_front(fmt::arg(fmt::string_view(name.rawData(), name.size()), val));
- add(_namedInt.front());
+ const auto& args() const {
+ return _args;
}
- void operator()(StringData name, unsigned int val) {
- _namedUInt.push_front(fmt::arg(fmt::string_view(name.rawData(), name.size()), val));
- add(_namedUInt.front());
+ void reserve(std::size_t sz) {
+ _args.reserve(sz, sz);
}
- void operator()(StringData name, long long val) {
- _namedLL.push_front(fmt::arg(fmt::string_view(name.rawData(), name.size()), val));
- add(_namedLL.front());
+private:
+ /**
+ * Workaround for `dynamic_format_arg_store`'s desire to copy string
+ * values and user-defined values.
+ */
+ static auto _wrapValue(StringData val) {
+ return std::string_view{val.rawData(), val.size()};
}
- void operator()(StringData name, unsigned long long val) {
- _namedULL.push_front(fmt::arg(fmt::string_view(name.rawData(), name.size()), val));
- add(_namedULL.front());
+ template <typename T>
+ static auto _wrapValue(const T& val) {
+ return std::cref(val);
}
- void operator()(StringData name, double val) {
- _namedDouble.push_front(fmt::arg(fmt::string_view(name.rawData(), name.size()), val));
- add(_namedDouble.front());
+ template <typename T>
+ void _add(const char* name, const T& val) {
+ // Store our own fmt::arg results in a container of std::any,
+ // and give reference_wrappers to _args. This avoids a string
+ // copy of the 'name' inside _args.
+ _args.push_back(std::cref(_store(fmt::arg(name, _wrapValue(val)))));
}
- void operator()(StringData name, StringData val) {
- _namedStringData.push_front(fmt::arg(fmt::string_view(name.rawData(), name.size()), val));
- add(_namedStringData.front());
+ void _addString(const char* name, std::string&& val) {
+ _add(name, StringData{_store(std::move(val))});
}
- boost::container::small_vector<fmt::basic_format_arg<fmt::format_context>,
- constants::kNumStaticAttrs>
- args;
-
-private:
template <typename T>
- void add(const T& named) {
- args.push_back(fmt::internal::make_arg<fmt::format_context>(named));
+ const T& _store(T&& val) {
+ return std::any_cast<const T&>(_storage.emplace_back(std::forward<T>(val)));
}
- std::deque<std::string> _storage;
- std::forward_list<fmt::internal::named_arg<bool, char>> _namedBool;
- std::forward_list<fmt::internal::named_arg<int, char>> _namedInt;
- std::forward_list<fmt::internal::named_arg<unsigned int, char>> _namedUInt;
- std::forward_list<fmt::internal::named_arg<long long, char>> _namedLL;
- std::forward_list<fmt::internal::named_arg<unsigned long long, char>> _namedULL;
- std::forward_list<fmt::internal::named_arg<double, char>> _namedDouble;
- std::forward_list<fmt::internal::named_arg<StringData, char>> _namedStringData;
+ std::deque<std::any> _storage;
+ fmt::dynamic_format_arg_store<fmt::format_context> _args;
};
} // namespace
void PlainFormatter::operator()(boost::log::record_view const& rec,
fmt::memory_buffer& buffer) const {
- using namespace boost::log;
+ using boost::log::extract;
StringData message = extract<StringData>(attributes::message(), rec).get();
const auto& attrs = extract<TypeErasedAttributeStorage>(attributes::attributes(), rec).get();
@@ -155,19 +143,15 @@ void PlainFormatter::operator()(boost::log::record_view const& rec,
// Log messages logged via logd are already formatted and have the id == 0
if (attrs.empty()) {
if (extract<int32_t>(attributes::id(), rec).get() == 0) {
- buffer.append(message.rawData(), message.rawData() + message.size());
-
+ buffer.append(message.begin(), message.end());
return;
}
}
TextValueExtractor extractor;
- extractor.args.reserve(attrs.size());
+ extractor.reserve(attrs.size());
attrs.apply(extractor);
- fmt::vformat_to(
- buffer,
- to_string_view(message),
- fmt::basic_format_args<fmt::format_context>(extractor.args.data(), extractor.args.size()));
+ fmt::vformat_to(buffer, std::string_view{message.rawData(), message.size()}, extractor.args());
size_t attributeMaxSize = buffer.size();
if (extract<LogTruncation>(attributes::truncation(), rec).get() == LogTruncation::Enabled) {
@@ -184,7 +168,6 @@ void PlainFormatter::operator()(boost::log::record_view const& rec,
void PlainFormatter::operator()(boost::log::record_view const& rec,
boost::log::formatting_ostream& strm) const {
- using namespace boost::log;
fmt::memory_buffer buffer;
operator()(rec, buffer);
strm.write(buffer.data(), buffer.size());