diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2021-03-12 14:35:50 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-03-17 07:27:12 +0000 |
commit | dc68f885b80e70805eab8c5686ee0941bbdd806b (patch) | |
tree | d01370941d5f6b9e4710f2ed6c2bdf9d4a61ab25 /src/mongo/logv2 | |
parent | 586beac1d4c9d6ba08b986a79e83fc9374b4ead0 (diff) | |
download | mongo-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.md | 6 | ||||
-rw-r--r-- | src/mongo/logv2/attribute_storage.h | 28 | ||||
-rw-r--r-- | src/mongo/logv2/bson_formatter.cpp | 1 | ||||
-rw-r--r-- | src/mongo/logv2/json_formatter.cpp | 46 | ||||
-rw-r--r-- | src/mongo/logv2/log_attr.h | 21 | ||||
-rw-r--r-- | src/mongo/logv2/log_debug.h | 50 | ||||
-rw-r--r-- | src/mongo/logv2/log_detail.cpp | 61 | ||||
-rw-r--r-- | src/mongo/logv2/log_detail.h | 4 | ||||
-rw-r--r-- | src/mongo/logv2/name_extractor.h | 52 | ||||
-rw-r--r-- | src/mongo/logv2/plain_formatter.cpp | 107 |
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()); |