/** * Copyright 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 'use strict'; var shimmer = require('shimmer'); var SUPPORTED_VERSIONS = '1 - 2'; function createNextWrap(api) { return function nextWrap(next) { return function next_trace(cb) { var span = api.createChildSpan({ name: 'mongo-cursor' }); if (!span) { return next.apply(this, arguments); } span.addLabel('db', this.ns); if (api.enhancedDatabaseReportingEnabled()) { span.addLabel('cmd', JSON.stringify(this.cmd)); } return next.call(this, wrapCallback(api, span, cb)); }; }; } function wrapWithLabel(api, label) { return function(original) { return function mongo_operation_trace(ns, ops, options, callback) { var span = api.createChildSpan({ name: label }); if (!span) { return original.apply(this, arguments); } span.addLabel('db', ns); if (api.enhancedDatabaseReportingEnabled()) { span.addLabel('operations', JSON.stringify(ops)); } if (typeof options === 'function') { return original.call(this, ns, ops, wrapCallback(api, span, options)); } else { return original.call(this, ns, ops, options, wrapCallback(api, span, callback)); } }; }; } /** * Wraps the provided callback so that the provided span will * be closed immediately after the callback is invoked. * * @param {Span} span The span to be closed. * @param {Function} done The callback to be wrapped. * @return {Function} The wrapped function. */ function wrapCallback(api, span, done) { var fn = function(err, res) { if (api.enhancedDatabaseReportingEnabled()) { if (err) { // Errors may contain sensitive query parameters. span.addLabel('mongoError', err); } if (res) { var result = res.result ? res.result : res; span.addLabel('result', result); } } span.endSpan(); if (done) { done(err, res); } }; return api.wrap(fn); } function createOnceWrap(api) { return function onceWrap(once) { return function once_trace(event, cb) { return once.call(this, event, api.wrap(cb)); }; }; } module.exports = [ { file: 'lib/connection/pool.js', versions: SUPPORTED_VERSIONS, patch: function(pool, api) { shimmer.wrap(pool.prototype, 'once', createOnceWrap(api)); }, unpatch: function(pool) { shimmer.unwrap(pool.prototype, 'once'); } }, { file: '', versions: SUPPORTED_VERSIONS, patch: function(mongo, api) { shimmer.wrap(mongo.Server.prototype, 'command', wrapWithLabel(api, 'mongo-command')); shimmer.wrap(mongo.Server.prototype, 'insert', wrapWithLabel(api, 'mongo-insert')); shimmer.wrap(mongo.Server.prototype, 'update', wrapWithLabel(api, 'mongo-update')); shimmer.wrap(mongo.Server.prototype, 'remove', wrapWithLabel(api, 'mongo-remove')); shimmer.wrap(mongo.Cursor.prototype, '_find', createNextWrap(api)); shimmer.wrap(mongo.Cursor.prototype, '_getmore', createNextWrap(api)); }, unpatch: function(mongo) { shimmer.unwrap(mongo.Server.prototype, 'command'); shimmer.unwrap(mongo.Server.prototype, 'insert'); shimmer.unwrap(mongo.Server.prototype, 'update'); shimmer.unwrap(mongo.Server.prototype, 'remove'); shimmer.unwrap(mongo.Cursor.prototype, '_find'); shimmer.unwrap(mongo.Cursor.prototype, '_getmore'); } } ];