diff options
author | Henrik Edin <henrik.edin@mongodb.com> | 2020-02-24 11:19:20 -0500 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-02-26 22:09:44 +0000 |
commit | 95a345cc3f19a4762c68a40c7dd283ba0772ee11 (patch) | |
tree | 96fed9d0fdf1e04568cc99df8fc7285722796e4b | |
parent | b88b28fccb697a020368c6a056f9987e4ff91206 (diff) | |
download | mongo-95a345cc3f19a4762c68a40c7dd283ba0772ee11.tar.gz |
SERVER-46008 Fix so logging works during global shutdown
-rw-r--r-- | src/mongo/logv2/log_domain_global.cpp | 43 | ||||
-rw-r--r-- | src/mongo/logv2/log_manager.cpp | 4 | ||||
-rw-r--r-- | src/mongo/logv2/log_source.h | 11 | ||||
-rw-r--r-- | src/mongo/logv2/log_test_v2.cpp | 18 |
4 files changed, 60 insertions, 16 deletions
diff --git a/src/mongo/logv2/log_domain_global.cpp b/src/mongo/logv2/log_domain_global.cpp index 7b8e117fa02..000ed72ffe3 100644 --- a/src/mongo/logv2/log_domain_global.cpp +++ b/src/mongo/logv2/log_domain_global.cpp @@ -68,6 +68,8 @@ struct LogDomainGlobal::Impl { const ConfigurationOptions& config() const; + LogSource& source(); + LogDomainGlobal& _parent; LogComponentSettings _settings; ConfigurationOptions _config; @@ -76,6 +78,9 @@ struct LogDomainGlobal::Impl { #ifndef _WIN32 boost::shared_ptr<boost::log::sinks::unlocked_sink<SyslogBackend>> _syslogSink; #endif + AtomicWord<int32_t> activeSourceThreadLocals{0}; + LogSource shutdownLogSource{&_parent, true}; + bool isInShutdown{false}; }; LogDomainGlobal::Impl::Impl(LogDomainGlobal& parent) : _parent(parent) { @@ -96,6 +101,10 @@ LogDomainGlobal::Impl::Impl(LogDomainGlobal& parent) : _parent(parent) { // Set default configuration invariant(configure({}).isOK()); + + // Make a call to source() to make sure the internal thread_local is created as early as + // possible and thus destroyed as late as possible. + source(); } Status LogDomainGlobal::Impl::configure(LogDomainGlobal::ConfigurationOptions const& options) { @@ -214,6 +223,36 @@ Status LogDomainGlobal::Impl::rotate(bool rename, StringData renameSuffix) { return Status::OK(); } +LogSource& LogDomainGlobal::Impl::source() { + // Use a thread_local logger so we don't need to have locking. thread_locals are destroyed + // before statics so keep track of number of thread_locals we have active and if this code + // is hit when it is zero then we are in shutdown and can use a global LogSource that does + // not provide synchronization instead. + class SourceCache { + public: + SourceCache(Impl* domain) : _domain(domain), _source(&domain->_parent) { + _domain->activeSourceThreadLocals.addAndFetch(1); + } + ~SourceCache() { + if (_domain->activeSourceThreadLocals.subtractAndFetch(1) == 0) { + _domain->isInShutdown = true; + } + } + + LogSource& source() { + return _source; + } + + private: + Impl* _domain; + LogSource _source; + }; + thread_local SourceCache cache(this); + if (isInShutdown) + return shutdownLogSource; + return cache.source(); +} + LogDomainGlobal::LogDomainGlobal() { _impl = std::make_unique<Impl>(*this); } @@ -221,9 +260,7 @@ LogDomainGlobal::LogDomainGlobal() { LogDomainGlobal::~LogDomainGlobal() {} LogSource& LogDomainGlobal::source() { - // Use a thread_local logger so we don't need to have locking - thread_local LogSource lg(this); - return lg; + return _impl->source(); } diff --git a/src/mongo/logv2/log_manager.cpp b/src/mongo/logv2/log_manager.cpp index c532989b5d7..8f8453417e2 100644 --- a/src/mongo/logv2/log_manager.cpp +++ b/src/mongo/logv2/log_manager.cpp @@ -51,8 +51,8 @@ LogManager::LogManager() { LogManager::~LogManager() {} LogManager& LogManager::global() { - static LogManager globalLogManager; - return globalLogManager; + static LogManager* globalLogManager = new LogManager(); + return *globalLogManager; } LogDomain& LogManager::getGlobalDomain() { diff --git a/src/mongo/logv2/log_source.h b/src/mongo/logv2/log_source.h index 25eea5c36b4..99269bcdba2 100644 --- a/src/mongo/logv2/log_source.h +++ b/src/mongo/logv2/log_source.h @@ -57,7 +57,7 @@ private: basic_logger<char, LogSource, boost::log::sources::single_thread_model>; public: - LogSource(const LogDomain::Internal* domain) + explicit LogSource(const LogDomain::Internal* domain, bool isShutdown) : _domain(domain), _severity(LogSeverity::Log()), _component(LogComponent::kDefault), @@ -73,11 +73,14 @@ 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([]() { return getThreadName(); })); + add_attribute_unlocked(attributes::threadName(), + boost::log::attributes::make_function([isShutdown]() { + return isShutdown ? "shutdown"_sd : getThreadName(); + })); } + explicit LogSource(const LogDomain::Internal* domain) : LogSource(domain, false) {} + boost::log::record open_record(int32_t id, LogSeverity severity, LogComponent component, diff --git a/src/mongo/logv2/log_test_v2.cpp b/src/mongo/logv2/log_test_v2.cpp index 0da56af42ea..12a592975d9 100644 --- a/src/mongo/logv2/log_test_v2.cpp +++ b/src/mongo/logv2/log_test_v2.cpp @@ -163,10 +163,10 @@ BSONObj toBSON(const TypeWithNonMemberFormatting&) { return builder.obj(); } -class LogDuringInitTester { +class LogDuringInitShutdownTester { public: - LogDuringInitTester() { - std::vector<std::string> lines; + LogDuringInitShutdownTester() { + auto sink = LogCaptureBackend::create(lines); sink->set_filter(ComponentSettingsFilter(LogManager::global().getGlobalDomain(), LogManager::global().getGlobalSettings())); @@ -174,13 +174,17 @@ public: boost::log::core::get()->add_sink(sink); LOGV2(20001, "log during init"); - ASSERT(lines.back() == "log during init"); - - boost::log::core::get()->remove_sink(sink); + ASSERT_EQUALS(lines.back(), "log during init"); } + ~LogDuringInitShutdownTester() { + LOGV2(4600800, "log during shutdown"); + ASSERT_EQUALS(lines.back(), "log during shutdown"); + } + + std::vector<std::string> lines; }; -LogDuringInitTester logDuringInit; +LogDuringInitShutdownTester logDuringInitAndShutdown; TEST_F(LogTestV2, Basic) { std::vector<std::string> lines; |