summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jstests/core/apitest_db_profile_level.js46
-rw-r--r--jstests/libs/log.js37
-rw-r--r--src/mongo/db/commands/profile_common.cpp27
3 files changed, 99 insertions, 11 deletions
diff --git a/jstests/core/apitest_db_profile_level.js b/jstests/core/apitest_db_profile_level.js
index 2172b4ed1cb..20f6ff55df9 100644
--- a/jstests/core/apitest_db_profile_level.js
+++ b/jstests/core/apitest_db_profile_level.js
@@ -1,11 +1,13 @@
/**
* Tests for setting of profile levels
- * @tags: [does_not_support_stepdowns, requires_profiling]
+ * @tags: [does_not_support_stepdowns, requires_profiling, requires_fcv_40]
*/
(function() {
'use strict';
+ load("jstests/libs/log.js"); // For findMatchingLogLine, findMatchingLogLines.
+
/*
* be sure the public collection API is complete
*/
@@ -16,25 +18,51 @@
// other tests that modify profiler level, when run in parallel.
var profileLevelDB = db.getSiblingDB("apitest_db_profile_level");
+ // Checks for the log that was expected to be created when profile level changed.
+ function profilerChangeWasLogged({from, to} = {}) {
+ const globalLog = assert.commandWorked(profileLevelDB.adminCommand({getLog: 'global'}));
+
+ const fieldMatcher = {msg: "Profiler settings changed"};
+ if (from && to) {
+ const lines = [...findMatchingLogLines(globalLog.log, fieldMatcher)];
+ return lines.find(line => line.match(new RegExp(/from:\{ /.source + from.source)) &&
+ line.match(new RegExp(/to:\{ /.source + to.source)));
+ } else {
+ return findMatchingLogLine(globalLog.log, fieldMatcher);
+ }
+ }
+
+ profileLevelDB.getProfilingLevel();
+ assert(!profilerChangeWasLogged({from: /level: 0/, to: /level: -1/}),
+ "Didn't expect anything to be logged");
+
+ assert.throws(() => {
+ profileLevelDB.setProfilingLevel(-1);
+ });
+
profileLevelDB.setProfilingLevel(0);
assert(profileLevelDB.getProfilingLevel() == 0, "prof level 0");
+ assert(profilerChangeWasLogged({from: /level: 0/, to: /level: 0/}),
+ "Didn't find expected log line");
profileLevelDB.setProfilingLevel(1);
assert(profileLevelDB.getProfilingLevel() == 1, "p1");
+ assert(profilerChangeWasLogged({from: /level: 0/, to: /level: 1/}),
+ "Didn't find expected log line");
profileLevelDB.setProfilingLevel(2);
assert(profileLevelDB.getProfilingLevel() == 2, "p2");
+ assert(profilerChangeWasLogged({from: /level: 1/, to: /level: 2/}),
+ "Didn't find expected log line");
profileLevelDB.setProfilingLevel(0);
assert(profileLevelDB.getProfilingLevel() == 0, "prof level 0");
+ assert(profilerChangeWasLogged({from: /level: 2/, to: /level: 0/}),
+ "Didn't find expected log line");
- var asserted = false;
- try {
+ assert.throws(() => {
profileLevelDB.setProfilingLevel(10);
- assert(false);
- } catch (e) {
- asserted = true;
- assert(e.dbSetProfilingException);
- }
- assert(asserted, "should have asserted");
+ });
+ // Check that didn't log an invalid profile level change.
+ assert(!profilerChangeWasLogged({from: /level: 0/, to: /level: 10/}), "Didn't expect log line");
})();
diff --git a/jstests/libs/log.js b/jstests/libs/log.js
new file mode 100644
index 00000000000..299a9ab8e0c
--- /dev/null
+++ b/jstests/libs/log.js
@@ -0,0 +1,37 @@
+// Yields every logline that contains the specified fields. The regex escape function used here is
+// drawn from the following:
+// https://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
+// https://github.com/ljharb/regexp.escape
+function * findMatchingLogLines(logLines, fields, ignoreFields) {
+ ignoreFields = ignoreFields || [];
+ function escapeRegex(input) {
+ return (typeof input === "string" ? input.replace(/[\^\$\\\.\*\+\?\(\)\[\]\{\}]/g, '\\$&')
+ : input);
+ }
+ function lineMatches(line, fields, ignoreFields) {
+ const fieldNames =
+ Object.keys(fields).filter((fieldName) => !ignoreFields.includes(fieldName));
+ return fieldNames.every((fieldName) => {
+ const fieldValue = fields[fieldName];
+ let regex = escapeRegex(fieldName) + ":? ?(" +
+ escapeRegex(checkLog.formatAsLogLine(fieldValue)) + "|" +
+ escapeRegex(checkLog.formatAsLogLine(fieldValue, true)) + ")";
+ const match = line.match(regex);
+ return match && match[0];
+ });
+ }
+
+ for (let line of logLines) {
+ if (lineMatches(line, fields, ignoreFields)) {
+ yield line;
+ }
+ }
+}
+// Finds and returns a logline containing all the specified fields, or null if no such logline
+// was found.
+function findMatchingLogLine(logLines, fields, ignoreFields) {
+ for (let line of findMatchingLogLines(logLines, fields, ignoreFields)) {
+ return line;
+ }
+ return null;
+}
diff --git a/src/mongo/db/commands/profile_common.cpp b/src/mongo/db/commands/profile_common.cpp
index c3ed936d753..d29ddf948e5 100644
--- a/src/mongo/db/commands/profile_common.cpp
+++ b/src/mongo/db/commands/profile_common.cpp
@@ -27,13 +27,16 @@
* 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::kCommand
#include "mongo/platform/basic.h"
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/commands/profile_common.h"
#include "mongo/db/commands/profile_gen.h"
+#include "mongo/db/jsobj.h"
#include "mongo/idl/idl_parser.h"
+#include "mongo/util/log.h"
namespace mongo {
@@ -70,10 +73,12 @@ bool ProfileCmdBase::run(OperationContext* opCtx,
// Delegate to _applyProfilingLevel to set the profiling level appropriately whether we are on
// mongoD or mongoS.
int oldLevel = _applyProfilingLevel(opCtx, dbName, profilingLevel);
+ auto oldSlowMS = serverGlobalParams.slowMS;
+ auto oldSampleRate = serverGlobalParams.sampleRate;
result.append("was", oldLevel);
- result.append("slowms", serverGlobalParams.slowMS);
- result.append("sampleRate", serverGlobalParams.sampleRate);
+ result.append("slowms", oldSlowMS);
+ result.append("sampleRate", oldSampleRate);
if (auto slowms = request.getSlowms()) {
serverGlobalParams.slowMS = *slowms;
@@ -85,6 +90,24 @@ bool ProfileCmdBase::run(OperationContext* opCtx,
serverGlobalParams.sampleRate = *sampleRate;
}
+ // Log the change made to server's profiling settings, unless the request was to get the current
+ // value.
+ if (profilingLevel != -1) {
+ BSONObjBuilder oldState;
+ BSONObjBuilder newState;
+
+ oldState.append("level"_sd, oldLevel);
+ oldState.append("slowms"_sd, oldSlowMS);
+ oldState.append("sampleRate"_sd, oldSampleRate);
+
+ newState.append("level"_sd, profilingLevel);
+ newState.append("slowms"_sd, serverGlobalParams.slowMS);
+ newState.append("sampleRate"_sd, serverGlobalParams.sampleRate);
+
+ LOG(0) << "{msg: \"Profiler settings changed\", from:" << oldState.obj()
+ << ", to:" << newState.obj() << "}";
+ }
+
return true;
}
} // namespace mongo