summaryrefslogtreecommitdiff
path: root/src/mongo/logv2
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/logv2')
-rw-r--r--src/mongo/logv2/json_formatter.cpp29
-rw-r--r--src/mongo/logv2/log_capture_backend.h37
-rw-r--r--src/mongo/logv2/log_component.h1
-rw-r--r--src/mongo/logv2/log_detail.cpp43
-rw-r--r--src/mongo/logv2/log_detail.h15
-rw-r--r--src/mongo/logv2/log_domain_global.cpp2
-rw-r--r--src/mongo/logv2/log_source.h8
-rw-r--r--src/mongo/logv2/logv2_test.cpp371
-rw-r--r--src/mongo/logv2/redaction.cpp6
-rw-r--r--src/mongo/logv2/redaction_test.cpp95
10 files changed, 166 insertions, 441 deletions
diff --git a/src/mongo/logv2/json_formatter.cpp b/src/mongo/logv2/json_formatter.cpp
index 58111121423..cbcfc85f121 100644
--- a/src/mongo/logv2/json_formatter.cpp
+++ b/src/mongo/logv2/json_formatter.cpp
@@ -168,27 +168,16 @@ private:
void storeQuoted(StringData name, const T& value) {
format_to(std::back_inserter(_buffer), FMT_COMPILE(R"({}"{}":")"), _separator, name);
std::size_t before = _buffer.size();
- std::size_t wouldWrite = 0;
- std::size_t written = 0;
- str::escapeForJSON(
- _buffer, value, _attributeMaxSize ? _attributeMaxSize : std::string::npos, &wouldWrite);
- written = _buffer.size() - before;
-
- if (wouldWrite > written) {
- // The bounded escape may have reached the limit and
- // stopped writing while in the middle of a UTF-8 sequence,
- // in which case the incomplete UTF-8 octets at the tail of the
- // buffer have to be trimmed.
- // Push a dummy byte so that the UTF-8 safe truncation
- // will truncate back down to the correct size.
- _buffer.push_back('x');
+ str::escapeForJSON(_buffer, value);
+ if (_attributeMaxSize != 0) {
auto truncatedEnd =
- str::UTF8SafeTruncation(_buffer.begin() + before, _buffer.end(), written);
-
- BSONObjBuilder truncationInfo = _truncated.subobjStart(name);
- truncationInfo.append("type"_sd, typeName(BSONType::String));
- truncationInfo.append("size"_sd, static_cast<int64_t>(wouldWrite));
- truncationInfo.done();
+ str::UTF8SafeTruncation(_buffer.begin() + before, _buffer.end(), _attributeMaxSize);
+ if (truncatedEnd != _buffer.end()) {
+ BSONObjBuilder truncationInfo = _truncated.subobjStart(name);
+ truncationInfo.append("type"_sd, typeName(BSONType::String));
+ truncationInfo.append("size"_sd, static_cast<int64_t>(_buffer.size() - before));
+ truncationInfo.done();
+ }
_buffer.resize(truncatedEnd - _buffer.begin());
}
diff --git a/src/mongo/logv2/log_capture_backend.h b/src/mongo/logv2/log_capture_backend.h
index 4078934fb4c..701ec62a9d4 100644
--- a/src/mongo/logv2/log_capture_backend.h
+++ b/src/mongo/logv2/log_capture_backend.h
@@ -37,44 +37,31 @@
#include <string>
#include <vector>
-#include "mongo/platform/atomic_word.h"
-
namespace mongo::logv2 {
-
-/*
- * LogLineListener is a wrapper class used in the LogCaptureBackend that defines what to do with
- * log lines upon consumption.
- */
-class LogLineListener {
-public:
- virtual ~LogLineListener() = default;
- virtual void accept(const std::string& line) = 0;
-};
-
class LogCaptureBackend
: public boost::log::sinks::
- basic_formatted_sink_backend<char, boost::log::sinks::concurrent_feeding> {
+ basic_formatted_sink_backend<char, boost::log::sinks::synchronized_feeding> {
public:
- LogCaptureBackend(std::unique_ptr<LogLineListener> logListener, bool stripEol)
- : _logListener{std::move(logListener)}, _stripEol(stripEol) {}
+ LogCaptureBackend(std::vector<std::string>& lines, bool stripEol)
+ : _stripEol(stripEol), _logLines(lines) {}
- static boost::shared_ptr<boost::log::sinks::unlocked_sink<LogCaptureBackend>> create(
- std::unique_ptr<LogLineListener> logListener, bool stripEol) {
- return boost::make_shared<boost::log::sinks::unlocked_sink<LogCaptureBackend>>(
- boost::make_shared<LogCaptureBackend>(std::move(logListener), stripEol));
+ static boost::shared_ptr<boost::log::sinks::synchronous_sink<LogCaptureBackend>> create(
+ std::vector<std::string>& lines, bool stripEol) {
+ return boost::make_shared<boost::log::sinks::synchronous_sink<LogCaptureBackend>>(
+ boost::make_shared<LogCaptureBackend>(lines, stripEol));
}
void consume(boost::log::record_view const& rec, string_type const& formatted_string) {
- if (_stripEol.load() && !formatted_string.empty() &&
+ if (_stripEol && !formatted_string.empty() &&
formatted_string[formatted_string.size() - 1] == '\n') {
- _logListener->accept(formatted_string.substr(0, formatted_string.size() - 1));
+ _logLines.push_back(formatted_string.substr(0, formatted_string.size() - 1));
} else {
- _logListener->accept(formatted_string);
+ _logLines.push_back(formatted_string);
}
}
private:
- std::unique_ptr<LogLineListener> _logListener;
- AtomicWord<bool> _stripEol;
+ bool _stripEol;
+ std::vector<std::string>& _logLines;
};
} // namespace mongo::logv2
diff --git a/src/mongo/logv2/log_component.h b/src/mongo/logv2/log_component.h
index 90aced1c07a..2b1985756b9 100644
--- a/src/mongo/logv2/log_component.h
+++ b/src/mongo/logv2/log_component.h
@@ -61,7 +61,6 @@ namespace mongo::logv2 {
X(kNetwork, , "network" , "NETWORK" , kDefault) \
X(kProcessHealth, , "processHealth" , "HEALTH" , kDefault) \
X(kQuery, , "query" , "QUERY" , kDefault) \
- X(kQueryStats, , "queryStats" , "QRYSTATS", kDefault) \
X(kReplication, , "replication" , "REPL" , kDefault) \
X(kReplicationElection, , "election" , "ELECTION", kReplication) \
X(kReplicationHeartbeats, , "heartbeats" , "REPL_HB" , kReplication) \
diff --git a/src/mongo/logv2/log_detail.cpp b/src/mongo/logv2/log_detail.cpp
index fb13b99e435..188ede8032a 100644
--- a/src/mongo/logv2/log_detail.cpp
+++ b/src/mongo/logv2/log_detail.cpp
@@ -32,9 +32,6 @@
#include "mongo/platform/basic.h"
#include <fmt/format.h>
-#ifdef _WIN32
-#include <io.h>
-#endif
#include "mongo/db/tenant_id.h"
#include "mongo/logv2/attributes.h"
@@ -43,41 +40,10 @@
#include "mongo/logv2/log_domain_internal.h"
#include "mongo/logv2/log_options.h"
#include "mongo/logv2/log_source.h"
-#include "mongo/util/scopeguard.h"
#include "mongo/util/static_immortal.h"
#include "mongo/util/testing_proctor.h"
-
-namespace mongo::logv2 {
-namespace {
-thread_local int loggingDepth = 0;
-} // namespace
-
-bool loggingInProgress() {
- return loggingDepth > 0;
-}
-
-void signalSafeWriteToStderr(StringData message) {
- while (!message.empty()) {
-#if defined(_WIN32)
- auto ret = _write(_fileno(stderr), message.rawData(), message.size());
-#else
- auto ret = write(STDERR_FILENO, message.rawData(), message.size());
-#endif
- if (ret == -1) {
-#if !defined(_WIN32)
- if (errno == EINTR) {
- continue;
- }
-#endif
- return;
- }
- message = message.substr(ret);
- }
-}
-
-namespace detail {
-
+namespace mongo::logv2::detail {
namespace {
GetTenantIDFn& getTenantID() {
// Ensure that we avoid undefined initialization ordering
@@ -180,9 +146,6 @@ void doLogImpl(int32_t id,
LogOptions const& options,
StringData message,
TypeErasedAttributeStorage const& attrs) {
- loggingDepth++;
- ScopeGuard updateDepth = [] { loggingDepth--; };
-
dassert(options.component() != LogComponent::kNumLogComponents);
// TestingProctor isEnabled cannot be called before it has been
// initialized. But log statements occurring earlier than that still need
@@ -238,6 +201,4 @@ void doUnstructuredLogImpl(LogSeverity const& severity, // NOLINT
doLogImpl(0, severity, options, formatted, TypeErasedAttributeStorage());
}
-} // namespace detail
-
-} // namespace mongo::logv2
+} // namespace mongo::logv2::detail
diff --git a/src/mongo/logv2/log_detail.h b/src/mongo/logv2/log_detail.h
index 7b3360662a2..6f60ae10c74 100644
--- a/src/mongo/logv2/log_detail.h
+++ b/src/mongo/logv2/log_detail.h
@@ -42,15 +42,8 @@
#include "mongo/logv2/log_severity.h"
#include "mongo/util/errno_util.h"
-namespace mongo::logv2 {
-
-// Whether there is a doLogImpl call currently on this thread's stack.
-bool loggingInProgress();
-
-// Write message to stderr in a signal-safe manner.
-void signalSafeWriteToStderr(StringData message);
-namespace detail {
-
+namespace mongo {
+namespace logv2::detail {
using GetTenantIDFn = std::function<boost::optional<TenantId>()>;
void setGetTenantIDCallback(GetTenantIDFn&& fn);
@@ -137,6 +130,6 @@ void doLog(int32_t id,
std::tuple_cat(toFlatAttributesTupleRef(args)...));
}
-} // namespace detail
+} // namespace logv2::detail
-} // namespace mongo::logv2
+} // namespace mongo
diff --git a/src/mongo/logv2/log_domain_global.cpp b/src/mongo/logv2/log_domain_global.cpp
index b75651de21d..5f2c6469a10 100644
--- a/src/mongo/logv2/log_domain_global.cpp
+++ b/src/mongo/logv2/log_domain_global.cpp
@@ -142,7 +142,7 @@ Status LogDomainGlobal::Impl::configure(LogDomainGlobal::ConfigurationOptions co
mapping[LogSeverity::Debug(3)] = boost::log::sinks::syslog::debug;
mapping[LogSeverity::Debug(2)] = boost::log::sinks::syslog::debug;
mapping[LogSeverity::Debug(1)] = boost::log::sinks::syslog::debug;
- mapping[LogSeverity::Log()] = boost::log::sinks::syslog::info;
+ mapping[LogSeverity::Log()] = boost::log::sinks::syslog::debug;
mapping[LogSeverity::Info()] = boost::log::sinks::syslog::info;
mapping[LogSeverity::Warning()] = boost::log::sinks::syslog::warning;
mapping[LogSeverity::Error()] = boost::log::sinks::syslog::critical;
diff --git a/src/mongo/logv2/log_source.h b/src/mongo/logv2/log_source.h
index 8e83cb6ad54..4051bcfb55a 100644
--- a/src/mongo/logv2/log_source.h
+++ b/src/mongo/logv2/log_source.h
@@ -74,10 +74,10 @@ public:
add_attribute_unlocked(attributes::timeStamp(), boost::log::attributes::make_function([]() {
return Date_t::now();
}));
- add_attribute_unlocked(attributes::threadName(),
- boost::log::attributes::make_function([isShutdown]() {
- return isShutdown ? "shutdown"_sd : getThreadName();
- }));
+ add_attribute_unlocked(
+ attributes::threadName(), boost::log::attributes::make_function([isShutdown]() {
+ return isShutdown ? "shutdown"_sd : ThreadName::getStaticString();
+ }));
}
explicit LogSource(const LogDomain::Internal* domain) : LogSource(domain, false) {}
diff --git a/src/mongo/logv2/logv2_test.cpp b/src/mongo/logv2/logv2_test.cpp
index 899440b4fba..7102e720203 100644
--- a/src/mongo/logv2/logv2_test.cpp
+++ b/src/mongo/logv2/logv2_test.cpp
@@ -32,7 +32,6 @@
#include "mongo/platform/basic.h"
#include <fstream>
-#include <signal.h>
#include <sstream>
#include <string>
#include <vector>
@@ -61,11 +60,8 @@
#include "mongo/logv2/uassert_sink.h"
#include "mongo/platform/decimal128.h"
#include "mongo/stdx/thread.h"
-#include "mongo/unittest/death_test.h"
#include "mongo/unittest/temp_dir.h"
#include "mongo/unittest/unittest.h"
-#include "mongo/util/shared_buffer.h"
-#include "mongo/util/str_escape.h"
#include "mongo/util/string_map.h"
#include "mongo/util/uuid.h"
@@ -193,21 +189,10 @@ void applyDefaultFilterToSink(SinkPtr&& sink) {
sink->set_filter(ComponentSettingsFilter(mgr().getGlobalDomain(), mgr().getGlobalSettings()));
}
-class Listener : public logv2::LogLineListener {
-public:
- explicit Listener(synchronized_value<std::vector<std::string>>* sv) : _sv(sv) {}
- void accept(const std::string& line) override {
- (***_sv).push_back(line);
- }
-
-private:
- synchronized_value<std::vector<std::string>>* _sv;
-};
-
class LogDuringInitShutdownTester {
public:
LogDuringInitShutdownTester() {
- auto sink = LogCaptureBackend::create(std::make_unique<Listener>(&syncedLines), true);
+ auto sink = LogCaptureBackend::create(lines, true);
applyDefaultFilterToSink(sink);
// We have to leave this sink installed as it is not allowed to install sinks during
// shutdown. Add a filter so it is only used during this test.
@@ -217,15 +202,15 @@ public:
ScopeGuard enabledGuard([this] { enabled = false; });
LOGV2(20001, "log during init");
- ASSERT_EQUALS((**syncedLines).back(), "log during init");
+ ASSERT_EQUALS(lines.back(), "log during init");
}
~LogDuringInitShutdownTester() {
enabled = true;
LOGV2(4600800, "log during shutdown");
- ASSERT_EQUALS((**syncedLines).back(), "log during shutdown");
+ ASSERT_EQUALS(lines.back(), "log during shutdown");
}
- synchronized_value<std::vector<std::string>> syncedLines;
+ std::vector<std::string> lines;
bool enabled = true;
};
@@ -237,30 +222,28 @@ public:
public:
LineCapture() = delete;
LineCapture(bool stripEol)
- : _syncedLines{synchronized_value<std::vector<std::string>>()},
- _sink{
- LogCaptureBackend::create(std::make_unique<Listener>(&_syncedLines), stripEol)} {}
- auto lines() {
- return **_syncedLines;
+ : _lines{std::make_unique<std::vector<std::string>>()},
+ _sink{LogCaptureBackend::create(*_lines, stripEol)} {}
+ auto& lines() {
+ return *_lines;
}
auto& sink() {
return _sink;
}
- std::string back() const {
- auto logLinesLockGuard = *_syncedLines;
- ASSERT_GT(logLinesLockGuard->size(), 0);
- return logLinesLockGuard->back();
+ const std::string& back() const {
+ ASSERT_GT(_lines->size(), 0);
+ return _lines->back();
}
void clear() {
- return (**_syncedLines).clear();
+ return _lines->clear();
}
size_t size() const {
- return (**_syncedLines).size();
+ return _lines->size();
}
private:
- synchronized_value<std::vector<std::string>> _syncedLines;
- boost::shared_ptr<boost::log::sinks::unlocked_sink<LogCaptureBackend>> _sink;
+ std::unique_ptr<std::vector<std::string>> _lines;
+ boost::shared_ptr<boost::log::sinks::synchronous_sink<LogCaptureBackend>> _sink;
};
LogV2Test() {
@@ -301,9 +284,9 @@ public:
}
template <typename Fmt>
- std::unique_ptr<LineCapture> makeLineCapture(Fmt&& formatter, bool stripEol = true) {
- auto ret = std::make_unique<LineCapture>(stripEol);
- auto& s = ret->sink();
+ LineCapture makeLineCapture(Fmt&& formatter, bool stripEol = true) {
+ LineCapture ret(stripEol);
+ auto& s = ret.sink();
applyDefaultFilterToSink(s);
s->set_formatter(std::forward<Fmt>(formatter));
attachSink(s);
@@ -321,96 +304,59 @@ TEST_F(LogV2Test, Basic) {
fmt::memory_buffer buffer;
LOGV2(20002, "test");
- ASSERT_EQUALS(lines->back(), "test");
+ ASSERT_EQUALS(lines.back(), "test");
LOGV2_DEBUG(20063, -2, "test debug");
- ASSERT_EQUALS(lines->back(), "test debug");
+ ASSERT_EQUALS(lines.back(), "test debug");
LOGV2(20003, "test {name}", "name"_attr = 1);
- ASSERT_EQUALS(lines->back(), "test 1");
+ ASSERT_EQUALS(lines.back(), "test 1");
LOGV2(20004, "test {name:d}", "name"_attr = 2);
- ASSERT_EQUALS(lines->back(), "test 2");
+ ASSERT_EQUALS(lines.back(), "test 2");
LOGV2(20005, "test {name}", "name"_attr = "char*");
- ASSERT_EQUALS(lines->back(), "test char*");
+ ASSERT_EQUALS(lines.back(), "test char*");
LOGV2(20006, "test {name}", "name"_attr = std::string("std::string"));
- ASSERT_EQUALS(lines->back(), "test std::string");
+ ASSERT_EQUALS(lines.back(), "test std::string");
LOGV2(20007, "test {name}", "name"_attr = "StringData"_sd);
- ASSERT_EQUALS(lines->back(), "test StringData");
+ ASSERT_EQUALS(lines.back(), "test StringData");
LOGV2_OPTIONS(20064, {LogTag::kStartupWarnings}, "test");
- ASSERT_EQUALS(lines->back(), "test");
+ ASSERT_EQUALS(lines.back(), "test");
TypeWithBSON t(1.0, 2.0);
LOGV2(20008, "{name} custom formatting", "name"_attr = t);
- ASSERT_EQUALS(lines->back(), t.toString() + " custom formatting");
+ ASSERT_EQUALS(lines.back(), t.toString() + " custom formatting");
TypeWithoutBSON t2(1.0, 2.0);
LOGV2(20009, "{name} custom formatting, no bson", "name"_attr = t2);
- ASSERT_EQUALS(lines->back(), t.toString() + " custom formatting, no bson");
+ ASSERT_EQUALS(lines.back(), t.toString() + " custom formatting, no bson");
TypeWithOnlyStringSerialize t3(1.0, 2.0);
LOGV2(20010, "{name}", "name"_attr = t3);
buffer.clear();
t3.serialize(buffer);
- ASSERT_EQUALS(lines->back(), fmt::to_string(buffer));
+ ASSERT_EQUALS(lines.back(), fmt::to_string(buffer));
// Serialize should be preferred when both are available
TypeWithBothStringFormatters t4;
LOGV2(20011, "{name}", "name"_attr = t4);
buffer.clear();
t4.serialize(buffer);
- ASSERT_EQUALS(lines->back(), fmt::to_string(buffer));
+ ASSERT_EQUALS(lines.back(), fmt::to_string(buffer));
// Message string is selected when using API that also take a format string
LOGV2(20084, "fmtstr {name}", "msgstr", "name"_attr = 1);
- ASSERT_EQUALS(lines->back(), "msgstr");
+ ASSERT_EQUALS(lines.back(), "msgstr");
// Test that logging exceptions does not propagate out to user code in release builds
if (!kDebugBuild) {
LOGV2(4638203, "mismatch {name}", "not_name"_attr = 1);
- ASSERT(StringData(lines->back()).startsWith("Exception during log"_sd));
+ ASSERT(StringData(lines.back()).startsWith("Exception during log"_sd));
}
-} // namespace
-
-namespace bl_sinks = boost::log::sinks;
-// Sink backend which will grab a mutex, then immediately segfault.
-class ConsumeSegfaultsBackend
- : public bl_sinks::basic_formatted_sink_backend<char, bl_sinks::synchronized_feeding> {
-public:
- static auto create() {
- return boost::make_shared<bl_sinks::synchronous_sink<ConsumeSegfaultsBackend>>(
- boost::make_shared<ConsumeSegfaultsBackend>());
- }
-
- void consume(boost::log::record_view const& rec, string_type const& formattedString) {
- if (firstRun) {
- firstRun = false;
- raise(SIGSEGV);
- } else {
- // Reentrance of consume(), which could cause deadlock. Exit normally, causing the death
- // test to fail.
- exit(0);
- }
- }
-
-private:
- bool firstRun = true;
-};
-
-// Test that signals thrown during logging will not hang process death. Uses the
-// ConsumeSegfaultsBackend so that upon the initial log call, ConsumeSegfaultsBackend::consume will
-// be called, sending SIGSEGV. If the signal handler incorrectly invokes the logging subsystem, the
-// ConsumeSegfaultsBackend::consume function will be again invoked, failing the test since this
-// could result in deadlock.
-DEATH_TEST_F(LogV2Test, SIGSEGVDoesNotHang, "Got signal: ") {
- auto sink = ConsumeSegfaultsBackend::create();
- attachSink(sink);
- LOGV2(6384304, "will SIGSEGV {str}", "str"_attr = "sigsegv");
- // If we get here, we didn't segfault, and the test will fail.
}
class LogV2TypesTest : public LogV2Test {
@@ -428,7 +374,7 @@ public:
template <typename T>
void validateJSON(T expected) {
namespace pt = boost::property_tree;
- std::istringstream json_stream(json->back());
+ std::istringstream json_stream(json.back());
pt::ptree ptree;
pt::json_parser::read_json(json_stream, ptree);
ASSERT_EQUALS(ptree.get<std::string>(std::string(kTenantFieldName)), tenant.toString());
@@ -436,20 +382,15 @@ public:
}
auto lastBSONElement() {
- auto str = bson->back();
- buf.realloc(str.size());
- str.copy(buf.get(), str.size());
- BSONObj obj(buf);
-
- ASSERT_EQUALS(obj.getField(kTenantFieldName).str(), tenant.toString());
- return obj.getField(kAttributesFieldName).Obj().getField("name"_sd);
+ ASSERT_EQUALS(BSONObj(bson.back().data()).getField(kTenantFieldName).str(),
+ tenant.toString());
+ return BSONObj(bson.back().data()).getField(kAttributesFieldName).Obj().getField("name"_sd);
}
TenantId tenant = TenantId(OID::gen());
- std::unique_ptr<LineCapture> text = makeLineCapture(PlainFormatter());
- std::unique_ptr<LineCapture> json = makeLineCapture(JSONFormatter());
- std::unique_ptr<LineCapture> bson = makeLineCapture(BSONFormatter());
- SharedBuffer buf;
+ LineCapture text = makeLineCapture(PlainFormatter());
+ LineCapture json = makeLineCapture(JSONFormatter());
+ LineCapture bson = makeLineCapture(BSONFormatter());
};
TEST_F(LogV2TypesTest, Numeric) {
@@ -457,9 +398,9 @@ TEST_F(LogV2TypesTest, Numeric) {
using T = decltype(dummy);
auto test = [&](auto value) {
- text->clear();
+ text.clear();
LOGV2(20012, "{name}", "name"_attr = value);
- ASSERT_EQUALS(text->back(), fmt::format("{}", value));
+ ASSERT_EQUALS(text.back(), fmt::format("{}", value));
validateJSON(value);
// TODO: We should have been able to use std::make_signed here but it is broken on
@@ -490,10 +431,10 @@ TEST_F(LogV2TypesTest, Numeric) {
using T = decltype(dummy);
auto test = [&](auto value) {
- text->clear();
+ text.clear();
LOGV2(20013, "{name}", "name"_attr = value);
// Floats are formatted as double
- ASSERT_EQUALS(text->back(), fmt::format("{}", static_cast<double>(value)));
+ ASSERT_EQUALS(text.back(), fmt::format("{}", static_cast<double>(value)));
validateJSON(value);
ASSERT_EQUALS(lastBSONElement().Number(), value);
};
@@ -512,13 +453,13 @@ TEST_F(LogV2TypesTest, Numeric) {
bool b = true;
LOGV2(20014, "bool {name}", "name"_attr = b);
- ASSERT_EQUALS(text->back(), "bool true");
+ ASSERT_EQUALS(text.back(), "bool true");
validateJSON(b);
ASSERT(lastBSONElement().Bool() == b);
char c = 1;
LOGV2(20015, "char {name}", "name"_attr = c);
- ASSERT_EQUALS(text->back(), "char 1");
+ ASSERT_EQUALS(text.back(), "char 1");
validateJSON(static_cast<uint8_t>(c)); // cast to prevent property_tree ASCII parse.
ASSERT(lastBSONElement().Number() == c);
@@ -545,19 +486,19 @@ TEST_F(LogV2TypesTest, Enums) {
enum UnscopedEnum { UnscopedEntry };
LOGV2(20076, "{name}", "name"_attr = UnscopedEntry);
auto expectedUnscoped = static_cast<std::underlying_type_t<UnscopedEnum>>(UnscopedEntry);
- ASSERT_EQUALS(text->back(), std::to_string(expectedUnscoped));
+ ASSERT_EQUALS(text.back(), std::to_string(expectedUnscoped));
validateJSON(expectedUnscoped);
ASSERT_EQUALS(lastBSONElement().Number(), expectedUnscoped);
enum class ScopedEnum { Entry = -1 };
LOGV2(20077, "{name}", "name"_attr = ScopedEnum::Entry);
auto expectedScoped = static_cast<std::underlying_type_t<ScopedEnum>>(ScopedEnum::Entry);
- ASSERT_EQUALS(text->back(), std::to_string(expectedScoped));
+ ASSERT_EQUALS(text.back(), std::to_string(expectedScoped));
validateJSON(expectedScoped);
ASSERT_EQUALS(lastBSONElement().Number(), expectedScoped);
LOGV2(20078, "{name}", "name"_attr = UnscopedEntryWithToString);
- ASSERT_EQUALS(text->back(), toString(UnscopedEntryWithToString));
+ ASSERT_EQUALS(text.back(), toString(UnscopedEntryWithToString));
validateJSON(toString(UnscopedEntryWithToString));
ASSERT_EQUALS(lastBSONElement().String(), toString(UnscopedEntryWithToString));
}
@@ -565,32 +506,32 @@ TEST_F(LogV2TypesTest, Enums) {
TEST_F(LogV2TypesTest, Stringlike) {
const char* c_str = "a c string";
LOGV2(20016, "c string {name}", "name"_attr = c_str);
- ASSERT_EQUALS(text->back(), "c string a c string");
+ ASSERT_EQUALS(text.back(), "c string a c string");
validateJSON(std::string(c_str));
ASSERT_EQUALS(lastBSONElement().String(), c_str);
char* c_str2 = const_cast<char*>("non-const");
LOGV2(20017, "c string {name}", "name"_attr = c_str2);
- ASSERT_EQUALS(text->back(), "c string non-const");
+ ASSERT_EQUALS(text.back(), "c string non-const");
validateJSON(std::string(c_str2));
ASSERT_EQUALS(lastBSONElement().String(), c_str2);
std::string str = "a std::string";
LOGV2(20018, "std::string {name}", "name"_attr = str);
- ASSERT_EQUALS(text->back(), "std::string a std::string");
+ ASSERT_EQUALS(text.back(), "std::string a std::string");
validateJSON(str);
ASSERT_EQUALS(lastBSONElement().String(), str);
StringData str_data = "a StringData"_sd;
LOGV2(20019, "StringData {name}", "name"_attr = str_data);
- ASSERT_EQUALS(text->back(), "StringData a StringData");
+ ASSERT_EQUALS(text.back(), "StringData a StringData");
validateJSON(str_data.toString());
ASSERT_EQUALS(lastBSONElement().String(), str_data);
{
std::string_view s = "a std::string_view";
LOGV2(4329200, "std::string_view {name}", "name"_attr = s);
- ASSERT_EQUALS(text->back(), "std::string_view a std::string_view");
+ ASSERT_EQUALS(text.back(), "std::string_view a std::string_view");
validateJSON(std::string{s});
ASSERT_EQUALS(lastBSONElement().String(), s);
}
@@ -604,9 +545,9 @@ TEST_F(LogV2TypesTest, BSONObj) {
.append("str"_sd, "a StringData"_sd)
.obj();
LOGV2(20020, "bson {name}", "name"_attr = bsonObj);
- ASSERT(text->back() ==
+ ASSERT(text.back() ==
std::string("bson ") + bsonObj.jsonString(JsonStringFormat::ExtendedRelaxedV2_0_0));
- ASSERT(mongo::fromjson(json->back())
+ ASSERT(mongo::fromjson(json.back())
.getField(kAttributesFieldName)
.Obj()
.getField("name")
@@ -619,9 +560,9 @@ TEST_F(LogV2TypesTest, BSONArray) {
BSONArray bsonArr =
BSONArrayBuilder().append("first"_sd).append("second"_sd).append("third"_sd).arr();
LOGV2(20021, "{name}", "name"_attr = bsonArr);
- ASSERT_EQUALS(text->back(),
+ ASSERT_EQUALS(text.back(),
bsonArr.jsonString(JsonStringFormat::ExtendedRelaxedV2_0_0, 0, true));
- ASSERT(mongo::fromjson(json->back())
+ ASSERT(mongo::fromjson(json.back())
.getField(kAttributesFieldName)
.Obj()
.getField("name")
@@ -638,8 +579,8 @@ TEST_F(LogV2TypesTest, BSONElement) {
.append("str"_sd, "a StringData"_sd)
.obj();
LOGV2(20022, "bson element {name}", "name"_attr = bsonObj.getField("int32"_sd));
- ASSERT(text->back() == std::string("bson element ") + bsonObj.getField("int32"_sd).toString());
- ASSERT(mongo::fromjson(json->back())
+ ASSERT(text.back() == std::string("bson element ") + bsonObj.getField("int32"_sd).toString());
+ ASSERT(mongo::fromjson(json.back())
.getField(kAttributesFieldName)
.Obj()
.getField("name"_sd)
@@ -656,8 +597,8 @@ TEST_F(LogV2TypesTest, DateT) {
setDateFormatIsLocalTimezone(localTimezone);
Date_t date = Date_t::now();
LOGV2(20023, "Date_t {name}", "name"_attr = date);
- ASSERT_EQUALS(text->back(), std::string("Date_t ") + date.toString());
- ASSERT_EQUALS(mongo::fromjson(json->back())
+ ASSERT_EQUALS(text.back(), std::string("Date_t ") + date.toString());
+ ASSERT_EQUALS(mongo::fromjson(json.back())
.getField(kAttributesFieldName)
.Obj()
.getField("name")
@@ -671,8 +612,8 @@ TEST_F(LogV2TypesTest, DateT) {
TEST_F(LogV2TypesTest, Decimal128) {
LOGV2(20024, "Decimal128 {name}", "name"_attr = Decimal128::kPi);
- ASSERT_EQUALS(text->back(), std::string("Decimal128 ") + Decimal128::kPi.toString());
- ASSERT(mongo::fromjson(json->back())
+ ASSERT_EQUALS(text.back(), std::string("Decimal128 ") + Decimal128::kPi.toString());
+ ASSERT(mongo::fromjson(json.back())
.getField(kAttributesFieldName)
.Obj()
.getField("name")
@@ -684,9 +625,9 @@ TEST_F(LogV2TypesTest, Decimal128) {
TEST_F(LogV2TypesTest, OID) {
OID oid = OID::gen();
LOGV2(20025, "OID {name}", "name"_attr = oid);
- ASSERT_EQUALS(text->back(), std::string("OID ") + oid.toString());
+ ASSERT_EQUALS(text.back(), std::string("OID ") + oid.toString());
ASSERT_EQUALS(
- mongo::fromjson(json->back()).getField(kAttributesFieldName).Obj().getField("name").OID(),
+ mongo::fromjson(json.back()).getField(kAttributesFieldName).Obj().getField("name").OID(),
oid);
ASSERT_EQUALS(lastBSONElement().OID(), oid);
}
@@ -694,8 +635,8 @@ TEST_F(LogV2TypesTest, OID) {
TEST_F(LogV2TypesTest, Timestamp) {
Timestamp ts = Timestamp::max();
LOGV2(20026, "Timestamp {name}", "name"_attr = ts);
- ASSERT_EQUALS(text->back(), std::string("Timestamp ") + ts.toString());
- ASSERT_EQUALS(mongo::fromjson(json->back())
+ ASSERT_EQUALS(text.back(), std::string("Timestamp ") + ts.toString());
+ ASSERT_EQUALS(mongo::fromjson(json.back())
.getField(kAttributesFieldName)
.Obj()
.getField("name")
@@ -707,8 +648,8 @@ TEST_F(LogV2TypesTest, Timestamp) {
TEST_F(LogV2TypesTest, UUID) {
UUID uuid = UUID::gen();
LOGV2(20027, "UUID {name}", "name"_attr = uuid);
- ASSERT_EQUALS(text->back(), std::string("UUID ") + uuid.toString());
- ASSERT_EQUALS(UUID::parse(mongo::fromjson(json->back())
+ ASSERT_EQUALS(text.back(), std::string("UUID ") + uuid.toString());
+ ASSERT_EQUALS(UUID::parse(mongo::fromjson(json.back())
.getField(kAttributesFieldName)
.Obj()
.getField("name")
@@ -719,10 +660,10 @@ TEST_F(LogV2TypesTest, UUID) {
TEST_F(LogV2TypesTest, BoostOptional) {
LOGV2(20028, "boost::optional empty {name}", "name"_attr = boost::optional<bool>());
- ASSERT_EQUALS(text->back(),
+ ASSERT_EQUALS(text.back(),
std::string("boost::optional empty ") +
constants::kNullOptionalString.toString());
- ASSERT(mongo::fromjson(json->back())
+ ASSERT(mongo::fromjson(json.back())
.getField(kAttributesFieldName)
.Obj()
.getField("name")
@@ -730,18 +671,18 @@ TEST_F(LogV2TypesTest, BoostOptional) {
ASSERT(lastBSONElement().isNull());
LOGV2(20029, "boost::optional<bool> {name}", "name"_attr = boost::optional<bool>(true));
- ASSERT_EQUALS(text->back(), std::string("boost::optional<bool> true"));
+ ASSERT_EQUALS(text.back(), std::string("boost::optional<bool> true"));
ASSERT_EQUALS(
- mongo::fromjson(json->back()).getField(kAttributesFieldName).Obj().getField("name").Bool(),
+ mongo::fromjson(json.back()).getField(kAttributesFieldName).Obj().getField("name").Bool(),
true);
ASSERT_EQUALS(lastBSONElement().Bool(), true);
LOGV2(20030,
"boost::optional<boost::optional<bool>> {name}",
"name"_attr = boost::optional<boost::optional<bool>>(boost::optional<bool>(true)));
- ASSERT_EQUALS(text->back(), std::string("boost::optional<boost::optional<bool>> true"));
+ ASSERT_EQUALS(text.back(), std::string("boost::optional<boost::optional<bool>> true"));
ASSERT_EQUALS(
- mongo::fromjson(json->back()).getField(kAttributesFieldName).Obj().getField("name").Bool(),
+ mongo::fromjson(json.back()).getField(kAttributesFieldName).Obj().getField("name").Bool(),
true);
ASSERT_EQUALS(lastBSONElement().Bool(), true);
@@ -749,9 +690,8 @@ TEST_F(LogV2TypesTest, BoostOptional) {
LOGV2(20031,
"boost::optional<TypeWithBSON> {name}",
"name"_attr = boost::optional<TypeWithBSON>(withBSON));
- ASSERT_EQUALS(text->back(),
- std::string("boost::optional<TypeWithBSON> ") + withBSON.toString());
- ASSERT(mongo::fromjson(json->back())
+ ASSERT_EQUALS(text.back(), std::string("boost::optional<TypeWithBSON> ") + withBSON.toString());
+ ASSERT(mongo::fromjson(json.back())
.getField(kAttributesFieldName)
.Obj()
.getField("name")
@@ -763,28 +703,25 @@ TEST_F(LogV2TypesTest, BoostOptional) {
LOGV2(20032,
"boost::optional<TypeWithBSON> {name}",
"name"_attr = boost::optional<TypeWithoutBSON>(withoutBSON));
- ASSERT_EQUALS(text->back(),
+ ASSERT_EQUALS(text.back(),
std::string("boost::optional<TypeWithBSON> ") + withoutBSON.toString());
- ASSERT_EQUALS(mongo::fromjson(json->back())
- .getField(kAttributesFieldName)
- .Obj()
- .getField("name")
- .String(),
- withoutBSON.toString());
+ ASSERT_EQUALS(
+ mongo::fromjson(json.back()).getField(kAttributesFieldName).Obj().getField("name").String(),
+ withoutBSON.toString());
ASSERT_EQUALS(lastBSONElement().String(), withoutBSON.toString());
}
TEST_F(LogV2TypesTest, Duration) {
Milliseconds ms{12345};
LOGV2(20033, "Duration {name}", "name"_attr = ms);
- ASSERT_EQUALS(text->back(), std::string("Duration ") + ms.toString());
- ASSERT_EQUALS(mongo::fromjson(json->back())
+ ASSERT_EQUALS(text.back(), std::string("Duration ") + ms.toString());
+ ASSERT_EQUALS(mongo::fromjson(json.back())
.getField(kAttributesFieldName)
.Obj()
.getField("name" + ms.mongoUnitSuffix())
.Int(),
ms.count());
- ASSERT_EQUALS(BSONObj(bson->back().data())
+ ASSERT_EQUALS(BSONObj(bson.back().data())
.getField(kAttributesFieldName)
.Obj()
.getField("name" + ms.mongoUnitSuffix())
@@ -796,31 +733,31 @@ TEST_F(LogV2Test, TextFormat) {
auto lines = makeLineCapture(TextFormatter());
LOGV2_OPTIONS(20065, {LogTag::kNone}, "warning");
- ASSERT(lines->back().rfind("** WARNING: warning") == std::string::npos);
+ ASSERT(lines.back().rfind("** WARNING: warning") == std::string::npos);
LOGV2_OPTIONS(20066, {LogTag::kStartupWarnings}, "warning");
- ASSERT(lines->back().rfind("** WARNING: warning") != std::string::npos);
+ ASSERT(lines.back().rfind("** WARNING: warning") != std::string::npos);
LOGV2_OPTIONS(20067,
{static_cast<LogTag::Value>(LogTag::kStartupWarnings | LogTag::kPlainShell)},
"warning");
- ASSERT(lines->back().rfind("** WARNING: warning") != std::string::npos);
+ ASSERT(lines.back().rfind("** WARNING: warning") != std::string::npos);
TypeWithBSON t(1.0, 2.0);
LOGV2(20034, "{name} custom formatting", "name"_attr = t);
- ASSERT(lines->back().rfind(t.toString() + " custom formatting") != std::string::npos);
+ ASSERT(lines.back().rfind(t.toString() + " custom formatting") != std::string::npos);
LOGV2(20035, "{name} bson", "name"_attr = t.toBSON());
- ASSERT(lines->back().rfind(t.toBSON().jsonString(JsonStringFormat::ExtendedRelaxedV2_0_0) +
- " bson") != std::string::npos);
+ ASSERT(lines.back().rfind(t.toBSON().jsonString(JsonStringFormat::ExtendedRelaxedV2_0_0) +
+ " bson") != std::string::npos);
TypeWithoutBSON t2(1.0, 2.0);
LOGV2(20036, "{name} custom formatting, no bson", "name"_attr = t2);
- ASSERT(lines->back().rfind(t.toString() + " custom formatting, no bson") != std::string::npos);
+ ASSERT(lines.back().rfind(t.toString() + " custom formatting, no bson") != std::string::npos);
TypeWithNonMemberFormatting t3;
LOGV2(20079, "{name}", "name"_attr = t3);
- ASSERT(lines->back().rfind(toString(t3)) != std::string::npos);
+ ASSERT(lines.back().rfind(toString(t3)) != std::string::npos);
}
std::string hello() {
@@ -835,12 +772,12 @@ public:
template <typename F>
void validate(F validator) {
- validator(mongo::fromjson(lines->back()));
- validator(BSONObj(linesBson->back().data()));
+ validator(mongo::fromjson(lines.back()));
+ validator(BSONObj(linesBson.back().data()));
}
- std::unique_ptr<LineCapture> lines = makeLineCapture(JSONFormatter());
- std::unique_ptr<LineCapture> linesBson = makeLineCapture(BSONFormatter());
+ LineCapture lines = makeLineCapture(JSONFormatter());
+ LineCapture linesBson = makeLineCapture(BSONFormatter());
};
TEST_F(LogV2JsonBsonTest, Root) {
@@ -1185,8 +1122,8 @@ public:
/** Ensure json and bson modes both pass. */
template <typename F>
void validate(F validator) {
- validator(mongo::fromjson(json->back()));
- validator(BSONObj(bson->back().data()));
+ validator(mongo::fromjson(json.back()));
+ validator(BSONObj(bson.back().data()));
}
};
@@ -1194,7 +1131,7 @@ public:
TEST_F(LogV2ContainerTest, StandardSequential) {
std::vector<std::string> vectorStrings = {"str1", "str2", "str3"};
LOGV2(20047, "{name}", "name"_attr = vectorStrings);
- ASSERT_EQUALS(text->back(), textJoin(vectorStrings, [](auto&& s) { return s; }));
+ ASSERT_EQUALS(text.back(), textJoin(vectorStrings, [](auto&& s) { return s; }));
validate([&vectorStrings](const BSONObj& obj) {
std::vector<BSONElement> jsonVector =
obj.getField(kAttributesFieldName).Obj().getField("name").Array();
@@ -1230,7 +1167,7 @@ TEST_F(LogV2ContainerTest, CustomFormatting) {
std::list<TypeWithBSON> listCustom = {
TypeWithBSON(0.0, 1.0), TypeWithBSON(2.0, 3.0), TypeWithBSON(4.0, 5.0)};
LOGV2(20048, "{name}", "name"_attr = listCustom);
- ASSERT_EQUALS(text->back(), textJoin(listCustom, [](auto&& x) { return x.toString(); }));
+ ASSERT_EQUALS(text.back(), textJoin(listCustom, [](auto&& x) { return x.toString(); }));
validate([&listCustom](const BSONObj& obj) {
std::vector<BSONElement> jsonVector =
obj.getField(kAttributesFieldName).Obj().getField("name").Array();
@@ -1246,7 +1183,7 @@ TEST_F(LogV2ContainerTest, CustomFormatting) {
TEST_F(LogV2ContainerTest, OptionalsAsElements) {
std::forward_list<boost::optional<bool>> listOptionalBool = {true, boost::none, false};
LOGV2(20049, "{name}", "name"_attr = listOptionalBool);
- ASSERT_EQUALS(text->back(), textJoin(listOptionalBool, [](const auto& item) -> std::string {
+ ASSERT_EQUALS(text.back(), textJoin(listOptionalBool, [](const auto& item) -> std::string {
if (!item)
return constants::kNullOptionalString.toString();
if (*item)
@@ -1273,7 +1210,7 @@ TEST_F(LogV2ContainerTest, OptionalsAsElements) {
TEST_F(LogV2ContainerTest, Nested) {
std::array<std::deque<int>, 4> arrayOfDeques = {{{0, 1}, {2, 3}, {4, 5}, {6, 7}}};
LOGV2(20050, "{name}", "name"_attr = arrayOfDeques);
- ASSERT_EQUALS(text->back(), textJoin(arrayOfDeques, [](auto&& outer) {
+ ASSERT_EQUALS(text.back(), textJoin(arrayOfDeques, [](auto&& outer) {
return textJoin(outer, [](auto&& v) { return fmt::format("{}", v); });
}));
validate([&arrayOfDeques](const BSONObj& obj) {
@@ -1299,7 +1236,7 @@ TEST_F(LogV2ContainerTest, Associative) {
// Associative containers are also supported
std::map<std::string, std::string> mapStrStr = {{"key1", "val1"}, {"key2", "val2"}};
LOGV2(20051, "{name}", "name"_attr = mapStrStr);
- ASSERT_EQUALS(text->back(), textJoin(mapStrStr, [](const auto& item) {
+ ASSERT_EQUALS(text.back(), textJoin(mapStrStr, [](const auto& item) {
return fmt::format("{}: {}", item.first, item.second);
}));
validate([&mapStrStr](const BSONObj& obj) {
@@ -1318,7 +1255,7 @@ TEST_F(LogV2ContainerTest, AssociativeWithOptionalSequential) {
{"key2", boost::optional<std::vector<int>>{boost::none}}};
LOGV2(20052, "{name}", "name"_attr = mapOptionalVector);
- ASSERT_EQUALS(text->back(), textJoin(mapOptionalVector, [](auto&& item) {
+ ASSERT_EQUALS(text.back(), textJoin(mapOptionalVector, [](auto&& item) {
std::string r = item.first + ": ";
if (item.second) {
r += textJoin(*item.second, [](int v) { return fmt::format("{}", v); });
@@ -1439,7 +1376,7 @@ TEST_F(LogV2Test, Unicode) {
};
auto getLastMongo = [&]() {
- return mongo::fromjson(lines->back())
+ return mongo::fromjson(lines.back())
.getField(constants::kAttributesFieldName)
.Obj()
.getField("name")
@@ -1449,7 +1386,7 @@ TEST_F(LogV2Test, Unicode) {
auto getLastPtree = [&]() {
namespace pt = boost::property_tree;
- std::istringstream json_stream(lines->back());
+ std::istringstream json_stream(lines.back());
pt::ptree ptree;
pt::json_parser::read_json(json_stream, ptree);
return ptree.get<std::string>(std::string(constants::kAttributesFieldName) + ".name");
@@ -1505,7 +1442,7 @@ TEST_F(LogV2Test, JsonTruncation) {
// Attributes coming after the truncated one should be written
ASSERT(obj.getField(constants::kAttributesFieldName).Obj().getField("attr2").Bool());
};
- validateTruncation(mongo::fromjson(lines->back()));
+ validateTruncation(mongo::fromjson(lines.back()));
LOGV2_OPTIONS(20086, {LogTruncation::Disabled}, "{name}", "name"_attr = builder.done());
auto validateTruncationDisabled = [&](const BSONObj& obj) {
@@ -1524,7 +1461,7 @@ TEST_F(LogV2Test, JsonTruncation) {
ASSERT(!obj.hasField(constants::kTruncatedFieldName));
ASSERT(!obj.hasField(constants::kTruncatedSizeFieldName));
};
- validateTruncationDisabled(mongo::fromjson(lines->back()));
+ validateTruncationDisabled(mongo::fromjson(lines.back()));
BSONArrayBuilder arrBuilder;
// Fields will use more than one byte each so this will truncate at some point
@@ -1549,55 +1486,7 @@ TEST_F(LogV2Test, JsonTruncation) {
obj.getField(constants::kTruncatedSizeFieldName).Obj().getField("name"_sd).Int(),
arrToLog.objsize());
};
- validateArrayTruncation(mongo::fromjson(lines->back()));
-}
-
-TEST_F(LogV2Test, StringTruncation) {
- const AtomicWord<int32_t> maxAttributeSizeKB(1);
- auto lines = makeLineCapture(JSONFormatter(&maxAttributeSizeKB));
-
- std::size_t maxLength = maxAttributeSizeKB.load() << 10;
- std::string prefix(maxLength - 3, 'a');
-
- struct TestCase {
- std::string input;
- std::string suffix;
- std::string note;
- };
-
- TestCase tests[] = {
- {prefix + "LMNOPQ", "LMN", "unescaped 1-byte octet"},
- // "\n\"NOPQ" expands to "\\n\\\"NOPQ" after escape, and the limit
- // is reached at the 2nd '\\' octet, but since it splits the "\\\""
- // sequence, the actual truncation happens after the 'n' octet.
- {prefix + "\n\"NOPQ", "\n", "2-byte escape sequence"},
- // "L\vNOPQ" expands to "L\\u000bNOPQ" after escape, and the limit
- // is reached at the 'u' octet, so the entire sequence is truncated.
- {prefix + "L\vNOPQ", "L", "multi-byte escape sequence"},
- {prefix + "LM\xC3\xB1PQ", "LM", "2-byte UTF-8 sequence"},
- {prefix + "L\xE1\x9B\x8FPQ", "L", "3-byte UTF-8 sequence"},
- {prefix + "L\xF0\x90\x8C\xBCQ", "L", "4-byte UTF-8 sequence"},
- {prefix + "\xE1\x9B\x8E\xE1\x9B\x8F", "\xE1\x9B\x8E", "UTF-8 codepoint boundary"},
- // The invalid UTF-8 codepoint 0xC3 is replaced with "\\ufffd", and truncated entirely
- {prefix + "L\xC3NOPQ", "L", "escaped invalid codepoint"},
- {std::string(maxLength, '\\'), "\\", "escaped backslash"},
- };
-
- for (const auto& [input, suffix, note] : tests) {
- LOGV2(6694001, "name", "name"_attr = input);
- BSONObj obj = fromjson(lines->back());
-
- auto str = obj[constants::kAttributesFieldName]["name"].checkAndGetStringData();
- std::string context = "Failed test: " + note;
-
- ASSERT_LTE(str.size(), maxLength) << context;
- ASSERT(str.endsWith(suffix))
- << context << " - string " << str << " does not end with " << suffix;
-
- auto trunc = obj[constants::kTruncatedFieldName]["name"];
- ASSERT_EQUALS(trunc["type"].String(), typeName(BSONType::String)) << context;
- ASSERT_EQUALS(trunc["size"].numberLong(), str::escapeForJSON(input).size()) << context;
- }
+ validateArrayTruncation(mongo::fromjson(lines.back()));
}
TEST_F(LogV2Test, Threads) {
@@ -1632,9 +1521,9 @@ TEST_F(LogV2Test, Threads) {
thread.join();
}
- ASSERT(linesPlain->size() == threads.size() * kNumPerThread);
- ASSERT(linesText->size() == threads.size() * kNumPerThread);
- ASSERT(linesJson->size() == threads.size() * kNumPerThread);
+ ASSERT(linesPlain.size() == threads.size() * kNumPerThread);
+ ASSERT(linesText.size() == threads.size() * kNumPerThread);
+ ASSERT(linesJson.size() == threads.size() * kNumPerThread);
}
TEST_F(LogV2Test, Ramlog) {
@@ -1648,7 +1537,7 @@ TEST_F(LogV2Test, Ramlog) {
auto verifyRamLog = [&] {
RamLog::LineIterator iter(ramlog);
- for (const auto& s : lines->lines()) {
+ for (const auto& s : lines.lines()) {
const auto next = iter.next();
if (s != next) {
std::cout << "\n\n\n********************** s='" << s << "', next='" << next
@@ -1771,8 +1660,8 @@ TEST_F(LogV2Test, MultipleDomains) {
}
};
LogDomain other_domain(std::make_unique<OtherDomain>());
- synchronized_value<std::vector<std::string>> other_lines;
- auto other_sink = LogCaptureBackend::create(std::make_unique<Listener>(&other_lines), true);
+ std::vector<std::string> other_lines;
+ auto other_sink = LogCaptureBackend::create(other_lines, true);
other_sink->set_filter(ComponentSettingsFilter(other_domain, mgr().getGlobalSettings()));
other_sink->set_formatter(PlainFormatter());
attachSink(other_sink);
@@ -1780,13 +1669,12 @@ TEST_F(LogV2Test, MultipleDomains) {
auto global_lines = makeLineCapture(PlainFormatter());
LOGV2_OPTIONS(20070, {&other_domain}, "test");
- auto logLinesLockGuard = *other_lines;
- ASSERT(global_lines->lines().empty());
- ASSERT(logLinesLockGuard->back() == "test");
+ ASSERT(global_lines.lines().empty());
+ ASSERT(other_lines.back() == "test");
LOGV2(20060, "global domain log");
- ASSERT(global_lines->back() == "global domain log");
- ASSERT(logLinesLockGuard->back() == "test");
+ ASSERT(global_lines.back() == "global domain log");
+ ASSERT(other_lines.back() == "test");
}
TEST_F(LogV2Test, FileLogging) {
@@ -1838,10 +1726,9 @@ TEST_F(LogV2Test, FileLogging) {
}
TEST_F(LogV2Test, UserAssert) {
- synchronized_value<std::vector<std::string>> syncedLines;
+ std::vector<std::string> lines;
auto sink = wrapInSynchronousSink(wrapInCompositeBackend(
- boost::make_shared<LogCaptureBackend>(std::make_unique<Listener>(&syncedLines), true),
- boost::make_shared<UserAssertSink>()));
+ boost::make_shared<LogCaptureBackend>(lines, true), boost::make_shared<UserAssertSink>()));
applyDefaultFilterToSink(sink);
sink->set_formatter(PlainFormatter());
attachSink(sink);
@@ -1851,31 +1738,31 @@ TEST_F(LogV2Test, UserAssert) {
ASSERT_THROWS_WITH_CHECK(
LOGV2_OPTIONS(4652000, {UserAssertAfterLog(ErrorCodes::BadValue)}, "uasserting log"),
DBException,
- [&syncedLines](const DBException& ex) {
+ [&lines](const DBException& ex) {
ASSERT_EQUALS(ex.code(), ErrorCodes::BadValue);
ASSERT_EQUALS(ex.reason(), "uasserting log");
- ASSERT_EQUALS((**syncedLines).front(), ex.reason());
+ ASSERT_EQUALS(lines.front(), ex.reason());
});
- (**syncedLines).clear();
+ lines.clear();
ASSERT_THROWS_WITH_CHECK(LOGV2_OPTIONS(4652001,
{UserAssertAfterLog(ErrorCodes::BadValue)},
"uasserting log {name}",
"name"_attr = 1),
DBException,
- [&syncedLines](const DBException& ex) {
+ [&lines](const DBException& ex) {
ASSERT_EQUALS(ex.code(), ErrorCodes::BadValue);
ASSERT_EQUALS(ex.reason(), "uasserting log 1");
- ASSERT_EQUALS((**syncedLines).front(), ex.reason());
+ ASSERT_EQUALS(lines.front(), ex.reason());
});
- (**syncedLines).clear();
+ lines.clear();
ASSERT_THROWS_WITH_CHECK(LOGV2_OPTIONS(4716000, {UserAssertAfterLog()}, "uasserting log"),
DBException,
- [&syncedLines](const DBException& ex) {
+ [&lines](const DBException& ex) {
ASSERT_EQUALS(ex.code(), 4716000);
ASSERT_EQUALS(ex.reason(), "uasserting log");
- ASSERT_EQUALS((**syncedLines).front(), ex.reason());
+ ASSERT_EQUALS(lines.front(), ex.reason());
});
}
diff --git a/src/mongo/logv2/redaction.cpp b/src/mongo/logv2/redaction.cpp
index 29536660722..0b143ba39ae 100644
--- a/src/mongo/logv2/redaction.cpp
+++ b/src/mongo/logv2/redaction.cpp
@@ -50,12 +50,12 @@ constexpr auto kRedactionDefaultMask = "###"_sd;
BSONObj redact(const BSONObj& objectToRedact) {
if (!logv2::shouldRedactLogs()) {
if (!logv2::shouldRedactBinDataEncrypt()) {
- return objectToRedact.redact(BSONObj::RedactLevel::sensitiveOnly);
+ return objectToRedact;
}
- return objectToRedact.redact(BSONObj::RedactLevel::encryptedAndSensitive);
+ return objectToRedact.redact(true /* onlyEncryptedFields */);
}
- return objectToRedact.redact(BSONObj::RedactLevel::all);
+ return objectToRedact.redact(false /* onlyEncryptedFields */);
}
StringData redact(StringData stringToRedact) {
diff --git a/src/mongo/logv2/redaction_test.cpp b/src/mongo/logv2/redaction_test.cpp
index ca61f7ec295..dda840a4681 100644
--- a/src/mongo/logv2/redaction_test.cpp
+++ b/src/mongo/logv2/redaction_test.cpp
@@ -34,7 +34,6 @@
#include "mongo/base/error_extra_info.h"
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/bson/bsontypes.h"
-#include "mongo/bson/json.h"
#include "mongo/db/jsobj.h"
#include "mongo/logv2/log_util.h"
#include "mongo/unittest/unittest.h"
@@ -141,6 +140,8 @@ TEST(RedactEncryptedStringTest, BasicStrings) {
}
BSONObj obj = builder.done();
+ std::cout << "This is obj: " << obj.toString() << std::endl;
+
auto redactedStr = R"({ type6: "###", string: "string", nestedobj: { subobj: "###" } })";
ASSERT_EQ(redact(obj).toString(), redactedStr);
@@ -148,98 +149,6 @@ TEST(RedactEncryptedStringTest, BasicStrings) {
ASSERT_EQ(redact(obj).toString(), obj.toString());
}
-TEST(RedactSensitiveStringTest, BasicStrings) {
- BSONObjBuilder builder{};
- builder.appendBinData("type8", sizeof(zero), BinDataType::Sensitive, zero);
- builder.append("string", "string");
- {
- BSONObjBuilder sub(builder.subobjStart("nestedobj"));
- sub.appendBinData("subobj", sizeof(zero), BinDataType::Sensitive, zero);
- }
- const BSONObj obj = builder.done();
-
- {
- logv2::setShouldRedactBinDataEncrypt(true);
- logv2::setShouldRedactLogs(true);
-
- // Fully-redacted logs should just redact everything
- const auto redactedStr = R"({ type8: "###", string: "###", nestedobj: { subobj: "###" } })";
- ASSERT_EQ(redact(obj).toString(), redactedStr);
- }
-
- {
- const auto redactedStr =
- R"({ type8: "###", string: "string", nestedobj: { subobj: "###" } })";
- // The setting for redacting logs shouldn't affect sensitive BinData.
- logv2::setShouldRedactLogs(false);
- ASSERT_EQ(redact(obj).toString(), redactedStr);
-
- // The setting for redacting encrypted BinData shouldn't affect sensitive BinData, either.
- logv2::setShouldRedactBinDataEncrypt(false);
- ASSERT_EQ(redact(obj).toString(), redactedStr);
- }
-}
-
-TEST(RedactSensitiveStringTest, NestedStrings) {
- // The setting for redacting logs shouldn't affect sensitive BinData.
- logv2::setShouldRedactBinDataEncrypt(false);
- // The setting for redacting encrypted BinData shouldn't affect sensitive BinData, either.
- logv2::setShouldRedactLogs(false);
-
- BSONObjBuilder builder{};
-
- // Test for [ "###", { ...: "###" }, ... ] shape cases.
- {
- auto subarray = BSONObjBuilder(builder.subarrayStart("subarray"));
- subarray.appendBinData("0", sizeof(zero), BinDataType::Sensitive, zero);
-
- for (auto nSubobjs = 0; nSubobjs < 3; ++nSubobjs) {
- BSONObjBuilder(subarray.subobjStart("subobj"))
- .appendBinData("type8", sizeof(zero), BinDataType::Sensitive, zero);
- }
- }
-
- // Test for { ...: "###", ...: [ "###", ... ] } shape cases.
- {
- auto subobj = BSONObjBuilder(builder.subobjStart("subobj"));
- subobj.appendBinData("type8", sizeof(zero), BinDataType::Sensitive, zero);
-
- auto subarray = BSONObjBuilder(subobj.subarrayStart("subarray"));
- for (auto nSubobjs = 0; nSubobjs < 3; ++nSubobjs) {
- subarray.appendBinData("0", sizeof(zero), BinDataType::Sensitive, zero);
- }
- }
-
- // Test for [ [ [ "###", ... ] ] ] shape cases.
- {
- auto subarray1 = BSONObjBuilder(builder.subarrayStart("subarrays"));
- auto subarray2 = BSONObjBuilder(subarray1.subarrayStart("subarray"));
- auto subarray3 = BSONObjBuilder(subarray2.subarrayStart("subarray"));
- for (auto nSubobjs = 0; nSubobjs < 3; ++nSubobjs) {
- subarray3.appendBinData("0", sizeof(zero), BinDataType::Sensitive, zero);
- }
- }
-
- // Test for { ...: { ...: { ...: "###" } } } shape cases.
- {
- auto subobj1 = BSONObjBuilder(builder.subobjStart("subobjs"));
- auto subobj2 = BSONObjBuilder(subobj1.subobjStart("subobj"));
- auto subobj3 = BSONObjBuilder(subobj2.subobjStart("subobj"));
- subobj3.appendBinData("type8", sizeof(zero), BinDataType::Sensitive, zero);
- }
-
- const BSONObj obj = builder.done();
-
- // Type 8 values should all be redacted.
- const BSONObj expected = fromjson(R"({
- subarray: [ "###", { type8: "###" }, { type8: "###" }, { type8: "###" } ],
- subobj: { type8: "###", subarray: [ "###", "###", "###" ] },
- subarrays: [ [ [ "###", "###", "###" ] ] ],
- subobjs: { subobj: { subobj: { type8: "###" } } }
- })");
- ASSERT_EQ(redact(obj).toString(), expected.toString());
-}
-
void testBSONCases(std::vector<BSONStringPair>& testCases) {
for (auto m : testCases) {
ASSERT_EQ(redact(m.first).toString(), m.second);