diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2020-07-01 14:49:38 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-07-01 20:15:55 +0000 |
commit | 07deced6b3fa2f5927bb33bd4940cc60d6bc4607 (patch) | |
tree | b4d0ba0c8c54ad24e0e3a6d01015d5122d9c870a /src/mongo/logv2 | |
parent | e14ec02403b4119b17bf013aa257a5eafeb35073 (diff) | |
download | mongo-07deced6b3fa2f5927bb33bd4940cc60d6bc4607.tar.gz |
SERVER-47933 runtime attr unique check
Recommit: handle pre-init testing proctor
Diffstat (limited to 'src/mongo/logv2')
-rw-r--r-- | src/mongo/logv2/attribute_storage.h | 9 | ||||
-rw-r--r-- | src/mongo/logv2/log_detail.cpp | 35 | ||||
-rw-r--r-- | src/mongo/logv2/logv2_test.cpp | 7 |
3 files changed, 51 insertions, 0 deletions
diff --git a/src/mongo/logv2/attribute_storage.h b/src/mongo/logv2/attribute_storage.h index 656302ba4de..141c10752a2 100644 --- a/src/mongo/logv2/attribute_storage.h +++ b/src/mongo/logv2/attribute_storage.h @@ -678,6 +678,8 @@ private: // Wrapper around internal pointer of AttributeStorage so it does not need any template parameters class TypeErasedAttributeStorage { public: + using const_iterator = const detail::NamedAttribute*; + TypeErasedAttributeStorage() : _size(0) {} template <typename... Args> @@ -695,6 +697,13 @@ public: return _size; } + const_iterator begin() const { + return _data; + } + const_iterator end() const { + return _data + _size; + } + // Applies a function to every stored named attribute in order they are captured template <typename Func> void apply(Func&& f) const { diff --git a/src/mongo/logv2/log_detail.cpp b/src/mongo/logv2/log_detail.cpp index 766c79488e4..d90d44ddf9e 100644 --- a/src/mongo/logv2/log_detail.cpp +++ b/src/mongo/logv2/log_detail.cpp @@ -31,12 +31,15 @@ #include "mongo/platform/basic.h" +#include <fmt/format.h> + #include "mongo/logv2/attributes.h" #include "mongo/logv2/log.h" #include "mongo/logv2/log_domain.h" #include "mongo/logv2/log_domain_internal.h" #include "mongo/logv2/log_options.h" #include "mongo/logv2/log_source.h" +#include "mongo/util/testing_proctor.h" namespace mongo::logv2::detail { @@ -99,12 +102,44 @@ private: std::deque<std::string> _storage; }; +static void checkUniqueAttrs(int32_t id, const TypeErasedAttributeStorage& attrs) { + if (attrs.size() <= 1) + return; + // O(N^2), but N is small and this avoids alloc, sort, and operator<. + auto first = attrs.begin(); + auto last = attrs.end(); + while (first != last) { + auto it = first; + ++first; + if (std::find_if(first, last, [&](auto&& a) { return a.name == it->name; }) == last) + continue; + StringData sep; + std::string msg; + for (auto&& a : attrs) { + msg.append(sep.rawData(), sep.size()) + .append("\"") + .append(a.name.rawData(), a.name.size()) + .append("\""); + sep = ","_sd; + } + uasserted(4793301, format(FMT_STRING("LOGV2 (id={}) attribute collision: [{}]"), id, msg)); + } +} + void doLogImpl(int32_t id, LogSeverity const& severity, LogOptions const& options, StringData message, TypeErasedAttributeStorage const& attrs) { dassert(options.component() != LogComponent::kNumLogComponents); + // TestingProctor isEnabled cannot be called before it has been + // initialized. But log statements occurring earlier than that still need + // to be checked. Log performance isn't as important at startup, so until + // the proctor is initialized, we check everything. + if (const auto& tp = TestingProctor::instance(); !tp.isInitialized() || tp.isEnabled()) { + checkUniqueAttrs(id, attrs); + } + auto& source = options.domain().internal().source(); auto record = source.open_record(id, severity, diff --git a/src/mongo/logv2/logv2_test.cpp b/src/mongo/logv2/logv2_test.cpp index e5c702a1f7c..f863c7db555 100644 --- a/src/mongo/logv2/logv2_test.cpp +++ b/src/mongo/logv2/logv2_test.cpp @@ -1318,6 +1318,13 @@ TEST_F(LogV2ContainerTest, StringMapUint32) { }); } +TEST_F(LogV2Test, AttrNameCollision) { + ASSERT_THROWS_CODE( + LOGV2(4793300, "Collision {k1}", "Collision", "k1"_attr = "v1", "k1"_attr = "v2"), + AssertionException, + 4793301); +} + TEST_F(LogV2Test, Unicode) { auto lines = makeLineCapture(JSONFormatter()); |