Skip to content

Commit b98f206

Browse files
authored
refactor(NODE-3356): Update command monitoring logging (#2853)
1 parent 68b4665 commit b98f206

File tree

9 files changed

+159
-134
lines changed

9 files changed

+159
-134
lines changed

lib/command_utils.js

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
'use strict';
2+
const Msg = require('./core/connection/msg').Msg;
3+
const KillCursor = require('./core/connection/commands').KillCursor;
4+
const GetMore = require('./core/connection/commands').GetMore;
5+
6+
/** Commands that we want to redact because of the sensitive nature of their contents */
7+
const SENSITIVE_COMMANDS = new Set([
8+
'authenticate',
9+
'saslStart',
10+
'saslContinue',
11+
'getnonce',
12+
'createUser',
13+
'updateUser',
14+
'copydbgetnonce',
15+
'copydbsaslstart',
16+
'copydb'
17+
]);
18+
19+
const HELLO_COMMANDS = new Set(['hello', 'ismaster', 'isMaster']);
20+
21+
const LEGACY_FIND_QUERY_MAP = {
22+
$query: 'filter',
23+
$orderby: 'sort',
24+
$hint: 'hint',
25+
$comment: 'comment',
26+
$maxScan: 'maxScan',
27+
$max: 'max',
28+
$min: 'min',
29+
$returnKey: 'returnKey',
30+
$showDiskLoc: 'showRecordId',
31+
$maxTimeMS: 'maxTimeMS',
32+
$snapshot: 'snapshot'
33+
};
34+
35+
const LEGACY_FIND_OPTIONS_MAP = {
36+
numberToSkip: 'skip',
37+
numberToReturn: 'batchSize',
38+
returnFieldsSelector: 'projection'
39+
};
40+
41+
const OP_QUERY_KEYS = [
42+
'tailable',
43+
'oplogReplay',
44+
'noCursorTimeout',
45+
'awaitData',
46+
'partial',
47+
'exhaust'
48+
];
49+
50+
const collectionName = command => command.ns.split('.')[1];
51+
52+
const shouldRedactCommand = (commandName, cmd) =>
53+
SENSITIVE_COMMANDS.has(commandName) ||
54+
(HELLO_COMMANDS.has(commandName) && !!cmd.speculativeAuthenticate);
55+
56+
/**
57+
* Extract the actual command from the query, possibly upconverting if it's a legacy
58+
* format
59+
*
60+
* @param {Object} command the command
61+
*/
62+
const extractCommand = command => {
63+
let extractedCommand;
64+
if (command instanceof GetMore) {
65+
extractedCommand = {
66+
getMore: command.cursorId,
67+
collection: collectionName(command),
68+
batchSize: command.numberToReturn
69+
};
70+
} else if (command instanceof KillCursor) {
71+
extractedCommand = {
72+
killCursors: collectionName(command),
73+
cursors: command.cursorIds
74+
};
75+
} else if (command instanceof Msg) {
76+
extractedCommand = command.command;
77+
} else if (command.query && command.query.$query) {
78+
let result;
79+
if (command.ns === 'admin.$cmd') {
80+
// upconvert legacy command
81+
result = Object.assign({}, command.query.$query);
82+
} else {
83+
// upconvert legacy find command
84+
result = { find: collectionName(command) };
85+
Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => {
86+
if (typeof command.query[key] !== 'undefined')
87+
result[LEGACY_FIND_QUERY_MAP[key]] = command.query[key];
88+
});
89+
}
90+
91+
Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => {
92+
if (typeof command[key] !== 'undefined') result[LEGACY_FIND_OPTIONS_MAP[key]] = command[key];
93+
});
94+
95+
OP_QUERY_KEYS.forEach(key => {
96+
if (command[key]) result[key] = command[key];
97+
});
98+
99+
if (typeof command.pre32Limit !== 'undefined') {
100+
result.limit = command.pre32Limit;
101+
}
102+
103+
if (command.query.$explain) {
104+
extractedCommand = { explain: result };
105+
} else {
106+
extractedCommand = result;
107+
}
108+
} else {
109+
extractedCommand = command.query || command;
110+
}
111+
112+
const commandName = Object.keys(extractedCommand)[0];
113+
return {
114+
cmd: extractedCommand,
115+
name: commandName,
116+
shouldRedact: shouldRedactCommand(commandName, extractedCommand)
117+
};
118+
};
119+
120+
module.exports = {
121+
extractCommand
122+
};

lib/core/connection/apm.js

Lines changed: 10 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,16 @@
11
'use strict';
2-
const Msg = require('../connection/msg').Msg;
32
const KillCursor = require('../connection/commands').KillCursor;
43
const GetMore = require('../connection/commands').GetMore;
54
const calculateDurationInMs = require('../../utils').calculateDurationInMs;
6-
7-
/** Commands that we want to redact because of the sensitive nature of their contents */
8-
const SENSITIVE_COMMANDS = new Set([
9-
'authenticate',
10-
'saslStart',
11-
'saslContinue',
12-
'getnonce',
13-
'createUser',
14-
'updateUser',
15-
'copydbgetnonce',
16-
'copydbsaslstart',
17-
'copydb'
18-
]);
19-
20-
const HELLO_COMMANDS = new Set(['hello', 'ismaster', 'isMaster']);
5+
const extractCommand = require('../../command_utils').extractCommand;
216

