diff options
author | Sara Golemon <sara.golemon@mongodb.com> | 2018-05-01 13:42:15 -0400 |
---|---|---|
committer | Sara Golemon <sara.golemon@mongodb.com> | 2018-05-01 14:43:47 -0400 |
commit | 97245f7c13ee8d18e3d82fc87dd44b9fd72b4da3 (patch) | |
tree | d512f78f20b7fd1acb43ecbd09b28883be8fc963 | |
parent | 52c1fe02a0cd0f64a4d97f7c1e17792b38c67ca4 (diff) | |
download | mongo-97245f7c13ee8d18e3d82fc87dd44b9fd72b4da3.tar.gz |
SERVER-34229 Add free monitoring to serverStatus
-rw-r--r-- | jstests/free_mon/free_mon_http_down.js | 4 | ||||
-rw-r--r-- | jstests/free_mon/free_mon_server_status.js | 48 | ||||
-rw-r--r-- | src/mongo/db/free_mon/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/free_mon/free_mon_controller.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/free_mon/free_mon_controller.h | 7 | ||||
-rw-r--r-- | src/mongo/db/free_mon/free_mon_processor.cpp | 173 | ||||
-rw-r--r-- | src/mongo/db/free_mon/free_mon_processor.h | 37 | ||||
-rw-r--r-- | src/mongo/db/free_mon/free_mon_status.cpp | 64 |
8 files changed, 268 insertions, 74 deletions
diff --git a/jstests/free_mon/free_mon_http_down.js b/jstests/free_mon/free_mon_http_down.js index aff229614c4..019b50f23eb 100644 --- a/jstests/free_mon/free_mon_http_down.js +++ b/jstests/free_mon/free_mon_http_down.js @@ -17,9 +17,13 @@ load("jstests/free_mon/libs/free_mon.js"); const conn = MongoRunner.runMongod(options); assert.neq(null, conn, 'mongod was unable to start up'); + const admin = conn.getDB('admin'); mock_web.waitRegisters(3); + const freeMonStats = assert.commandWorked(admin.runCommand({serverStatus: 1})).freeMonitoring; + assert.gte(freeMonStats.registerErrors, 3); + MongoRunner.stopMongod(conn); mock_web.stop(); diff --git a/jstests/free_mon/free_mon_server_status.js b/jstests/free_mon/free_mon_server_status.js new file mode 100644 index 00000000000..5a7fc991831 --- /dev/null +++ b/jstests/free_mon/free_mon_server_status.js @@ -0,0 +1,48 @@ +// Validate serverStatus output. +// +load("jstests/free_mon/libs/free_mon.js"); + +(function() { + 'use strict'; + + const mock_web = new FreeMonWebServer(); + mock_web.start(); + + const mongod = MongoRunner.runMongod({ + setParameter: "cloudFreeMonitoringEndpointURL=" + mock_web.getURL(), + }); + assert.neq(mongod, null, 'mongod not running'); + const admin = mongod.getDB('admin'); + + const kRetryIntervalSecs = 1; + function freeMonStats() { + return assert.commandWorked(admin.runCommand({serverStatus: 1})).freeMonitoring; + } + + // Initial state. + assert.eq(freeMonStats().state, 'undecided'); + + assert.commandWorked(admin.runCommand({setFreeMonitoring: 1, action: 'enable'})); + WaitForRegistration(mongod); + + const enabled = freeMonStats(); + assert.eq(enabled.state, 'enabled'); + assert.eq(enabled.retryIntervalSecs, kRetryIntervalSecs); + assert.eq(enabled.registerErrors, 0); + assert.eq(enabled.metricsErrors, 0); + + // Explicitly disabled. + assert.commandWorked(admin.runCommand({setFreeMonitoring: 1, action: 'disable'})); + sleep(2); // Give the async command time to run. + + const disabled = freeMonStats(); + assert.eq(disabled.state, 'disabled'); + assert.eq(disabled.retryIntervalSecs, kRetryIntervalSecs); + assert.eq(disabled.registerErrors, 0); + assert.eq(disabled.metricsErrors, 0); + + // Enabled. + // Cleanup. + MongoRunner.stopMongod(mongod); + mock_web.stop(); +})(); diff --git a/src/mongo/db/free_mon/SConscript b/src/mongo/db/free_mon/SConscript index 72d656dce15..ac990e7e8aa 100644 --- a/src/mongo/db/free_mon/SConscript +++ b/src/mongo/db/free_mon/SConscript @@ -36,10 +36,12 @@ if free_monitoring == "on": 'free_mon_commands.cpp', 'free_mon_mongod.cpp', 'free_mon_options.cpp', + 'free_mon_status.cpp', 'http_client_curl.cpp' if not env.TargetOSIs('windows') else 'http_client_winhttp.cpp', ], LIBDEPS=[ 'free_mon', + '$BUILD_DIR/mongo/db/commands/server_status', '$BUILD_DIR/mongo/db/ftdc/ftdc_server', '$BUILD_DIR/mongo/util/options_parser/options_parser', ], diff --git a/src/mongo/db/free_mon/free_mon_controller.cpp b/src/mongo/db/free_mon/free_mon_controller.cpp index 21200304349..289e8c69d1a 100644 --- a/src/mongo/db/free_mon/free_mon_controller.cpp +++ b/src/mongo/db/free_mon/free_mon_controller.cpp @@ -196,4 +196,11 @@ void FreeMonController::turnCrankForTest(size_t countMessagesToIgnore) { _processor->turnCrankForTest(countMessagesToIgnore); } +void FreeMonController::getServerStatus(OperationContext* opCtx, BSONObjBuilder* status) { + if (!_processor) { + status->append("state", "disabled"); + } + _processor->getServerStatus(opCtx, status); +} + } // namespace mongo diff --git a/src/mongo/db/free_mon/free_mon_controller.h b/src/mongo/db/free_mon/free_mon_controller.h index e78dea57d34..3f1807b7e6f 100644 --- a/src/mongo/db/free_mon/free_mon_controller.h +++ b/src/mongo/db/free_mon/free_mon_controller.h @@ -35,6 +35,7 @@ #include <vector> #include "mongo/base/status.h" +#include "mongo/db/client.h" #include "mongo/db/free_mon/free_mon_message.h" #include "mongo/db/free_mon/free_mon_network.h" #include "mongo/db/free_mon/free_mon_processor.h" @@ -116,8 +117,10 @@ public: */ boost::optional<Status> unregisterServerCommand(Milliseconds timeout); - // TODO - add these methods - // void getServerStatus(BSONObjBuilder* builder); + /** + * Populates an info blob for use by {serverStatus: 1} + */ + void getServerStatus(OperationContext* opCtx, BSONObjBuilder* status); /** * Notify on upsert. diff --git a/src/mongo/db/free_mon/free_mon_processor.cpp b/src/mongo/db/free_mon/free_mon_processor.cpp index 04620d1cf23..9a6ca23513a 100644 --- a/src/mongo/db/free_mon/free_mon_processor.cpp +++ b/src/mongo/db/free_mon/free_mon_processor.cpp @@ -126,12 +126,12 @@ FreeMonProcessor::FreeMonProcessor(FreeMonCollectorCollection& registration, _metrics(metrics), _network(network), _random(Date_t::now().asInt64()), - _registrationRetry(_random), - _metricsRetry(_random), + _registrationRetry(RegistrationRetryCounter(_random)), + _metricsRetry(MetricsRetryCounter(_random)), _metricsGatherInterval(kDefaultMetricsGatherInterval), _queue(useCrankForTest) { - _registrationRetry.reset(); - _metricsRetry.reset(); + _registrationRetry->reset(); + _metricsRetry->reset(); } void FreeMonProcessor::enqueue(std::shared_ptr<FreeMonMessage> msg) { @@ -262,11 +262,8 @@ void FreeMonProcessor::run() { } } -void FreeMonProcessor::readState(Client* client) { - - auto optCtx = client->makeOperationContext(); - - auto state = FreeMonStorage::read(optCtx.get()); +void FreeMonProcessor::readState(OperationContext* opCtx) { + auto state = FreeMonStorage::read(opCtx); _lastReadState = state; @@ -276,15 +273,21 @@ void FreeMonProcessor::readState(Client* client) { _state = state.get(); } else if (!state.is_initialized()) { // Default the state - _state.setVersion(kProtocolVersion); - _state.setState(StorageStateEnum::disabled); - _state.setRegistrationId(""); - _state.setInformationalURL(""); - _state.setMessage(""); - _state.setUserReminder(""); + auto state = _state.synchronize(); + state->setVersion(kProtocolVersion); + state->setState(StorageStateEnum::disabled); + state->setRegistrationId(""); + state->setInformationalURL(""); + state->setMessage(""); + state->setUserReminder(""); } } +void FreeMonProcessor::readState(Client* client) { + auto opCtx = client->makeOperationContext(); + readState(opCtx.get()); +} + void FreeMonProcessor::writeState(Client* client) { // Do a compare and swap @@ -292,7 +295,7 @@ void FreeMonProcessor::writeState(Client* client) { // If the local document is different, then oh-well we do nothing, and wait until the next round // Has our in-memory state changed, if so consider writing - if (_lastReadState != _state) { + if (_lastReadState != _state.get()) { // The read and write are bound the same operation context { @@ -302,9 +305,9 @@ void FreeMonProcessor::writeState(Client* client) { // If our in-memory copy matches the last read, then write it to disk if (state == _lastReadState) { - FreeMonStorage::replace(optCtx.get(), _state); + FreeMonStorage::replace(optCtx.get(), _state.get()); - _lastReadState = _state; + _lastReadState = boost::make_optional(_state.get()); } } } @@ -401,8 +404,9 @@ void FreeMonProcessor::doCommandRegister(Client* client, FreeMonRegistrationRequest req; - if (!_state.getRegistrationId().empty()) { - req.setId(_state.getRegistrationId()); + auto regid = _state->getRegistrationId(); + if (!regid.empty()) { + req.setId(regid); } req.setVersion(kProtocolVersion); @@ -422,7 +426,7 @@ void FreeMonProcessor::doCommandRegister(Client* client, req.setPayload(std::get<0>(collect)); // Record that the registration is pending - _state.setState(StorageStateEnum::pending); + _state->setState(StorageStateEnum::pending); writeState(client); @@ -590,7 +594,7 @@ void FreeMonProcessor::doAsyncRegisterComplete( // Our request is no longer in-progress so delete it _futureRegistrationResponse.reset(); - if (_state.getState() != StorageStateEnum::pending) { + if (_state->getState() != StorageStateEnum::pending) { notifyPendingRegisters(Status(ErrorCodes::BadValue, "Registration was canceled")); return; @@ -603,7 +607,7 @@ void FreeMonProcessor::doAsyncRegisterComplete( warning() << "Free Monitoring registration halted due to " << s; // Disable on any error - _state.setState(StorageStateEnum::disabled); + _state->setState(StorageStateEnum::disabled); // Persist state writeState(client); @@ -615,26 +619,29 @@ void FreeMonProcessor::doAsyncRegisterComplete( } // Update in-memory state - _registrationRetry.setMin(Seconds(resp.getReportingInterval())); + _registrationRetry->setMin(Seconds(resp.getReportingInterval())); - _state.setRegistrationId(resp.getId()); + { + auto state = _state.synchronize(); + state->setRegistrationId(resp.getId()); - if (resp.getUserReminder().is_initialized()) { - _state.setUserReminder(resp.getUserReminder().get()); - } else { - _state.setUserReminder(""); - } + if (resp.getUserReminder().is_initialized()) { + state->setUserReminder(resp.getUserReminder().get()); + } else { + state->setUserReminder(""); + } - _state.setMessage(resp.getMessage()); - _state.setInformationalURL(resp.getInformationalURL()); + state->setMessage(resp.getMessage()); + state->setInformationalURL(resp.getInformationalURL()); - _state.setState(StorageStateEnum::enabled); + state->setState(StorageStateEnum::enabled); + } // Persist state writeState(client); // Reset retry counter - _registrationRetry.reset(); + _registrationRetry->reset(); // Notify waiters notifyPendingRegisters(Status::OK()); @@ -643,7 +650,7 @@ void FreeMonProcessor::doAsyncRegisterComplete( // Enqueue next metrics upload enqueue(FreeMonMessage::createWithDeadline(FreeMonMessageType::MetricsSend, - _registrationRetry.getNextDeadline(client))); + _registrationRetry->getNextDeadline(client))); } void FreeMonProcessor::doAsyncRegisterFail( @@ -652,32 +659,32 @@ void FreeMonProcessor::doAsyncRegisterFail( // Our request is no longer in-progress so delete it _futureRegistrationResponse.reset(); - if (_state.getState() != StorageStateEnum::pending) { + if (_state->getState() != StorageStateEnum::pending) { notifyPendingRegisters(Status(ErrorCodes::BadValue, "Registration was canceled")); return; } - if (!_registrationRetry.incrementError()) { + if (!_registrationRetry->incrementError()) { // We have exceeded our retry warning() << "Free Monitoring is abandoning registration after excess retries"; return; } LOG(1) << "Free Monitoring Registration Failed with status '" << msg->getPayload() - << "', retrying in " << _registrationRetry.getNextDuration(); + << "', retrying in " << _registrationRetry->getNextDuration(); // Enqueue a register retry enqueue(FreeMonRegisterCommandMessage::createWithDeadline( - _tags, _registrationRetry.getNextDeadline(client))); + _tags, _registrationRetry->getNextDeadline(client))); } void FreeMonProcessor::doCommandUnregister( Client* client, FreeMonWaitableMessageWithPayload<FreeMonMessageType::UnregisterCommand>* msg) { // Treat this request as idempotent - if (_state.getState() != StorageStateEnum::disabled) { + if (_state->getState() != StorageStateEnum::disabled) { - _state.setState(StorageStateEnum::disabled); + _state->setState(StorageStateEnum::disabled); writeState(client); @@ -726,24 +733,26 @@ std::string compressMetrics(MetricsBuffer& buffer) { void FreeMonProcessor::doMetricsSend(Client* client) { readState(client); - if (_state.getState() != StorageStateEnum::enabled) { + if (_state->getState() != StorageStateEnum::enabled) { // If we are recently disabled, then stop sending metrics return; } // Build outbound request FreeMonMetricsRequest req; - invariant(!_state.getRegistrationId().empty()); + invariant(!_state->getRegistrationId().empty()); req.setVersion(kProtocolVersion); req.setEncoding(MetricsEncodingEnum::snappy); - req.setId(_state.getRegistrationId()); + req.setId(_state->getRegistrationId()); // Get the buffered metrics auto metrics = compressMetrics(_metricsBuffer); req.setMetrics(ConstDataRange(metrics.data(), metrics.size())); + _lastMetricsSend = Date_t::now(); + // Send the async request doAsyncCallback<FreeMonMetricsResponse>( this, @@ -770,7 +779,7 @@ void FreeMonProcessor::doAsyncMetricsComplete( warning() << "Free Monitoring metrics uploading halted due to " << s; // Disable free monitoring on validation errors - _state.setState(StorageStateEnum::disabled); + _state->setState(StorageStateEnum::disabled); writeState(client); // If validation fails, we do not retry @@ -790,49 +799,81 @@ void FreeMonProcessor::doAsyncMetricsComplete( _metricsBuffer.reset(); - if (resp.getId().is_initialized()) { - _state.setRegistrationId(resp.getId().get()); - } + { + auto state = _state.synchronize(); - if (resp.getUserReminder().is_initialized()) { - _state.setUserReminder(resp.getUserReminder().get()); - } + if (resp.getId().is_initialized()) { + state->setRegistrationId(resp.getId().get()); + } - if (resp.getInformationalURL().is_initialized()) { - _state.setInformationalURL(resp.getInformationalURL().get()); - } + if (resp.getUserReminder().is_initialized()) { + state->setUserReminder(resp.getUserReminder().get()); + } + + if (resp.getInformationalURL().is_initialized()) { + state->setInformationalURL(resp.getInformationalURL().get()); + } - if (resp.getMessage().is_initialized()) { - _state.setMessage(resp.getMessage().get()); + if (resp.getMessage().is_initialized()) { + state->setMessage(resp.getMessage().get()); + } } // Persist state writeState(client); // Reset retry counter - _metricsRetry.setMin(Seconds(resp.getReportingInterval())); - _metricsRetry.reset(); + _metricsRetry->setMin(Seconds(resp.getReportingInterval())); + _metricsRetry->reset(); // Enqueue next metrics upload enqueue(FreeMonMessage::createWithDeadline(FreeMonMessageType::MetricsSend, - _registrationRetry.getNextDeadline(client))); + _registrationRetry->getNextDeadline(client))); } void FreeMonProcessor::doAsyncMetricsFail( Client* client, const FreeMonMessageWithPayload<FreeMonMessageType::AsyncMetricsFail>* msg) { - if (!_metricsRetry.incrementError()) { + if (!_metricsRetry->incrementError()) { // We have exceeded our retry warning() << "Free Monitoring is abandoning metrics upload after excess retries"; return; } LOG(1) << "Free Monitoring Metrics upload failed with status " << msg->getPayload() - << ", retrying in " << _metricsRetry.getNextDuration(); + << ", retrying in " << _metricsRetry->getNextDuration(); // Enqueue next metrics upload enqueue(FreeMonMessage::createWithDeadline(FreeMonMessageType::MetricsSend, - _metricsRetry.getNextDeadline(client))); + _metricsRetry->getNextDeadline(client))); +} + +void FreeMonProcessor::getServerStatus(OperationContext* opCtx, BSONObjBuilder* status) { + try { + readState(opCtx); + } catch (const DBException&) { + // readState() may throw if invoked during shutdown (as in ReplSetTest cleanup). + // If we have a lastReadState, go ahead and use that, otherwise just give up already. + if (!_lastReadState.get()) { + return; + } + } + + if (!_lastReadState.get()) { + // _state gets initialized by readState() regardless, + // use _lastReadState to differential "undecided" from default. + status->append("state", "undecided"); + return; + } + + status->append("state", StorageState_serializer(_state->getState())); + status->append("retryIntervalSecs", durationCount<Seconds>(_metricsRetry->getNextDuration())); + auto lastMetricsSend = _lastMetricsSend.get(); + if (lastMetricsSend) { + status->append("lastRunTime", lastMetricsSend->toString()); + } + status->append("registerErrors", static_cast<long long>(_registrationRetry->getCount())); + status->append("metricsErrors", static_cast<long long>(_metricsRetry->getCount())); } void FreeMonProcessor::doOnTransitionToPrimary(Client* client) { @@ -871,7 +912,7 @@ void FreeMonProcessor::doNotifyOnUpsert( << newState.getVersion(), newState.getVersion() == kStorageVersion); - processInMemoryStateChange(_state, newState); + processInMemoryStateChange(_state.get(), newState); // Note: enabled -> disabled is handled implicitly by register and send metrics checks // after _state is updated below @@ -896,7 +937,7 @@ void FreeMonProcessor::doNotifyOnDelete(Client* client) { // the same and stop free monitoring. We continue collecting though. // So we mark the internal state as disabled which stop registration and metrics send - _state.setState(StorageStateEnum::disabled); + _state->setState(StorageStateEnum::disabled); } void FreeMonProcessor::doNotifyOnRollback(Client* client) { @@ -904,12 +945,12 @@ void FreeMonProcessor::doNotifyOnRollback(Client* client) { // We should re-read the disk state and proceed. // copy the in-memory state - auto originalState = _state; + auto originalState = _state.get(); // Re-read state from disk readState(client); - auto& newState = _state; + auto newState = _state.get(); if (newState != originalState) { processInMemoryStateChange(originalState, newState); diff --git a/src/mongo/db/free_mon/free_mon_processor.h b/src/mongo/db/free_mon/free_mon_processor.h index 64734d3a981..846c7db1d55 100644 --- a/src/mongo/db/free_mon/free_mon_processor.h +++ b/src/mongo/db/free_mon/free_mon_processor.h @@ -28,6 +28,7 @@ #pragma once #include <boost/optional.hpp> +#include <boost/thread/synchronized_value.hpp> #include <cstdint> #include <deque> #include <memory> @@ -84,7 +85,7 @@ public: /** * Get the next retry duration. */ - Seconds getNextDuration() { + Seconds getNextDuration() const { dassert(_current != Seconds(0)); return _current; } @@ -92,7 +93,7 @@ public: /** * Get the next retry deadline */ - Date_t getNextDeadline(Client* client) { + Date_t getNextDeadline(Client* client) const { return client->getServiceContext()->getPreciseClockSource()->now() + _current; } @@ -118,6 +119,10 @@ public: bool incrementError() final; + size_t getCount() const { + return _retryCount; + } + private: // Random number generator for jitter PseudoRandom& _random; @@ -154,6 +159,10 @@ public: bool incrementError() final; + size_t getCount() const { + return _retryCount; + } + private: // Random number generator for jitter PseudoRandom& _random; @@ -308,6 +317,11 @@ private: /** * Read the state from the database. */ + void readState(OperationContext* opCtx); + + /** + * Create a short-lived opCtx and read the state from the database. + */ void readState(Client* client); /** @@ -403,6 +417,14 @@ private: void processInMemoryStateChange(const FreeMonStorageState& originalState, const FreeMonStorageState& newState); +protected: + friend class FreeMonController; + + /** + * Server status section with state for active processor. + */ + void getServerStatus(OperationContext* opCtx, BSONObjBuilder* status); + private: // Collection of collectors to send on registration FreeMonCollectorCollection& _registration; @@ -417,10 +439,10 @@ private: PseudoRandom _random; // Registration Retry logic - RegistrationRetryCounter _registrationRetry; + boost::synchronized_value<RegistrationRetryCounter> _registrationRetry; // Metrics Retry logic - MetricsRetryCounter _metricsRetry; + boost::synchronized_value<MetricsRetryCounter> _metricsRetry; // Interval for gathering metrics Seconds _metricsGatherInterval; @@ -428,6 +450,9 @@ private: // Buffer of metrics to upload MetricsBuffer _metricsBuffer; + // When did we last send a metrics batch? + boost::synchronized_value<boost::optional<Date_t>> _lastMetricsSend; + // List of tags from server configuration registration std::vector<std::string> _tags; @@ -438,13 +463,13 @@ private: std::vector<std::shared_ptr<FreeMonMessage>> _pendingRegisters; // Last read storage state - boost::optional<FreeMonStorageState> _lastReadState; + boost::synchronized_value<boost::optional<FreeMonStorageState>> _lastReadState; // When we change to primary, do we register? bool _registerOnTransitionToPrimary{false}; // Pending update to disk - FreeMonStorageState _state; + boost::synchronized_value<FreeMonStorageState> _state; // Countdown launch to support manual cranking FreeMonCountdownLatch _countdown; diff --git a/src/mongo/db/free_mon/free_mon_status.cpp b/src/mongo/db/free_mon/free_mon_status.cpp new file mode 100644 index 00000000000..73ff7165052 --- /dev/null +++ b/src/mongo/db/free_mon/free_mon_status.cpp @@ -0,0 +1,64 @@ +/** + * Copyright (C) 2018 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/commands/server_status.h" +#include "mongo/db/free_mon/free_mon_controller.h" + +namespace mongo { +namespace { + +class FreeMonServerStatus : public ServerStatusSection { +public: + FreeMonServerStatus() : ServerStatusSection("freeMonitoring") {} + + bool includeByDefault() const final { + return true; + } + + void addRequiredPrivileges(std::vector<Privilege>* out) final { + out->push_back(Privilege(ResourcePattern::forClusterResource(), + ActionType::checkFreeMonitoringStatus)); + } + + BSONObj generateSection(OperationContext* opCtx, const BSONElement& configElement) const final { + auto* controller = FreeMonController::get(opCtx->getServiceContext()); + if (!controller) { + return BSON("state" + << "disabled"); + } + + BSONObjBuilder builder; + controller->getServerStatus(opCtx, &builder); + return builder.obj(); + } +} freeMonServerStatus; + +} // namespace +} // namespace mongo |