summaryrefslogtreecommitdiff
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-08-19 17:11:26 +0000
commitdd0c322ddd022e409bde89e8d3566e67ac166cdc (patch)
treebbe9bcecde63d22b30cc3286521755248cd67e82
parent52357b37f74e561b5e9edf95733399e01a4d303f (diff)
downloadmongo-dd0c322ddd022e409bde89e8d3566e67ac166cdc.tar.gz
SERVER-47933 runtime attr unique check
Recommit: handle pre-init testing proctor (cherry picked from commit 07deced6b3fa2f5927bb33bd4940cc60d6bc4607)
-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 29ff0ed7dd8..90067013cd2 100644
--- a/src/mongo/logv2/attribute_storage.h
+++ b/src/mongo/logv2/attribute_storage.h
@@ -679,6 +679,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>
@@ -696,6 +698,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 2d87434a4da..0b1af757618 100644
--- a/src/mongo/logv2/logv2_test.cpp
+++ b/src/mongo/logv2/logv2_test.cpp
@@ -1319,6 +1319,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());