UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

144 lines (111 loc) 4.12 kB
'use strict' const { channel, addHook, AsyncResource } = require('./helpers/instrument') const shimmer = require('../../datadog-shimmer') addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.5'] }, Bucket => { const startCh = channel('apm:couchbase:query:start') const asyncEndCh = channel('apm:couchbase:query:async-end') const endCh = channel('apm:couchbase:query:end') const errorCh = channel('apm:couchbase:query:error') Bucket.prototype._maybeInvoke = wrapMaybeInvoke(Bucket.prototype._maybeInvoke) Bucket.prototype.query = wrapQuery(Bucket.prototype.query) shimmer.wrap(Bucket.prototype, '_n1qlReq', _n1qlReq => function (host, q, adhoc, emitter) { if (!startCh.hasSubscribers) { return _n1qlReq.apply(this, arguments) } if (!emitter || !emitter.once) return _n1qlReq.apply(this, arguments) const n1qlQuery = q && q.statement startCh.publish({ resource: n1qlQuery, bucket: this }) emitter.once('rows', AsyncResource.bind(() => { asyncEndCh.publish(undefined) })) emitter.once('error', AsyncResource.bind((error) => { errorCh.publish(error) asyncEndCh.publish(undefined) })) try { return _n1qlReq.apply(this, arguments) } catch (err) { err.stack // trigger getting the stack at the original throwing point errorCh.publish(err) throw err } finally { endCh.publish(undefined) } }) Bucket.prototype.upsert = wrap('apm:couchbase:upsert', Bucket.prototype.upsert) Bucket.prototype.insert = wrap('apm:couchbase:insert', Bucket.prototype.insert) Bucket.prototype.replace = wrap('apm:couchbase:replace', Bucket.prototype.replace) Bucket.prototype.append = wrap('apm:couchbase:append', Bucket.prototype.append) Bucket.prototype.prepend = wrap('apm:couchbase:prepend', Bucket.prototype.prepend) return Bucket }) addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^2.6.5'] }, Cluster => { Cluster.prototype._maybeInvoke = wrapMaybeInvoke(Cluster.prototype._maybeInvoke) Cluster.prototype.query = wrapQuery(Cluster.prototype.query) return Cluster }) function findCallbackIndex (args) { for (let i = args.length - 1; i >= 2; i--) { if (typeof args[i] === 'function') return i } return -1 } function wrapMaybeInvoke (_maybeInvoke) { const wrapped = function (fn, args) { if (!Array.isArray(args)) return _maybeInvoke.apply(this, arguments) const callbackIndex = args.length - 1 const callback = args[callbackIndex] if (callback instanceof Function) { args[callbackIndex] = AsyncResource.bind(callback) } return _maybeInvoke.apply(this, arguments) } return shimmer.wrap(_maybeInvoke, wrapped) } function wrapQuery (query) { const wrapped = function (q, params, callback) { callback = AsyncResource.bind(arguments[arguments.length - 1]) if (typeof callback === 'function') { arguments[arguments.length - 1] = callback } const res = query.apply(this, arguments) return res } return shimmer.wrap(query, wrapped) } function wrap (prefix, fn) { const startCh = channel(prefix + ':start') const endCh = channel(prefix + ':end') const asyncEndCh = channel(prefix + ':async-end') const errorCh = channel(prefix + ':error') const wrapped = function (key, value, options, callback) { if (!startCh.hasSubscribers) { return fn.apply(this, arguments) } const callbackIndex = findCallbackIndex(arguments) if (callbackIndex < 0) return fn.apply(this, arguments) const cb = arguments[callbackIndex] startCh.publish({ bucket: this }) arguments[callbackIndex] = function (error, result) { if (error) { errorCh.publish(error) } asyncEndCh.publish(result) return cb.apply(this, arguments) } try { return fn.apply(this, arguments) } catch (error) { error.stack // trigger getting the stack at the original throwing point errorCh.publish(error) throw error } finally { endCh.publish(undefined) } } return shimmer.wrap(fn, wrapped) }