summaryrefslogtreecommitdiff
path: root/src/mongo/logv2
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2020-07-01 14:49:38 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-01 20:15:55 +0000
commit07deced6b3fa2f5927bb33bd4940cc60d6bc4607 (patch)
treeb4d0ba0c8c54ad24e0e3a6d01015d5122d9c870a /src/mongo/logv2
parente14ec02403b4119b17bf013aa257a5eafeb35073 (diff)
downloadmongo-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.h9
-rw-r--r--src/mongo/logv2/log_detail.cpp35
-rw-r--r--src/mongo/logv2/logv2_test.cpp7
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());