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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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.options[key] !== 'undefined')
  85. result[LEGACY_FIND_OPTIONS_MAP[key]] = command.options[key];
  86. });
  87. OP_QUERY_KEYS.forEach(key => {
  88. if (command[key]) result[key] = command[key];
  89. });
  90. if (typeof command.pre32Limit !== 'undefined') {
  91. result.limit = command.pre32Limit;
  92. }
  93. if (command.query.$explain) {
  94. return { explain: result };
  95. }
  96. return result;
  97. }
  98. return command.query ? command.query : command;
  99. };
  100. const extractReply = (command, reply) => {
  101. if (command instanceof GetMore) {
  102. return {
  103. ok: 1,
  104. cursor: {
  105. id: reply.message.cursorId,
  106. ns: namespace(command),
  107. nextBatch: reply.message.documents
  108. }
  109. };
  110. }
  111. if (command instanceof KillCursor) {
  112. return {
  113. ok: 1,
  114. cursorsUnknown: command.cursorIds
  115. };
  116. }
  117. // is this a legacy find command?
  118. if (command.query && typeof command.query.$query !== 'undefined') {
  119. return {
  120. ok: 1,
  121. cursor: {
  122. id: reply.message.cursorId,
  123. ns: namespace(command),
  124. firstBatch: reply.message.documents
  125. }
  126. };
  127. }
  128. return reply.result;
  129. };
  130. /** An event indicating the start of a given command */
  131. class CommandStartedEvent {
  132. /**
  133. * Create a started event
  134. *
  135. * @param {Pool} pool the pool that originated the command
  136. * @param {Object} command the command
  137. */
  138. constructor(pool, command) {
  139. const cmd = extractCommand(command);
  140. const commandName = extractCommandName(cmd);
  141. // NOTE: remove in major revision, this is not spec behavior
  142. if (SENSITIVE_COMMANDS.has(commandName)) {
  143. this.commandObj = {};
  144. this.commandObj[commandName] = true;
  145. }
  146. Object.assign(this, {
  147. command: cmd,
  148. databaseName: databaseName(command),
  149. commandName,
  150. requestId: command.requestId,
  151. connectionId: generateConnectionId(pool)
  152. });
  153. }
  154. }
  155. /** An event indicating the success of a given command */
  156. class CommandSucceededEvent {
  157. /**
  158. * Create a succeeded event
  159. *
  160. * @param {Pool} pool the pool that originated the command
  161. * @param {Object} command the command
  162. * @param {Object} reply the reply for this command from the server
  163. * @param {Array} started a high resolution tuple timestamp of when the command was first sent, to calculate duration
  164. */
  165. constructor(pool, command, reply, started) {
  166. const cmd = extractCommand(command);
  167. const commandName = extractCommandName(cmd);
  168. Object.assign(this, {
  169. duration: calculateDurationInMs(started),
  170. commandName,
  171. reply: maybeRedact(commandName, extractReply(command, reply)),
  172. requestId: command.requestId,
  173. connectionId: generateConnectionId(pool)
  174. });
  175. }
  176. }
  177. /** An event indicating the failure of a given command */
  178. class CommandFailedEvent {
  179. /**
  180. * Create a failure event
  181. *
  182. * @param {Pool} pool the pool that originated the command
  183. * @param {Object} command the command
  184. * @param {MongoError|Object} error the generated error or a server error response
  185. * @param {Array} started a high resolution tuple timestamp of when the command was first sent, to calculate duration
  186. */
  187. constructor(pool, command, error, started) {
  188. const cmd = extractCommand(command);
  189. const commandName = extractCommandName(cmd);
  190. Object.assign(this, {
  191. duration: calculateDurationInMs(started),
  192. commandName,
  193. failure: maybeRedact(commandName, error),
  194. requestId: command.requestId,
  195. connectionId: generateConnectionId(pool)
  196. });
  197. }
  198. }
  199. module.exports = {
  200. CommandStartedEvent,
  201. CommandSucceededEvent,
  202. CommandFailedEvent
  203. };