Skip to content

Commit

Permalink
add support for bluebird (#372)
Browse files Browse the repository at this point in the history
  • Loading branch information
rochdev authored Nov 12, 2018
1 parent bdb993b commit 52b8937
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 2 deletions.
16 changes: 16 additions & 0 deletions src/plugins/bluebird.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict'

const tx = require('./util/promise')

module.exports = [
{
name: 'bluebird',
versions: ['2.0.2 - 3'], // 2.0.0 and 2.0.1 were removed from npm
patch (Promise, tracer, config) {
this.wrap(Promise.prototype, '_then', tx.createWrapThen(tracer, config))
},
unpatch (Promise) {
this.unwrap(Promise.prototype, '_then')
}
}
]
1 change: 1 addition & 0 deletions src/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module.exports = {
'amqp10': require('./amqp10'),
'amqplib': require('./amqplib'),
'bluebird': require('./bluebird'),
'elasticsearch': require('./elasticsearch'),
'express': require('./express'),
'graphql': require('./graphql'),
Expand Down
30 changes: 30 additions & 0 deletions src/plugins/util/promise.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict'

module.exports = {
createWrapThen (tracer, config) {
return function wrapThen (then) {
return function thenWithTrace (onFulfilled, onRejected, onProgress) {
arguments[0] = wrapCallback(tracer, onFulfilled)
arguments[1] = wrapCallback(tracer, onRejected)

// not standard but sometimes supported
if (onProgress) {
arguments[2] = wrapCallback(tracer, onProgress)
}

return then.apply(this, arguments)
}
}
}
}

function wrapCallback (tracer, callback) {
if (typeof callback !== 'function') return callback

const scope = tracer.scopeManager().active()

return function () {
tracer.scopeManager().activate(scope ? scope.span() : null)
return callback.apply(this, arguments)
}
}
6 changes: 4 additions & 2 deletions src/scope/scope_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,10 @@ class ScopeManager {
let execution = this._active

while (execution !== null) {
if (execution.scope()) {
return execution.scope()
const scope = execution.scope()

if (scope) {
return scope.span() ? scope : null
}

execution = execution.parent()
Expand Down
104 changes: 104 additions & 0 deletions test/plugins/bluebird.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use strict'

const agent = require('./agent')
const plugin = require('../../src/plugins/bluebird')

wrapIt()

describe('Plugin', () => {
let Promise
let tracer

describe('bluebird', () => {
withVersions(plugin, 'bluebird', version => {
beforeEach(() => {
tracer = require('../..')
})

afterEach(() => {
return agent.close()
})

describe('without configuration', () => {
beforeEach(() => {
return agent.load(plugin, 'bluebird')
.then(() => {
Promise = require(`../../versions/bluebird@${version}`).get()
})
})

it('should run the then() callback in context where then() was called', () => {
if (process.env.DD_CONTEXT_PROPAGATION === 'false') return

const span = {}
const promise = new Promise((resolve, reject) => {
setImmediate(() => {
tracer.scopeManager().activate({})
resolve()
})
})

tracer.scopeManager().activate(span)

return promise
.then(() => {
tracer.scopeManager().activate({})
})
.then(() => {
const scope = tracer.scopeManager().active()

expect(scope).to.not.be.null
expect(scope.span()).to.equal(span)
})
})

it('should run the catch() callback in context where catch() was called', () => {
if (process.env.DD_CONTEXT_PROPAGATION === 'false') return

const span = {}
const promise = new Promise((resolve, reject) => {
setImmediate(() => {
tracer.scopeManager().activate({})
reject(new Error())
})
})

tracer.scopeManager().activate(span)

return promise
.catch(err => {
tracer.scopeManager().activate({})
throw err
})
.catch(() => {
const scope = tracer.scopeManager().active()

expect(scope).to.not.be.null
expect(scope.span()).to.equal(span)
})
})

it('should allow to run without a scope if not available when calling then()', () => {
if (process.env.DD_CONTEXT_PROPAGATION === 'false') return

tracer.scopeManager().activate(null)

const promise = new Promise((resolve, reject) => {
setImmediate(() => {
tracer.scopeManager().activate({})
resolve()
})
})

return promise
.then(() => {
tracer.scopeManager().activate({})
})
.then(() => {
expect(tracer.scopeManager().active()).to.be.null
})
})
})
})
})
})
9 changes: 9 additions & 0 deletions test/scope/scope_manager.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,13 @@ describe('ScopeManager', () => {
asyncHooks.before(1)
}).not.to.throw()
})

it('should allow deactivating a scope', () => {
const span = {}

scopeManager.activate(span)
scopeManager.activate(null)

expect(scopeManager.active()).to.be.null
})
})

0 comments on commit 52b8937

Please sign in to comment.