diff options
Diffstat (limited to 'src/mongo/db/ftdc')
| -rw-r--r-- | src/mongo/db/ftdc/SConscript | 31 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/collector.cpp | 1 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/compressor_test.cpp | 2 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/constants.h | 6 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/controller.cpp | 31 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/controller.h | 15 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/controller_test.cpp | 2 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/ftdc_mongod.cpp | 323 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/ftdc_mongod.h | 56 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/ftdc_mongos.cpp | 153 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/ftdc_mongos.h | 43 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/ftdc_server.cpp | 350 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/ftdc_server.h | 103 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/ftdc_system_stats.h | 1 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/util.cpp | 13 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/util.h | 5 | ||||
| -rw-r--r-- | src/mongo/db/ftdc/util_test.cpp | 21 |
17 files changed, 804 insertions, 352 deletions
diff --git a/src/mongo/db/ftdc/SConscript b/src/mongo/db/ftdc/SConscript index 0d16aec93f2..81df9ad0f4d 100644 --- a/src/mongo/db/ftdc/SConscript +++ b/src/mongo/db/ftdc/SConscript @@ -21,7 +21,6 @@ ftdcEnv.Library( LIBDEPS=[ '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/bson/util/bson_extract', - '$BUILD_DIR/mongo/db/server_options_core', '$BUILD_DIR/mongo/db/service_context', '$BUILD_DIR/third_party/s2/s2', # For VarInt '$BUILD_DIR/third_party/shim_zlib', @@ -40,24 +39,44 @@ elif env.TargetOSIs('windows'): ] env.Library( - target='ftdc_mongod', + target='ftdc_server', source=[ - 'ftdc_commands.cpp', - 'ftdc_mongod.cpp', + 'ftdc_server.cpp', 'ftdc_system_stats.cpp', 'ftdc_system_stats_${TARGET_OS}.cpp', ], LIBDEPS=[ '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/db/commands', - '$BUILD_DIR/mongo/db/repl/repl_coordinator_global', '$BUILD_DIR/mongo/db/server_parameters', - '$BUILD_DIR/mongo/db/storage/storage_options', '$BUILD_DIR/mongo/util/processinfo', 'ftdc' ] + platform_libs, ) +env.Library( + target='ftdc_mongod', + source=[ + 'ftdc_commands.cpp', + 'ftdc_mongod.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/db/repl/repl_coordinator_global', + '$BUILD_DIR/mongo/db/storage/storage_options', + 'ftdc_server' + ], +) + +env.Library( + target='ftdc_mongos', + source=[ + 'ftdc_mongos.cpp', + ], + LIBDEPS=[ + 'ftdc_server' + ], +) + env.CppUnitTest( target='ftdc_test', source=[ diff --git a/src/mongo/db/ftdc/collector.cpp b/src/mongo/db/ftdc/collector.cpp index 611f12dff5a..7c35fb12bb6 100644 --- a/src/mongo/db/ftdc/collector.cpp +++ b/src/mongo/db/ftdc/collector.cpp @@ -67,6 +67,7 @@ std::tuple<BSONObj, Date_t> FTDCCollectorCollection::collect(Client* client) { // batches that are taking a long time. auto txn = client->makeOperationContext(); txn->lockState()->setShouldConflictWithSecondaryBatchApplication(false); + txn->lockState()->setShouldAcquireTicket(false); for (auto& collector : _collectors) { BSONObjBuilder subObjBuilder(builder.subobjStart(collector->name())); diff --git a/src/mongo/db/ftdc/compressor_test.cpp b/src/mongo/db/ftdc/compressor_test.cpp index 688197a392a..0c01bd58040 100644 --- a/src/mongo/db/ftdc/compressor_test.cpp +++ b/src/mongo/db/ftdc/compressor_test.cpp @@ -368,7 +368,7 @@ TEST(FTDCCompressor, TestNumbersCompat) { } // Test various date time types -TEST(AFTDCCompressor, TestDateTimeTypes) { +TEST(FTDCCompressor, TestDateTimeTypes) { TestTie c; for (int i = 0; i < 10; i++) { BSONObjBuilder builder1; diff --git a/src/mongo/db/ftdc/constants.h b/src/mongo/db/ftdc/constants.h index a989fd35b64..3fe5191ff44 100644 --- a/src/mongo/db/ftdc/constants.h +++ b/src/mongo/db/ftdc/constants.h @@ -26,6 +26,10 @@ * then also delete it in the license file. */ +#pragma once + +#include "mongo/base/string_data.h" + namespace mongo { extern const char kFTDCInterimFile[]; @@ -42,4 +46,6 @@ extern const char kFTDCDocsField[]; extern const char kFTDCCollectStartField[]; extern const char kFTDCCollectEndField[]; +constexpr StringData kFTDCDefaultDirectory = "diagnostic.data"_sd; + } // namespace mongo diff --git a/src/mongo/db/ftdc/controller.cpp b/src/mongo/db/ftdc/controller.cpp index 9e2987db0f9..bc3d4df444c 100644 --- a/src/mongo/db/ftdc/controller.cpp +++ b/src/mongo/db/ftdc/controller.cpp @@ -47,9 +47,19 @@ namespace mongo { -void FTDCController::setEnabled(bool enabled) { +Status FTDCController::setEnabled(bool enabled) { stdx::lock_guard<stdx::mutex> lock(_mutex); + + if (_path.empty()) { + return Status(ErrorCodes::FTDCPathNotSet, + str::stream() << "FTDC cannot be enabled without setting the set parameter " + "'diagnosticDataCollectionDirectoryPath' first."); + } + _configTemp.enabled = enabled; + _condvar.notify_one(); + + return Status::OK(); } void FTDCController::setPeriod(Milliseconds millis) { @@ -82,6 +92,23 @@ void FTDCController::setMaxSamplesPerInterimMetricChunk(size_t size) { _condvar.notify_one(); } +Status FTDCController::setDirectory(const boost::filesystem::path& path) { + stdx::lock_guard<stdx::mutex> lock(_mutex); + + if (!_path.empty()) { + return Status(ErrorCodes::FTDCPathAlreadySet, + str::stream() << "FTDC path has already been set to '" << _path.string() + << "'. It cannot be changed."); + } + + _path = path; + + // Do not notify for the change since it has to be enabled via setEnabled. + + return Status::OK(); +} + + void FTDCController::addPeriodicCollector(std::unique_ptr<FTDCCollectorInterface> collector) { { stdx::lock_guard<stdx::mutex> lock(_mutex); @@ -203,7 +230,7 @@ void FTDCController::doLoop() { } // TODO: consider only running this thread if we are enabled - // for now, we just keep an idle thread as it is simplier + // for now, we just keep an idle thread as it is simpler if (_config.enabled) { // Delay initialization of FTDCFileManager until we are sure the user has enabled // FTDC diff --git a/src/mongo/db/ftdc/controller.h b/src/mongo/db/ftdc/controller.h index 44b5e838506..e73d570598d 100644 --- a/src/mongo/db/ftdc/controller.h +++ b/src/mongo/db/ftdc/controller.h @@ -62,8 +62,12 @@ public: /* * Set whether the controller is enabled, and collects data. + * + * Returns ErrorCodes::FTDCPathNotSet if no log path has been specified for FTDC. This occurs + * in MongoS in some situations since MongoS is not required to have a storage directory like + * MongoD does. */ - void setEnabled(bool enabled); + Status setEnabled(bool enabled); /** * Set the period for data collection. @@ -94,6 +98,13 @@ public: */ void setMaxSamplesPerInterimMetricChunk(size_t size); + /* + * Set the path to store FTDC files if not already set. + * + * Returns ErrorCodes::FTDCPathAlreadySet if the path has already been set. + */ + Status setDirectory(const boost::filesystem::path& path); + /** * Add a metric collector to collect periodically. i.e., serverStatus */ @@ -172,7 +183,7 @@ private: State _state{State::kNotStarted}; // Directory to store files - const boost::filesystem::path _path; + boost::filesystem::path _path; // Mutex to protect the condvar, configuration changes, and most recent periodic document. stdx::mutex _mutex; diff --git a/src/mongo/db/ftdc/controller_test.cpp b/src/mongo/db/ftdc/controller_test.cpp index 365f06580cd..c75a3fe44d6 100644 --- a/src/mongo/db/ftdc/controller_test.cpp +++ b/src/mongo/db/ftdc/controller_test.cpp @@ -254,7 +254,7 @@ TEST(FTDCControllerTest, TestStartAsDisabled) { ASSERT_EQUALS(files0.size(), 0UL); - c.setEnabled(true); + ASSERT_OK(c.setEnabled(true)); c1Ptr->setSignalOnCount(50); diff --git a/src/mongo/db/ftdc/ftdc_mongod.cpp b/src/mongo/db/ftdc/ftdc_mongod.cpp index 094a2b05d06..1f53ec345ea 100644 --- a/src/mongo/db/ftdc/ftdc_mongod.cpp +++ b/src/mongo/db/ftdc/ftdc_mongod.cpp @@ -31,295 +31,18 @@ #include "mongo/db/ftdc/ftdc_mongod.h" #include <boost/filesystem.hpp> -#include <fstream> -#include <memory> -#include "mongo/base/init.h" -#include "mongo/base/status.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/commands.h" -#include "mongo/db/ftdc/collector.h" -#include "mongo/db/ftdc/config.h" +#include "mongo/db/ftdc/constants.h" #include "mongo/db/ftdc/controller.h" -#include "mongo/db/ftdc/ftdc_system_stats.h" -#include "mongo/db/jsobj.h" +#include "mongo/db/ftdc/ftdc_server.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/repl/replication_coordinator_global.h" -#include "mongo/db/server_parameters.h" -#include "mongo/db/service_context.h" #include "mongo/db/storage/storage_options.h" namespace mongo { namespace { - -const auto getFTDCController = ServiceContext::declareDecoration<std::unique_ptr<FTDCController>>(); - -FTDCController* getGlobalFTDCController() { - if (!hasGlobalServiceContext()) { - return nullptr; - } - - return getFTDCController(getGlobalServiceContext()).get(); -} - -std::atomic<bool> localEnabledFlag(FTDCConfig::kEnabledDefault); // NOLINT - -class ExportedFTDCEnabledParameter - : public ExportedServerParameter<bool, ServerParameterType::kStartupAndRuntime> { -public: - ExportedFTDCEnabledParameter() - : ExportedServerParameter<bool, ServerParameterType::kStartupAndRuntime>( - ServerParameterSet::getGlobal(), - "diagnosticDataCollectionEnabled", - &localEnabledFlag) {} - - virtual Status validate(const bool& potentialNewValue) { - auto controller = getGlobalFTDCController(); - if (controller) { - controller->setEnabled(potentialNewValue); - } - - return Status::OK(); - } - -} exportedFTDCEnabledParameter; - -std::atomic<std::int32_t> localPeriodMillis(FTDCConfig::kPeriodMillisDefault); // NOLINT - -class ExportedFTDCPeriodParameter - : public ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime> { -public: - ExportedFTDCPeriodParameter() - : ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime>( - ServerParameterSet::getGlobal(), - "diagnosticDataCollectionPeriodMillis", - &localPeriodMillis) {} - - virtual Status validate(const std::int32_t& potentialNewValue) { - if (potentialNewValue < 100) { - return Status( - ErrorCodes::BadValue, - "diagnosticDataCollectionPeriodMillis must be greater than or equal to 100ms"); - } - - auto controller = getGlobalFTDCController(); - if (controller) { - controller->setPeriod(Milliseconds(potentialNewValue)); - } - - return Status::OK(); - } - -} exportedFTDCPeriodParameter; - -// Scale the values down since are defaults are in bytes, but the user interface is MB -std::atomic<std::int32_t> localMaxDirectorySizeMB( // NOLINT - FTDCConfig::kMaxDirectorySizeBytesDefault / (1024 * 1024)); - -std::atomic<std::int32_t> localMaxFileSizeMB(FTDCConfig::kMaxFileSizeBytesDefault / // NOLINT - (1024 * 1024)); - -class ExportedFTDCDirectorySizeParameter - : public ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime> { -public: - ExportedFTDCDirectorySizeParameter() - : ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime>( - ServerParameterSet::getGlobal(), - "diagnosticDataCollectionDirectorySizeMB", - &localMaxDirectorySizeMB) {} - - virtual Status validate(const std::int32_t& potentialNewValue) { - if (potentialNewValue < 10) { - return Status( - ErrorCodes::BadValue, - "diagnosticDataCollectionDirectorySizeMB must be greater than or equal to 10"); - } - - if (potentialNewValue < localMaxFileSizeMB) { - return Status( - ErrorCodes::BadValue, - str::stream() - << "diagnosticDataCollectionDirectorySizeMB must be greater than or equal to '" - << localMaxFileSizeMB - << "' which is the current value of diagnosticDataCollectionFileSizeMB."); - } - - auto controller = getGlobalFTDCController(); - if (controller) { - controller->setMaxDirectorySizeBytes(potentialNewValue * 1024 * 1024); - } - - return Status::OK(); - } - -} exportedFTDCDirectorySizeParameter; - -class ExportedFTDCFileSizeParameter - : public ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime> { -public: - ExportedFTDCFileSizeParameter() - : ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime>( - ServerParameterSet::getGlobal(), - "diagnosticDataCollectionFileSizeMB", - &localMaxFileSizeMB) {} - - virtual Status validate(const std::int32_t& potentialNewValue) { - if (potentialNewValue < 1) { - return Status(ErrorCodes::BadValue, - "diagnosticDataCollectionFileSizeMB must be greater than or equal to 1"); - } - - if (potentialNewValue > localMaxDirectorySizeMB) { - return Status( - ErrorCodes::BadValue, - str::stream() - << "diagnosticDataCollectionFileSizeMB must be less than or equal to '" - << localMaxDirectorySizeMB - << "' which is the current value of diagnosticDataCollectionDirectorySizeMB."); - } - - auto controller = getGlobalFTDCController(); - if (controller) { - controller->setMaxFileSizeBytes(potentialNewValue * 1024 * 1024); - } - - return Status::OK(); - } - -} exportedFTDCFileSizeParameter; - -std::atomic<std::int32_t> localMaxSamplesPerArchiveMetricChunk( // NOLINT - FTDCConfig::kMaxSamplesPerArchiveMetricChunkDefault); - -class ExportedFTDCArchiveChunkSizeParameter - : public ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime> { -public: - ExportedFTDCArchiveChunkSizeParameter() - : ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime>( - ServerParameterSet::getGlobal(), - "diagnosticDataCollectionSamplesPerChunk", - &localMaxSamplesPerArchiveMetricChunk) {} - - virtual Status validate(const std::int32_t& potentialNewValue) { - if (potentialNewValue < 2) { - return Status( - ErrorCodes::BadValue, - "diagnosticDataCollectionSamplesPerChunk must be greater than or equal to 2"); - } - - auto controller = getGlobalFTDCController(); - if (controller) { - controller->setMaxSamplesPerArchiveMetricChunk(potentialNewValue); - } - - return Status::OK(); - } - -} exportedFTDCArchiveChunkSizeParameter; - -std::atomic<std::int32_t> localMaxSamplesPerInterimMetricChunk( // NOLINT - FTDCConfig::kMaxSamplesPerInterimMetricChunkDefault); - -class ExportedFTDCInterimChunkSizeParameter - : public ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime> { -public: - ExportedFTDCInterimChunkSizeParameter() - : ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime>( - ServerParameterSet::getGlobal(), - "diagnosticDataCollectionSamplesPerInterimUpdate", - &localMaxSamplesPerInterimMetricChunk) {} - - virtual Status validate(const std::int32_t& potentialNewValue) { - if (potentialNewValue < 2) { - return Status(ErrorCodes::BadValue, - "diagnosticDataCollectionSamplesPerInterimUpdate must be greater than or " - "equal to 2"); - } - - auto controller = getGlobalFTDCController(); - if (controller) { - controller->setMaxSamplesPerInterimMetricChunk(potentialNewValue); - } - - return Status::OK(); - } - -} exportedFTDCInterimChunkSizeParameter; - -class FTDCSimpleInternalCommandCollector final : public FTDCCollectorInterface { -public: - FTDCSimpleInternalCommandCollector(StringData command, - StringData name, - StringData ns, - BSONObj cmdObj) - : _name(name.toString()), _ns(ns.toString()), _cmdObj(std::move(cmdObj)) { - _command = Command::findCommand(command); - invariant(_command); - } - - void collect(OperationContext* txn, BSONObjBuilder& builder) override { - std::string errmsg; - - bool ret = _command->run(txn, _ns, _cmdObj, 0, errmsg, builder); - - // Some commands return errmsgs when they return false (collstats) - // Some commands return bson objs when they return false (replGetStatus) - // We append the status as needed to ensure readers of the collected data can check the - // status of any individual command. - _command->appendCommandStatus(builder, ret, errmsg); - } - - std::string name() const override { - return _name; - } - -private: - std::string _name; - std::string _ns; - BSONObj _cmdObj; - - // Not owned - Command* _command; -}; - -} // namespace - -// Register the FTDC system -// Note: This must be run before the server parameters are parsed during startup -// so that the FTDCController is initialized. -// -void startFTDC() { - boost::filesystem::path dir(storageGlobalParams.dbpath); - dir /= "diagnostic.data"; - - - FTDCConfig config; - config.period = Milliseconds(localPeriodMillis.load()); - config.enabled = localEnabledFlag; - config.maxFileSizeBytes = localMaxFileSizeMB * 1024 * 1024; - config.maxDirectorySizeBytes = localMaxDirectorySizeMB * 1024 * 1024; - config.maxSamplesPerArchiveMetricChunk = localMaxSamplesPerArchiveMetricChunk; - config.maxSamplesPerInterimMetricChunk = localMaxSamplesPerInterimMetricChunk; - - auto controller = stdx::make_unique<FTDCController>(dir, config); - - // Install periodic collectors - // These are collected on the period interval in FTDCConfig. - // NOTE: For each command here, there must be an equivalent privilege check in - // GetDiagnosticDataCommand - - // CmdServerStatus - // The "sharding" section is filtered out because at this time it only consists of strings in - // migration status. This section triggers too many schema changes in the serverStatus which - // hurt ftdc compression efficiency, because its output varies depending on the list of active - // migrations. - controller->addPeriodicCollector(stdx::make_unique<FTDCSimpleInternalCommandCollector>( - "serverStatus", - "serverStatus", - "", - BSON("serverStatus" << 1 << "tcMalloc" << true << "sharding" << false))); - +void registerMongoDCollectors(FTDCController* controller) { // These metrics are only collected if replication is enabled if (repl::getGlobalReplicationCoordinator()->getReplicationMode() != repl::ReplicationCoordinator::modeNone) { @@ -335,43 +58,19 @@ void startFTDC() { BSON("collStats" << "oplog.rs"))); } - - // Install System Metric Collector as a periodic collector - installSystemMetricsCollector(controller.get()); - - // Install file rotation collectors - // These are collected on each file rotation. - - // CmdBuildInfo - controller->addOnRotateCollector(stdx::make_unique<FTDCSimpleInternalCommandCollector>( - "buildInfo", "buildInfo", "", BSON("buildInfo" << 1))); - - // CmdGetCmdLineOpts - controller->addOnRotateCollector(stdx::make_unique<FTDCSimpleInternalCommandCollector>( - "getCmdLineOpts", "getCmdLineOpts", "", BSON("getCmdLineOpts" << 1))); - - // HostInfoCmd - controller->addOnRotateCollector(stdx::make_unique<FTDCSimpleInternalCommandCollector>( - "hostInfo", "hostInfo", "", BSON("hostInfo" << 1))); - - // Install the new controller - auto& staticFTDC = getFTDCController(getGlobalServiceContext()); - - staticFTDC = std::move(controller); - - staticFTDC->start(); } -void stopFTDC() { - auto controller = getGlobalFTDCController(); +} // namespace - if (controller) { - controller->stop(); - } +void startMongoDFTDC() { + boost::filesystem::path dir(storageGlobalParams.dbpath); + dir /= kFTDCDefaultDirectory.toString(); + + startFTDC(dir, FTDCStartMode::kStart, registerMongoDCollectors); } -FTDCController* FTDCController::get(ServiceContext* serviceContext) { - return getFTDCController(serviceContext).get(); +void stopMongoDFTDC() { + stopFTDC(); } } // namespace mongo diff --git a/src/mongo/db/ftdc/ftdc_mongod.h b/src/mongo/db/ftdc/ftdc_mongod.h index 1e4f20b8b17..b4409dde902 100644 --- a/src/mongo/db/ftdc/ftdc_mongod.h +++ b/src/mongo/db/ftdc/ftdc_mongod.h @@ -1,30 +1,30 @@ /** -* Copyright (C) 2015 MongoDB Inc. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License, version 3, -* as published by the Free Software Foundation. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -* -* As a special exception, the copyright holders give permission to link the -* code of portions of this program with the OpenSSL library under certain -* conditions as described in each individual source file and distribute -* linked combinations including the program with the OpenSSL library. You -* must comply with the GNU Affero General Public License in all respects -* for all of the code used other than as permitted herein. If you modify -* file(s) with this exception, you may extend this exception to your -* version of the file(s), but you are not obligated to do so. If you do not -* wish to do so, delete this exception statement from your version. If you -* delete this exception statement from all source files in the program, -* then also delete it in the license file. -*/ + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ #pragma once @@ -34,11 +34,11 @@ namespace mongo { * Start Full Time Data Capture * Starts 1 thread. */ -void startFTDC(); +void startMongoDFTDC(); /** * Stop Full Time Data Capture */ -void stopFTDC(); +void stopMongoDFTDC(); } // namespace mongo diff --git a/src/mongo/db/ftdc/ftdc_mongos.cpp b/src/mongo/db/ftdc/ftdc_mongos.cpp new file mode 100644 index 00000000000..bdacaa7b6e1 --- /dev/null +++ b/src/mongo/db/ftdc/ftdc_mongos.cpp @@ -0,0 +1,153 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kFTDC + +#include "mongo/platform/basic.h" + +#include "mongo/db/ftdc/ftdc_mongos.h" + +#include <boost/filesystem.hpp> + +#include "mongo/db/ftdc/controller.h" +#include "mongo/db/ftdc/ftdc_server.h" +#include "mongo/db/server_parameters.h" +#include "mongo/stdx/thread.h" +#include "mongo/util/log.h" + +namespace mongo { + +namespace { + +/** + * Expose diagnosticDataCollectionDirectoryPath set parameter to specify the MongoS FTDC path. + */ +class ExportedFTDCDirectoryPathParameter : public ServerParameter { +public: + ExportedFTDCDirectoryPathParameter() + : ServerParameter(ServerParameterSet::getGlobal(), + "diagnosticDataCollectionDirectoryPath", + true, + true) {} + + + void append(OperationContext* opCtx, BSONObjBuilder& b, const std::string& name) final { + stdx::lock_guard<stdx::mutex> guard(_lock); + b.append(name, _path.generic_string()); + } + + Status set(const BSONElement& newValueElement) { + if (newValueElement.type() != String) { + return Status(ErrorCodes::BadValue, + "diagnosticDataCollectionDirectoryPath only supports type string"); + } + + std::string str = newValueElement.str(); + return setFromString(str); + } + + Status setFromString(const std::string& str) final { + stdx::lock_guard<stdx::mutex> guard(_lock); + + FTDCController* controller = nullptr; + + if (hasGlobalServiceContext()) { + controller = FTDCController::get(getGlobalServiceContext()); + } + + if (controller) { + Status s = controller->setDirectory(str); + if (!s.isOK()) { + return s; + } + } + + _path = str; + + return Status::OK(); + } + + boost::filesystem::path getDirectory() { + stdx::lock_guard<stdx::mutex> guard(_lock); + return _path; + } + + void setDirectory(boost::filesystem::path& path) { + stdx::lock_guard<stdx::mutex> guard(_lock); + _path = path; + } + +private: + // Lock to guard _path + stdx::mutex _lock; + + // Directory location of ftdc files, guarded by _lock + boost::filesystem::path _path; +} exportedFTDCDirectoryPathParameter; + +void registerMongoSCollectors(FTDCController* controller) { + // PoolStats + controller->addPeriodicCollector(stdx::make_unique<FTDCSimpleInternalCommandCollector>( + "connPoolStats", "connPoolStats", "", BSON("connPoolStats" << 1))); +} + +} // namespace + +void startMongoSFTDC() { + // Get the path to use for FTDC: + // 1. Check if the user set one. + // 2. If not, check if the user has a logpath and derive one. + // 3. Otherwise, tell the user FTDC cannot run. + + // Only attempt to enable FTDC if we have a path to log files to. + FTDCStartMode startMode = FTDCStartMode::kStart; + auto directory = exportedFTDCDirectoryPathParameter.getDirectory(); + + if (directory.empty()) { + if (serverGlobalParams.logpath.empty()) { + warning() << "FTDC is disabled because neither '--logpath' nor set parameter " + "'diagnosticDataCollectionDirectoryPath' are specified."; + startMode = FTDCStartMode::kSkipStart; + } else { + directory = FTDCUtil::getMongoSPath(serverGlobalParams.logpath); + + // Update the server parameter with the computed path. + // Note: If the computed FTDC directory conflicts with an existing file, then FTDC will + // warn about the conflict, and not startup. It will not terminate MongoS in this + // situation. + exportedFTDCDirectoryPathParameter.setDirectory(directory); + } + } + + startFTDC(directory, startMode, registerMongoSCollectors); +} + +void stopMongoSFTDC() { + stopFTDC(); +} + +} // namespace mongo diff --git a/src/mongo/db/ftdc/ftdc_mongos.h b/src/mongo/db/ftdc/ftdc_mongos.h new file mode 100644 index 00000000000..4d8ff8fc08b --- /dev/null +++ b/src/mongo/db/ftdc/ftdc_mongos.h @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#pragma once + +namespace mongo { + +/** + * Start Full Time Data Capture + */ +void startMongoSFTDC(); + +/** + * Stop Full Time Data Capture + */ +void stopMongoSFTDC(); + +} // namespace mongo diff --git a/src/mongo/db/ftdc/ftdc_server.cpp b/src/mongo/db/ftdc/ftdc_server.cpp new file mode 100644 index 00000000000..167587a8722 --- /dev/null +++ b/src/mongo/db/ftdc/ftdc_server.cpp @@ -0,0 +1,350 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#include "mongo/platform/basic.h" + +#include "mongo/db/ftdc/ftdc_server.h" + +#include <boost/filesystem.hpp> +#include <fstream> +#include <memory> + +#include "mongo/base/status.h" +#include "mongo/bson/bsonobjbuilder.h" +#include "mongo/db/commands.h" +#include "mongo/db/ftdc/collector.h" +#include "mongo/db/ftdc/config.h" +#include "mongo/db/ftdc/controller.h" +#include "mongo/db/ftdc/ftdc_system_stats.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/server_parameters.h" +#include "mongo/db/service_context.h" +#include "mongo/stdx/memory.h" + +namespace mongo { + +namespace { + +const auto getFTDCController = ServiceContext::declareDecoration<std::unique_ptr<FTDCController>>(); + +FTDCController* getGlobalFTDCController() { + if (!hasGlobalServiceContext()) { + return nullptr; + } + + return getFTDCController(getGlobalServiceContext()).get(); +} + +std::atomic<bool> localEnabledFlag(FTDCConfig::kEnabledDefault); // NOLINT + +class ExportedFTDCEnabledParameter + : public ExportedServerParameter<bool, ServerParameterType::kStartupAndRuntime> { +public: + ExportedFTDCEnabledParameter() + : ExportedServerParameter<bool, ServerParameterType::kStartupAndRuntime>( + ServerParameterSet::getGlobal(), + "diagnosticDataCollectionEnabled", + &localEnabledFlag) {} + + virtual Status validate(const bool& potentialNewValue) { + auto controller = getGlobalFTDCController(); + if (controller) { + return controller->setEnabled(potentialNewValue); + } + + return Status::OK(); + } + +} exportedFTDCEnabledParameter; + +std::atomic<std::int32_t> localPeriodMillis(FTDCConfig::kPeriodMillisDefault); // NOLINT + +class ExportedFTDCPeriodParameter + : public ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime> { +public: + ExportedFTDCPeriodParameter() + : ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime>( + ServerParameterSet::getGlobal(), + "diagnosticDataCollectionPeriodMillis", + &localPeriodMillis) {} + + virtual Status validate(const std::int32_t& potentialNewValue) { + if (potentialNewValue < 100) { + return Status( + ErrorCodes::BadValue, + "diagnosticDataCollectionPeriodMillis must be greater than or equal to 100ms"); + } + + auto controller = getGlobalFTDCController(); + if (controller) { + controller->setPeriod(Milliseconds(potentialNewValue)); + } + + return Status::OK(); + } + +} exportedFTDCPeriodParameter; + +// Scale the values down since are defaults are in bytes, but the user interface is MB +std::atomic<std::int32_t> localMaxDirectorySizeMB(FTDCConfig::kMaxDirectorySizeBytesDefault / + (1024 * 1024)); // NOLINT + +std::atomic<std::int32_t> localMaxFileSizeMB(FTDCConfig::kMaxFileSizeBytesDefault / + (1024 * 1024)); // NOLINT + +class ExportedFTDCDirectorySizeParameter + : public ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime> { +public: + ExportedFTDCDirectorySizeParameter() + : ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime>( + ServerParameterSet::getGlobal(), + "diagnosticDataCollectionDirectorySizeMB", + &localMaxDirectorySizeMB) {} + + virtual Status validate(const std::int32_t& potentialNewValue) { + if (potentialNewValue < 10) { + return Status( + ErrorCodes::BadValue, + "diagnosticDataCollectionDirectorySizeMB must be greater than or equal to 10"); + } + + if (potentialNewValue < localMaxFileSizeMB.load()) { + return Status( + ErrorCodes::BadValue, + str::stream() + << "diagnosticDataCollectionDirectorySizeMB must be greater than or equal to '" + << localMaxFileSizeMB.load() + << "' which is the current value of diagnosticDataCollectionFileSizeMB."); + } + + auto controller = getGlobalFTDCController(); + if (controller) { + controller->setMaxDirectorySizeBytes(potentialNewValue * 1024 * 1024); + } + + return Status::OK(); + } + +} exportedFTDCDirectorySizeParameter; + +class ExportedFTDCFileSizeParameter + : public ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime> { +public: + ExportedFTDCFileSizeParameter() + : ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime>( + ServerParameterSet::getGlobal(), + "diagnosticDataCollectionFileSizeMB", + &localMaxFileSizeMB) {} + + virtual Status validate(const std::int32_t& potentialNewValue) { + if (potentialNewValue < 1) { + return Status(ErrorCodes::BadValue, + "diagnosticDataCollectionFileSizeMB must be greater than or equal to 1"); + } + + if (potentialNewValue > localMaxDirectorySizeMB.load()) { + return Status( + ErrorCodes::BadValue, + str::stream() + << "diagnosticDataCollectionFileSizeMB must be less than or equal to '" + << localMaxDirectorySizeMB.load() + << "' which is the current value of diagnosticDataCollectionDirectorySizeMB."); + } + + auto controller = getGlobalFTDCController(); + if (controller) { + controller->setMaxFileSizeBytes(potentialNewValue * 1024 * 1024); + } + + return Status::OK(); + } + +} exportedFTDCFileSizeParameter; + +std::atomic<std::int32_t> localMaxSamplesPerArchiveMetricChunk( // NOLINT + FTDCConfig::kMaxSamplesPerArchiveMetricChunkDefault); + +class ExportedFTDCArchiveChunkSizeParameter + : public ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime> { +public: + ExportedFTDCArchiveChunkSizeParameter() + : ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime>( + ServerParameterSet::getGlobal(), + "diagnosticDataCollectionSamplesPerChunk", + &localMaxSamplesPerArchiveMetricChunk) {} + + virtual Status validate(const std::int32_t& potentialNewValue) { + if (potentialNewValue < 2) { + return Status( + ErrorCodes::BadValue, + "diagnosticDataCollectionSamplesPerChunk must be greater than or equal to 2"); + } + + auto controller = getGlobalFTDCController(); + if (controller) { + controller->setMaxSamplesPerArchiveMetricChunk(potentialNewValue); + } + + return Status::OK(); + } + +} exportedFTDCArchiveChunkSizeParameter; + +std::atomic<std::int32_t> localMaxSamplesPerInterimMetricChunk( // NOLINT + FTDCConfig::kMaxSamplesPerInterimMetricChunkDefault); + +class ExportedFTDCInterimChunkSizeParameter + : public ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime> { +public: + ExportedFTDCInterimChunkSizeParameter() + : ExportedServerParameter<std::int32_t, ServerParameterType::kStartupAndRuntime>( + ServerParameterSet::getGlobal(), + "diagnosticDataCollectionSamplesPerInterimUpdate", + &localMaxSamplesPerInterimMetricChunk) {} + + virtual Status validate(const std::int32_t& potentialNewValue) { + if (potentialNewValue < 2) { + return Status(ErrorCodes::BadValue, + "diagnosticDataCollectionSamplesPerInterimUpdate must be greater than or " + "equal to 2"); + } + + auto controller = getGlobalFTDCController(); + if (controller) { + controller->setMaxSamplesPerInterimMetricChunk(potentialNewValue); + } + + return Status::OK(); + } + +} exportedFTDCInterimChunkSizeParameter; +} // namespace + +FTDCSimpleInternalCommandCollector::FTDCSimpleInternalCommandCollector(StringData command, + StringData name, + StringData ns, + BSONObj cmdObj) + : _name(name.toString()), _ns(ns.toString()), _cmdObj(std::move(cmdObj)) { + _command = Command::findCommand(command); + invariant(_command); +} + +void FTDCSimpleInternalCommandCollector::collect(OperationContext* opCtx, BSONObjBuilder& builder) { + std::string errmsg; + + bool ret = _command->run(opCtx, _ns, _cmdObj, 0, errmsg, builder); + + // Some commands return errmsgs when they return false (collstats) + // Some commands return bson objs when they return false (replGetStatus) + // We append the status as needed to ensure readers of the collected data can check the + // status of any individual command. + _command->appendCommandStatus(builder, ret, errmsg); +} + +std::string FTDCSimpleInternalCommandCollector::name() const { + return _name; +} + +// Register the FTDC system +// Note: This must be run before the server parameters are parsed during startup +// so that the FTDCController is initialized. +// +void startFTDC(boost::filesystem::path& path, + FTDCStartMode startupMode, + RegisterCollectorsFunction registerCollectors) { + FTDCConfig config; + config.period = Milliseconds(localPeriodMillis.load()); + // Only enable FTDC if our caller says to enable FTDC, MongoS may not have a valid path to write + // files to so update the diagnosticDataCollectionEnabled set parameter to reflect that. + localEnabledFlag.store(startupMode == FTDCStartMode::kStart && localEnabledFlag.load()); + config.enabled = localEnabledFlag.load(); + config.maxFileSizeBytes = localMaxFileSizeMB.load() * 1024 * 1024; + config.maxDirectorySizeBytes = localMaxDirectorySizeMB.load() * 1024 * 1024; + config.maxSamplesPerArchiveMetricChunk = localMaxSamplesPerArchiveMetricChunk.load(); + config.maxSamplesPerInterimMetricChunk = localMaxSamplesPerInterimMetricChunk.load(); + + auto controller = stdx::make_unique<FTDCController>(path, config); + + // Install periodic collectors + // These are collected on the period interval in FTDCConfig. + // NOTE: For each command here, there must be an equivalent privilege check in + // GetDiagnosticDataCommand + + // CmdServerStatus + // The "sharding" section is filtered out because at this time it only consists of strings in + // migration status. This section triggers too many schema changes in the serverStatus which + // hurt ftdc compression efficiency, because its output varies depending on the list of active + // migrations. + // TODO: do we need to enable "sharding" on MongoS? + controller->addPeriodicCollector(stdx::make_unique<FTDCSimpleInternalCommandCollector>( + "serverStatus", + "serverStatus", + "", + BSON("serverStatus" << 1 << "tcMalloc" << true << "sharding" << false))); + + registerCollectors(controller.get()); + + // Install System Metric Collector as a periodic collector + installSystemMetricsCollector(controller.get()); + + // Install file rotation collectors + // These are collected on each file rotation. + + // CmdBuildInfo + controller->addOnRotateCollector(stdx::make_unique<FTDCSimpleInternalCommandCollector>( + "buildInfo", "buildInfo", "", BSON("buildInfo" << 1))); + + // CmdGetCmdLineOpts + controller->addOnRotateCollector(stdx::make_unique<FTDCSimpleInternalCommandCollector>( + "getCmdLineOpts", "getCmdLineOpts", "", BSON("getCmdLineOpts" << 1))); + + // HostInfoCmd + controller->addOnRotateCollector(stdx::make_unique<FTDCSimpleInternalCommandCollector>( + "hostInfo", "hostInfo", "", BSON("hostInfo" << 1))); + + // Install the new controller + auto& staticFTDC = getFTDCController(getGlobalServiceContext()); + + staticFTDC = std::move(controller); + + staticFTDC->start(); +} + +void stopFTDC() { + auto controller = getGlobalFTDCController(); + + if (controller) { + controller->stop(); + } +} + +FTDCController* FTDCController::get(ServiceContext* serviceContext) { + return getFTDCController(serviceContext).get(); +} + +} // namespace mongo diff --git a/src/mongo/db/ftdc/ftdc_server.h b/src/mongo/db/ftdc/ftdc_server.h new file mode 100644 index 00000000000..4b4583ae153 --- /dev/null +++ b/src/mongo/db/ftdc/ftdc_server.h @@ -0,0 +1,103 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#pragma once + +#include <string> + +#include "mongo/bson/bsonobjbuilder.h" +#include "mongo/db/commands.h" +#include "mongo/db/ftdc/collector.h" +#include "mongo/db/ftdc/controller.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/operation_context.h" +#include "mongo/stdx/functional.h" + +namespace mongo { + +/** + * Function that allows FTDC server components to register their own collectors as needed. + */ +using RegisterCollectorsFunction = stdx::function<void(FTDCController*)>; + +/** + * An enum that decides whether FTDC will startup as part of startup or if its deferred to later. + */ +enum class FTDCStartMode { + + /** + * Skip starting FTDC since it missing a file storage location. + */ + kSkipStart, + + /** + * Start FTDC because it has a path to store files. + */ + kStart, +}; + +/** + * Start Full Time Data Capture + * Starts 1 thread. + * + * See MongoD and MongoS specific functions. + */ +void startFTDC(boost::filesystem::path& path, + FTDCStartMode startupMode, + RegisterCollectorsFunction registerCollectors); + +/** + * Stop Full Time Data Capture + * + * See MongoD and MongoS specific functions. + */ +void stopFTDC(); + +/** + * A simple FTDC Collector that runs Commands. + */ +class FTDCSimpleInternalCommandCollector final : public FTDCCollectorInterface { +public: + FTDCSimpleInternalCommandCollector(StringData command, + StringData name, + StringData ns, + BSONObj cmdObj); + + void collect(OperationContext* opCtx, BSONObjBuilder& builder) override; + std::string name() const override; + +private: + std::string _name; + std::string _ns; + BSONObj _cmdObj; + + // Not owned + Command* _command; +}; + +} // namespace mongo diff --git a/src/mongo/db/ftdc/ftdc_system_stats.h b/src/mongo/db/ftdc/ftdc_system_stats.h index 20d21ef4f39..97bc0a67cf5 100644 --- a/src/mongo/db/ftdc/ftdc_system_stats.h +++ b/src/mongo/db/ftdc/ftdc_system_stats.h @@ -25,6 +25,7 @@ * delete this exception statement from all source files in the program, * then also delete it in the license file. */ +#pragma once #include <string> diff --git a/src/mongo/db/ftdc/util.cpp b/src/mongo/db/ftdc/util.cpp index d56eb8ca380..243ba90b666 100644 --- a/src/mongo/db/ftdc/util.cpp +++ b/src/mongo/db/ftdc/util.cpp @@ -103,6 +103,19 @@ Date_t roundTime(Date_t now, Milliseconds period) { return Date_t::fromMillisSinceEpoch(next_time); } +boost::filesystem::path getMongoSPath(const boost::filesystem::path& logFile) { + auto base = logFile; + + // Keep stripping file extensions until we are only left with the file name + while (base.has_extension()) { + auto full_path = base.generic_string(); + base = full_path.substr(0, full_path.size() - base.extension().size()); + } + + base += "." + kFTDCDefaultDirectory.toString(); + return base; +} + } // namespace FTDCUtil diff --git a/src/mongo/db/ftdc/util.h b/src/mongo/db/ftdc/util.h index 0cb4d19ce7f..4816c534f96 100644 --- a/src/mongo/db/ftdc/util.h +++ b/src/mongo/db/ftdc/util.h @@ -190,6 +190,11 @@ boost::filesystem::path getInterimTempFile(const boost::filesystem::path& file); */ Date_t roundTime(Date_t now, Milliseconds period); +/** + * Get the storage path for MongoS from the log file path. + */ +boost::filesystem::path getMongoSPath(const boost::filesystem::path& logFile); + } // namespace FTDCUtil } // namespace mongo diff --git a/src/mongo/db/ftdc/util_test.cpp b/src/mongo/db/ftdc/util_test.cpp index aa99006c73a..0adf0f73c15 100644 --- a/src/mongo/db/ftdc/util_test.cpp +++ b/src/mongo/db/ftdc/util_test.cpp @@ -46,4 +46,25 @@ TEST(FTDCUtilTest, TestRoundTime) { checkTime(14, 13, 7); } +// Validate the MongoS FTDC path is computed correctly from a log file path. +TEST(FTDCUtilTest, TestMongoSPath) { + + std::vector<std::pair<std::string, std::string>> testCases = { + {"/var/log/mongos.log", "/var/log/mongos.diagnostic.data"}, + {"/var/log/mongos.foo.log", "/var/log/mongos.diagnostic.data"}, + {"/var/log/log_file", "/var/log/log_file.diagnostic.data"}, + {"./mongos.log", "./mongos.diagnostic.data"}, + {"../mongos.log", "../mongos.diagnostic.data"}, + {"c:\\var\\log\\mongos.log", "c:\\var\\log\\mongos.diagnostic.data"}, + {"c:\\var\\log\\mongos.foo.log", "c:\\var\\log\\mongos.diagnostic.data"}, + {"c:\\var\\log\\log_file", "c:\\var\\log\\log_file.diagnostic.data"}, + {"/var/some.log/mongos.log", "/var/some.log/mongos.diagnostic.data"}, + {"/var/some.log/log_file", "/var/some.log/log_file.diagnostic.data"}, + }; + + for (const auto& p : testCases) { + ASSERT_EQUALS(FTDCUtil::getMongoSPath(p.first), p.second); + } +} + } // namespace mongo |
