summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/logv2/attribute_storage.h9
-rw-r--r--src/mongo/logv2/log_detail.cpp30
-rw-r--r--src/mongo/logv2/logv2_test.cpp7
3 files changed, 46 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..e7863215590 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,39 @@ 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);
+ if (TestingProctor::instance().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());