227
// helper methods
23-
const extractCommandName = commandDoc => Object.keys(commandDoc)[0];
248
const namespace = command => command.ns;
259
const databaseName = command => command.ns.split('.')[0];
26-
const collectionName = command => command.ns.split('.')[1];
2710
const generateConnectionId = pool =>
2811
pool.options ? `${pool.options.host}:${pool.options.port}` : pool.address;
29-
const maybeRedact = (commandName, cmd, result) =>
30-
SENSITIVE_COMMANDS.has(commandName) ||
31-
(HELLO_COMMANDS.has(commandName) && cmd.speculativeAuthenticate)
32-
? {}
33-
: result;
3412
const isLegacyPool = pool => pool.s && pool.queue;
3513

36-
const LEGACY_FIND_QUERY_MAP = {
37-
$query: 'filter',
38-
$orderby: 'sort',
39-
$hint: 'hint',
40-
$comment: 'comment',
41-
$maxScan: 'maxScan',
42-
$max: 'max',
43-
$min: 'min',
44-
$returnKey: 'returnKey',
45-
$showDiskLoc: 'showRecordId',
46-
$maxTimeMS: 'maxTimeMS',
47-
$snapshot: 'snapshot'
48-
};
49-
50-
const LEGACY_FIND_OPTIONS_MAP = {
51-
numberToSkip: 'skip',
52-
numberToReturn: 'batchSize',
53-
returnFieldsSelector: 'projection'
54-
};
55-
56-
const OP_QUERY_KEYS = [
57-
'tailable',
58-
'oplogReplay',
59-
'noCursorTimeout',
60-
'awaitData',
61-
'partial',
62-
'exhaust'
63-
];
64-
65-
/**
66-
* Extract the actual command from the query, possibly upconverting if it's a legacy
67-
* format
68-
*
69-
* @param {Object} command the command
70-
*/
71-
const extractCommand = command => {
72-
if (command instanceof GetMore) {
73-
return {
74-
getMore: command.cursorId,
75-
collection: collectionName(command),
76-
batchSize: command.numberToReturn
77-
};
78-
}
79-
80-
if (command instanceof KillCursor) {
81-
return {
82-
killCursors: collectionName(command),
83-
cursors: command.cursorIds
84-
};
85-
}
86-
87-
if (command instanceof Msg) {
88-
return command.command;
89-
}
90-
91-
if (command.query && command.query.$query) {
92-
let result;
93-
if (command.ns === 'admin.$cmd') {
94-
// upconvert legacy command
95-
result = Object.assign({}, command.query.$query);
96-
} else {
97-
// upconvert legacy find command
98-
result = { find: collectionName(command) };
99-
Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => {
100-
if (typeof command.query[key] !== 'undefined')
101-
result[LEGACY_FIND_QUERY_MAP[key]] = command.query[key];
102-
});
103-
}
104-
105-
Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => {
106-
if (typeof command[key] !== 'undefined') result[LEGACY_FIND_OPTIONS_MAP[key]] = command[key];
107-
});
108-
109-
OP_QUERY_KEYS.forEach(key => {
110-
if (command[key]) result[key] = command[key];
111-
});
112-
113-
if (typeof command.pre32Limit !== 'undefined') {
114-
result.limit = command.pre32Limit;
115-
}
116-
117-
if (command.query.$explain) {
118-
return { explain: result };
119-
}
120-
121-
return result;
122-
}
123-
124-
return command.query ? command.query : command;
125-
};
126-
12714
const extractReply = (command, reply) => {
12815
if (command instanceof GetMore) {
12916
return {
@@ -183,15 +70,15 @@ class CommandStartedEvent {
18370
* @param {Object} command the command
18471
*/
18572
constructor(pool, command) {
186-
const cmd = extractCommand(command);
187-
const commandName = extractCommandName(cmd);
73+
const extractedCommand = extractCommand(command);
74+
const commandName = extractedCommand.name;
18875
const connectionDetails = extractConnectionDetails(pool);
18976

19077
Object.assign(this, connectionDetails, {
19178
requestId: command.requestId,
19279
databaseName: databaseName(command),
19380
commandName,
194-
command: maybeRedact(commandName, cmd, cmd)
81+
command: extractedCommand.shouldRedact ? {} : extractedCommand.cmd
19582
});
19683
}
19784
}
@@ -207,15 +94,15 @@ class CommandSucceededEvent {
20794
* @param {Array} started a high resolution tuple timestamp of when the command was first sent, to calculate duration
20895
*/
20996
constructor(pool, command, reply, started) {
210-
const cmd = extractCommand(command);
211-
const commandName = extractCommandName(cmd);
97+
const extractedCommand = extractCommand(command);
98+
const commandName = extractedCommand.name;
21299
const connectionDetails = extractConnectionDetails(pool);
213100

214101
Object.assign(this, connectionDetails, {
215102
requestId: command.requestId,
216103
commandName,
217104
duration: calculateDurationInMs(started),
218-
reply: maybeRedact(commandName, cmd, extractReply(command, reply))
105+
reply: extractedCommand.shouldRedact ? {} : extractReply(command, reply)
219106
});
220107
}
221108
}
@@ -231,15 +118,15 @@ class CommandFailedEvent {
231118
* @param {Array} started a high resolution tuple timestamp of when the command was first sent, to calculate duration
232119
*/
233120
constructor(pool, command, error, started) {
234-
const cmd = extractCommand(command);
235-
const commandName = extractCommandName(cmd);
121+
const extractedCommand = extractCommand(command);
122+
const commandName = extractedCommand.name;
236123
const connectionDetails = extractConnectionDetails(pool);
237124

238125
Object.assign(this, connectionDetails, {
239126
requestId: command.requestId,
240127
commandName,
241128
duration: calculateDurationInMs(started),
242-
failure: maybeRedact(commandName, cmd, error)
129+
failure: extractedCommand.shouldRedact ? {} : error
243130
});
244131
}
245132
}

lib/core/connection/connection.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,10 +254,10 @@ class Connection extends EventEmitter {
254254
// Debug Log
255255
if (this.logger.isDebug()) {
256256
if (!Array.isArray(buffer)) {
257-
this.logger.debug(`writing buffer [${buffer.toString('hex')}] to ${this.address}`);
257+
this.logger.debug(`writing buffer [ ${buffer.length} ] to ${this.address}`);
258258
} else {
259259
for (let i = 0; i < buffer.length; i++)
260-
this.logger.debug(`writing buffer [${buffer[i].toString('hex')}] to ${this.address}`);
260+
this.logger.debug(`writing buffer [ ${buffer[i].length} ] to ${this.address}`);
261261
}
262262
}
263263

lib/core/connection/pool.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,8 @@ function messageHandler(self) {
390390
if (self.logger.isDebug()) {
391391
self.logger.debug(
392392
f(
393-
'message [%s] received from %s:%s',
394-
message.raw.toString('hex'),
393+
'message [ %s ] received from %s:%s',
394+
message.raw.length,
395395
self.options.host,
396396
self.options.port
397397
)

lib/core/sdam/server.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const isNodeShuttingDownError = require('../error').isNodeShuttingDownError;
2020
const isNetworkErrorBeforeHandshake = require('../error').isNetworkErrorBeforeHandshake;
2121
const maxWireVersion = require('../utils').maxWireVersion;
2222
const makeStateMachine = require('../utils').makeStateMachine;
23+
const extractCommand = require('../../command_utils').extractCommand;
2324
const common = require('./common');
2425
const ServerType = common.ServerType;
2526
const isTransactionCommand = require('../transactions').isTransactionCommand;
@@ -261,10 +262,11 @@ class Server extends EventEmitter {
261262

262263
// Debug log
263264
if (this.s.logger.isDebug()) {
265+
const extractedCommand = extractCommand(cmd);
264266
this.s.logger.debug(
265267
`executing command [${JSON.stringify({
266268
ns,
267-
cmd,
269+
cmd: extractedCommand.shouldRedact ? `${extractedCommand.name} details REDACTED` : cmd,
268270
options: debugOptions(DEBUG_FIELDS, options)
269271
})}] against ${this.name}`
270272
);

lib/core/topologies/server.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ var inherits = require('util').inherits,
1616
createCompressionInfo = require('./shared').createCompressionInfo,
1717
resolveClusterTime = require('./shared').resolveClusterTime,
1818
SessionMixins = require('./shared').SessionMixins,
19+
extractCommand = require('../../command_utils').extractCommand,
1920
relayEvents = require('../utils').relayEvents;
2021

2122
const collationNotSupported = require('../utils').collationNotSupported;
@@ -608,18 +609,20 @@ Server.prototype.command = function(ns, cmd, options, callback) {
608609
options = Object.assign({}, options, { wireProtocolCommand: false });
609610

610611
// Debug log
611-
if (self.s.logger.isDebug())
612+
if (self.s.logger.isDebug()) {
613+
const extractedCommand = extractCommand(cmd);
612614
self.s.logger.debug(
613615
f(
614616
'executing command [%s] against %s',
615617
JSON.stringify({
616618
ns: ns,
617-
cmd: cmd,
619+
cmd: extractedCommand.shouldRedact ? `${extractedCommand.name} details REDACTED` : cmd,
618620
options: debugOptions(debugFields, options)
619621
}),
620622
self.name
621623
)
622624
);
625+
}
623626

624627
// If we are not connected or have a disconnectHandler specified
625628
if (disconnectHandler(self, 'command', ns, cmd, options, callback)) return;

0 commit comments

Comments
 (0)