Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

apm.js 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. 'use strict';
  2. const KillCursor = require('../connection/commands').KillCursor;
  3. const GetMore = require('../connection/commands').GetMore;
  4. const calculateDurationInMs = require('../utils').calculateDurationInMs;
  5. /** Commands that we want to redact because of the sensitive nature of their contents */
  6. const SENSITIVE_COMMANDS = new Set([
  7. 'authenticate',
  8. 'saslStart',
  9. 'saslContinue',
  10. 'getnonce',
  11. 'createUser',
  12. 'updateUser',
  13. 'copydbgetnonce',
  14. 'copydbsaslstart',
  15. 'copydb'
  16. ]);
  17. // helper methods
  18. const extractCommandName = command => Object.keys(command)[0];
  19. const namespace = command => command.ns;
  20. const databaseName = command => command.ns.split('.')[0];
  21. const collectionName = command => command.ns.split('.')[1];
  22. const generateConnectionId = pool => `${pool.options.host}:${pool.options.port}`;
  23. const maybeRedact = (commandName, result) => (SENSITIVE_COMMANDS.has(commandName) ? {} : result);
  24. const LEGACY_FIND_QUERY_MAP = {
  25. $query: 'filter',
  26. $orderby: 'sort',
  27. $hint: 'hint',
  28. $comment: 'comment',
  29. $maxScan: 'maxScan',
  30. $max: 'max',
  31. $min: 'min',
  32. $returnKey: 'returnKey',
  33. $showDiskLoc: 'showRecordId',
  34. $maxTimeMS: 'maxTimeMS',
  35. $snapshot: 'snapshot'
  36. };
  37. const LEGACY_FIND_OPTIONS_MAP = {
  38. numberToSkip: 'skip',
  39. numberToReturn: 'batchSize',
  40. returnFieldsSelector: 'projection'
  41. };
  42. const OP_QUERY_KEYS = [
  43. 'tailable',
  44. 'oplogReplay',
  45. 'noCursorTimeout',
  46. 'awaitData',
  47. 'partial',
  48. 'exhaust'
  49. ];
  50. /**
  51. * Extract the actual command from the query, possibly upconverting if it's a legacy
  52. * format
  53. *
  54. * @param {Object} command the command
  55. */
  56. const extractCommand = command => {
  57. if (command instanceof GetMore) {
  58. return {
  59. getMore: command.cursorId,
  60. collection: collectionName(command),
  61. batchSize: command.numberToReturn
  62. };
  63. }
  64. if (command instanceof KillCursor) {
  65. return {
  66. killCursors: collectionName(command),
  67. cursors: command.cursorIds
  68. };
  69. }
  70. if (command.query && command.query.$query) {
  71. let result;
  72. if (command.ns === 'admin.$cmd') {
  73. // upconvert legacy command
  74. result = Object.assign({}, command.query.$query);
  75. } else {
  76. // upconvert legacy find command
  77. result = { find: collectionName(command) };
  78. Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => {
  79. if (typeof command.query[key] !== 'undefined')
  80. result[LEGACY_FIND_QUERY_MAP[key]] = command.query[key];
  81. });
  82. }
  83. Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => {
  84. if (typeof command[key] !== 'undefined') result[LEGACY_FIND_OPTIONS_MAP[key]] = command[key];
  85. });
  86. OP_QUERY_KEYS.forEach(key => {
  87. if (command[key]) result[key] = command[key];
  88. });
  89. if (typeof command.pre32Limit !== 'undefined') {
  90. result.limit = command.pre32Limit;
  91. }
  92. if (command.query.$explain) {
  93. return { explain: result };
  94. }
  95. return result;
  96. }
  97. return command.query ? command.query : command;
  98. };
  99. const extractReply = (command, reply) => {
  100. if (command instanceof GetMore) {
  101. return {
  102. ok: 1,
  103. cursor: {
  104. id: reply.message.cursorId,
  105. ns: namespace(command),
  106. nextBatch: reply.message.documents
  107. }
  108. };
  109. }
  110. if (command instanceof KillCursor) {
  111. return {
  112. ok: 1,
  113. cursorsUnknown: command.cursorIds
  114. };
  115. }
  116. // is this a legacy find command?
  117. if (command.query && typeof command.query.$query !== 'undefined') {
  118. return {
  119. ok: 1,
  120. cursor: {
  121. id: reply.message.cursorId,
  122. ns: namespace(command),
  123. firstBatch: reply.message.documents
  124. }
  125. };
  126. }
  127. return reply.result;
  128. };
  129. /** An event indicating the start of a given command */
  130. class CommandStartedEvent {
  131. /**
  132. * Create a started event
  133. *
  134. * @param {Pool} pool the pool that originated the command
  135. * @param {Object} command the command
  136. */
  137. constructor(pool, command) {
  138. const cmd = extractCommand(command);
  139. const commandName = extractCommandName(cmd);
  140. // NOTE: remove in major revision, this is not spec behavior
  141. if (SENSITIVE_COMMANDS.has(commandName)) {
  142. this.commandObj = {};
  143. this.commandObj[commandName] = true;
  144. }
  145. Object.assign(this, {
  146. command: cmd,
  147. databaseName: databaseName(command),
  148. commandName,
  149. requestId: command.requestId,
  150. connectionId: generateConnectionId(pool)
  151. });
  152. }
  153. }
  154. /** An event indicating the success of a given command */
  155. class CommandSucceededEvent {
  156. /**
  157. * Create a succeeded event
  158. *
  159. * @param {Pool} pool the pool that originated the command
  160. * @param {Object} command the command
  161. * @param {Object} reply the reply for this command from the server
  162. * @param {Array} started a high resolution tuple timestamp of when the command was first sent, to calculate duration
  163. */
  164. constructor(pool, command, reply, started) {
  165. const cmd = extractCommand(command);
  166. const commandName = extractCommandName(cmd);
  167. Object.assign(this, {
  168. duration: calculateDurationInMs(started),
  169. commandName,
  170. reply: maybeRedact(commandName, extractReply(command, reply)),
  171. requestId: command.requestId,
  172. connectionId: generateConnectionId(pool)
  173. });
  174. }
  175. }
  176. /** An event indicating the failure of a given command */
  177. class CommandFailedEvent {
  178. /**
  179. * Create a failure event
  180. *
  181. * @param {Pool} pool the pool that originated the command
  182. * @param {Object} command the command
  183. * @param {MongoError|Object} error the generated error or a server error response
  184. * @param {Array} started a high resolution tuple timestamp of when the command was first sent, to calculate duration
  185. */
  186. constructor(pool, command, error, started) {
  187. const cmd = extractCommand(command);
  188. const commandName = extractCommandName(cmd);
  189. Object.assign(this, {
  190. duration: calculateDurationInMs(started),
  191. commandName,
  192. failure: maybeRedact(commandName, error),
  193. requestId: command.requestId,
  194. connectionId: generateConnectionId(pool)
  195. });
  196. }
  197. }
  198. module.exports = {
  199. CommandStartedEvent,
  200. CommandSucceededEvent,
  201. CommandFailedEvent
  202. };