Skip to content

Commit 055e873

Browse files
Bryan ClementMartin Kuba
authored andcommitted
instrumentation: fixed issue with bluebird promises losing transaction state
1 parent 3651b79 commit 055e873

File tree

5 files changed

+155
-5
lines changed

5 files changed

+155
-5
lines changed

lib/instrumentation/bluebird.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use strict'
2+
3+
var shimmer = require('../shimmer')
4+
5+
module.exports = function initialize(agent, bluebird) {
6+
var tracer = agent.tracer
7+
8+
shimmer.wrapMethod(
9+
bluebird.prototype,
10+
'bluebird.prototype',
11+
'_then',
12+
function wrapThen(original) {
13+
return tracer.wrapFunctionNoSegment(original, null, wrapper)
14+
}
15+
)
16+
17+
function wrapper(args) {
18+
var onResolve = args[0]
19+
if (typeof onResolve === 'function') {
20+
args[0] = tracer.bindFunction(onResolve)
21+
}
22+
23+
var onReject = args[1]
24+
if (typeof onReject === 'function') {
25+
args[1] = tracer.bindFunction(onReject)
26+
}
27+
28+
return args
29+
}
30+
}

lib/instrumentations.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
module.exports = function instrumentations() {
55
return [
66
'connect',
7+
'bluebird',
78
'express',
89
'generic-pool',
910
'hapi',

lib/transaction/tracer/index.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ function argSlice(args) {
213213
return array
214214
}
215215

216-
function wrapFunctionNoSegment(original, name) {
216+
function wrapFunctionNoSegment(original, name, wrapper) {
217217
if (typeof original !== 'function') return original
218218

219219
logger.trace('Wrapping function %s (no segment)', name || original.name || 'anonymous')
@@ -224,10 +224,15 @@ function wrapFunctionNoSegment(original, name) {
224224
function wrappedFunction() {
225225
if (!tracer.getTransaction()) return original.apply(this, arguments)
226226
var args = tracer.slice(arguments)
227-
var last = args.length - 1
228-
var cb = args[last]
229-
if (typeof cb === 'function') {
230-
args[last] = tracer.bindFunction(cb)
227+
228+
if (wrapper === undefined) {
229+
var last = args.length - 1
230+
var cb = args[last]
231+
if (typeof cb === 'function') {
232+
args[last] = tracer.bindFunction(cb)
233+
}
234+
} else {
235+
args = wrapper(args)
231236
}
232237
return original.apply(this, args)
233238
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
'use strict'
2+
3+
var test = require('tap').test
4+
var helper = require('../../lib/agent_helper')
5+
6+
7+
test('preserves transaction in resolve callback', function(t) {
8+
var agent = setupAgent(t)
9+
var Promise = require('bluebird')
10+
11+
var total = 2
12+
var finished = 0
13+
14+
for (var i = 0; i < total; i++) {
15+
helper.runInTransaction(agent, function transactionWrapper(transaction) {
16+
Promise.resolve().then(function anonymous() {
17+
checkTransaction(t, agent, transaction)
18+
finished++
19+
if (finished === total) t.end()
20+
})
21+
})
22+
}
23+
})
24+
25+
test('preserves transaction in reject callback', function(t) {
26+
var agent = setupAgent(t)
27+
var Promise = require('bluebird')
28+
29+
var total = 2
30+
var finished = 0
31+
32+
for (var i = 0; i < total; i++) {
33+
helper.runInTransaction(agent, function transactionWrapper(transaction) {
34+
Promise.reject(new Error('some error')).then(
35+
function() { /* success */ },
36+
function anonymous() {
37+
checkTransaction(t, agent, transaction)
38+
finished++
39+
if (finished === total) t.end()
40+
}
41+
)
42+
})
43+
}
44+
})
45+
46+
test('preserves transaction in catch callback', function(t) {
47+
var agent = setupAgent(t)
48+
var Promise = require('bluebird')
49+
50+
var total = 2
51+
var finished = 0
52+
53+
for (var i = 0; i < total; i++) {
54+
helper.runInTransaction(agent, function transactionWrapper(transaction) {
55+
Promise.reject(new Error('some error'))
56+
.catch(function(error) {
57+
checkTransaction(t, agent, transaction)
58+
finished++
59+
if (finished === total) t.end()
60+
})
61+
})
62+
}
63+
})
64+
65+
test('preserves transaction with chained promises', function(t) {
66+
var agent = setupAgent(t)
67+
var Promise = require('bluebird')
68+
69+
helper.runInTransaction(agent, function transactionWrapper(transaction) {
70+
Promise.resolve(1).then(function() {
71+
return 1
72+
})
73+
.then(function() {
74+
return 2
75+
})
76+
.then(function() {
77+
checkTransaction(t, agent, transaction)
78+
t.end()
79+
})
80+
})
81+
})
82+
83+
test('preserves transaction with chained promises and catch callback', function(t) {
84+
var agent = setupAgent(t)
85+
var Promise = require('bluebird')
86+
87+
helper.runInTransaction(agent, function transactionWrapper(transaction) {
88+
Promise.resolve(1).then(function() {
89+
return 1
90+
})
91+
.then(function() {
92+
throw new Error('some error')
93+
})
94+
.catch(function() {
95+
checkTransaction(t, agent, transaction)
96+
t.end()
97+
})
98+
})
99+
})
100+
101+
function setupAgent(t) {
102+
var agent = helper.instrumentMockedAgent()
103+
t.tearDown(function tearDown() {
104+
helper.unloadAgent(agent)
105+
})
106+
return agent
107+
}
108+
109+
function checkTransaction(t, agent, transaction) {
110+
t.ok(agent.getTransaction() != null, 'there should be a transaction')
111+
t.equal(agent.getTransaction().id, transaction.id)
112+
}
113+

test/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"JSV": "~4.0.2",
1111
"architect": "*",
1212
"async": "*",
13+
"bluebird": "*",
1314
"chai": "^1",
1415
"connect": "*",
1516
"cover": "*",

0 commit comments

Comments
 (0)