3
3
const { errorMonitor } = require ( 'events' )
4
4
const {
5
5
channel,
6
- addHook,
7
- AsyncResource
6
+ addHook
8
7
} = require ( './helpers/instrument' )
9
8
const shimmer = require ( '../../datadog-shimmer' )
10
9
@@ -24,31 +23,50 @@ function wrapAllNames (names, action) {
24
23
names . forEach ( name => action ( name ) )
25
24
}
26
25
27
- // semver >=2 <3
28
- function wrapMaybeInvoke ( _maybeInvoke ) {
29
- const wrapped = function ( fn , args ) {
30
- if ( ! Array . isArray ( args ) ) return _maybeInvoke . apply ( this , arguments )
31
-
32
- const callbackIndex = args . length - 1
33
- const callback = args [ callbackIndex ]
26
+ function wrapCallback ( callback , ctx , channelPrefix ) {
27
+ const callbackStartCh = channel ( `${ channelPrefix } :callback:start` )
28
+ const callbackFinishCh = channel ( `${ channelPrefix } :callback:finish` )
34
29
35
- if ( typeof callback === 'function' ) {
36
- args [ callbackIndex ] = AsyncResource . bind ( callback )
30
+ const wrapped = callbackStartCh . runStores ( ctx , ( ) => {
31
+ return function ( ...args ) {
32
+ return callbackFinishCh . runStores ( ctx , ( ) => {
33
+ return callback . apply ( this , args )
34
+ } )
37
35
}
38
-
39
- return _maybeInvoke . apply ( this , arguments )
40
- }
36
+ } )
37
+ Object . defineProperty ( wrapped , '_dd_wrapped' , { value : true } )
41
38
return wrapped
42
39
}
43
40
44
41
function wrapQuery ( query ) {
45
- const wrapped = function ( q , params , callback ) {
46
- if ( typeof arguments [ arguments . length - 1 ] === 'function' ) {
47
- arguments [ arguments . length - 1 ] = AsyncResource . bind ( arguments [ arguments . length - 1 ] )
42
+ return function ( q , params , callback ) {
43
+ const cb = arguments [ arguments . length - 1 ]
44
+ if ( typeof cb === 'function' ) {
45
+ const ctx = { }
46
+ arguments [ arguments . length - 1 ] = wrapCallback ( cb , ctx , 'apm:couchbase:query' )
48
47
}
49
48
50
49
return query . apply ( this , arguments )
51
50
}
51
+ }
52
+
53
+ function wrapCallbackFinish ( callback , thisArg , _args , errorCh , finishCh , ctx , channelPrefix ) {
54
+ const callbackStartCh = channel ( `${ channelPrefix } :callback:start` )
55
+ const callbackFinishCh = channel ( `${ channelPrefix } :callback:finish` )
56
+
57
+ const wrapped = callbackStartCh . runStores ( ctx , ( ) => {
58
+ return function finish ( error , result ) {
59
+ return callbackFinishCh . runStores ( ctx , ( ) => {
60
+ if ( error ) {
61
+ ctx . error = error
62
+ errorCh . publish ( ctx )
63
+ }
64
+ finishCh . publish ( ctx )
65
+ return callback . apply ( thisArg , [ error , result ] )
66
+ } )
67
+ }
68
+ } )
69
+ Object . defineProperty ( wrapped , '_dd_wrapped' , { value : true } )
52
70
return wrapped
53
71
}
54
72
@@ -62,31 +80,24 @@ function wrap (prefix, fn) {
62
80
return fn . apply ( this , arguments )
63
81
}
64
82
65
- const callbackIndex = findCallbackIndex ( arguments )
83
+ const callbackIndex = findCallbackIndex ( arguments , 1 )
66
84
67
85
if ( callbackIndex < 0 ) return fn . apply ( this , arguments )
68
86
69
- const callbackResource = new AsyncResource ( 'bound-anonymous-fn' )
70
- const asyncResource = new AsyncResource ( 'bound-anonymous-fn' )
71
-
72
- return asyncResource . runInAsyncScope ( ( ) => {
73
- const cb = callbackResource . bind ( arguments [ callbackIndex ] )
87
+ const ctx = { bucket : { name : this . name || this . _name } , seedNodes : this . _dd_hosts }
88
+ return startCh . runStores ( ctx , ( ) => {
89
+ const cb = arguments [ callbackIndex ]
74
90
75
- startCh . publish ( { bucket : { name : this . name || this . _name } , seedNodes : this . _dd_hosts } )
76
-
77
- arguments [ callbackIndex ] = shimmer . wrapFunction ( cb , cb => asyncResource . bind ( function ( error , result ) {
78
- if ( error ) {
79
- errorCh . publish ( error )
80
- }
81
- finishCh . publish ( result )
82
- return cb . apply ( this , arguments )
83
- } ) )
91
+ arguments [ callbackIndex ] = shimmer . wrapFunction ( cb , ( cb ) => {
92
+ return wrapCallbackFinish ( cb , this , arguments , errorCh , finishCh , ctx , prefix )
93
+ } )
84
94
85
95
try {
86
96
return fn . apply ( this , arguments )
87
97
} catch ( error ) {
98
+ ctx . error = error
88
99
error . stack // trigger getting the stack at the original throwing point
89
- errorCh . publish ( error )
100
+ errorCh . publish ( ctx )
90
101
91
102
throw error
92
103
}
@@ -95,6 +106,26 @@ function wrap (prefix, fn) {
95
106
return wrapped
96
107
}
97
108
109
+ // semver >=2 <3
110
+ function wrapMaybeInvoke ( _maybeInvoke , channelPrefix ) {
111
+ return function ( fn , args ) {
112
+ if ( ! Array . isArray ( args ) ) return _maybeInvoke . apply ( this , arguments )
113
+
114
+ const callbackIndex = findCallbackIndex ( args , 0 )
115
+
116
+ if ( callbackIndex === - 1 ) return _maybeInvoke . apply ( this , arguments )
117
+
118
+ const callback = args [ callbackIndex ]
119
+
120
+ if ( typeof callback === 'function' && ! callback . _dd_wrapped ) {
121
+ const ctx = { }
122
+ args [ callbackIndex ] = wrapCallback ( callback , ctx , channelPrefix )
123
+ }
124
+
125
+ return _maybeInvoke . apply ( this , arguments )
126
+ }
127
+ }
128
+
98
129
// semver >=3
99
130
100
131
function wrapCBandPromise ( fn , name , startData , thisArg , args ) {
@@ -104,36 +135,36 @@ function wrapCBandPromise (fn, name, startData, thisArg, args) {
104
135
105
136
if ( ! startCh . hasSubscribers ) return fn . apply ( thisArg , args )
106
137
107
- const asyncResource = new AsyncResource ( 'bound-anonymous-fn' )
108
- const callbackResource = new AsyncResource ( 'bound-anonymous-fn' )
109
-
110
- return asyncResource . runInAsyncScope ( ( ) => {
111
- startCh . publish ( startData )
112
-
138
+ const ctx = startData
139
+ return startCh . runStores ( ctx , ( ) => {
113
140
try {
114
141
const cbIndex = findCallbackIndex ( args , 1 )
115
142
if ( cbIndex >= 0 ) {
116
143
// v3 offers callback or promises event handling
117
144
// NOTE: this does not work with v3.2.0-3.2.1 cluster.query, as there is a bug in the couchbase source code
118
- const cb = callbackResource . bind ( args [ cbIndex ] )
119
- args [ cbIndex ] = shimmer . wrapFunction ( cb , cb => asyncResource . bind ( function ( error , result ) {
120
- if ( error ) {
121
- errorCh . publish ( error )
122
- }
123
- finishCh . publish ( { result } )
124
- return cb . apply ( thisArg , arguments )
125
- } ) )
145
+ args [ cbIndex ] = shimmer . wrapFunction ( args [ cbIndex ] , ( cb ) => {
146
+ return wrapCallbackFinish ( cb , thisArg , args , errorCh , finishCh , ctx , `apm:couchbase:${ name } ` )
147
+ } )
126
148
}
127
149
const res = fn . apply ( thisArg , args )
128
150
129
151
// semver >=3 will always return promise by default
130
152
res . then (
131
- asyncResource . bind ( ( result ) => finishCh . publish ( { result } ) ) ,
132
- asyncResource . bind ( ( err ) => errorCh . publish ( err ) ) )
153
+ ( result ) => {
154
+ ctx . result = result
155
+ finishCh . publish ( ctx )
156
+ } ,
157
+ ( err ) => {
158
+ ctx . error = err
159
+ errorCh . publish ( ctx )
160
+ finishCh . publish ( ctx )
161
+ }
162
+ )
133
163
return res
134
164
} catch ( e ) {
135
165
e . stack
136
- errorCh . publish ( e )
166
+ ctx . error = e
167
+ errorCh . publish ( ctx )
137
168
throw e
138
169
}
139
170
} )
@@ -160,11 +191,14 @@ function wrapV3Query (query) {
160
191
161
192
// semver >=2 <3
162
193
addHook ( { name : 'couchbase' , file : 'lib/bucket.js' , versions : [ '^2.6.12' ] } , Bucket => {
194
+ shimmer . wrap ( Bucket . prototype , '_maybeInvoke' , maybeInvoke => {
195
+ return wrapMaybeInvoke ( maybeInvoke , 'apm:couchbase:bucket:maybeInvoke' )
196
+ } )
197
+
163
198
const startCh = channel ( 'apm:couchbase:query:start' )
164
199
const finishCh = channel ( 'apm:couchbase:query:finish' )
165
200
const errorCh = channel ( 'apm:couchbase:query:error' )
166
201
167
- shimmer . wrap ( Bucket . prototype , '_maybeInvoke' , maybeInvoke => wrapMaybeInvoke ( maybeInvoke ) )
168
202
shimmer . wrap ( Bucket . prototype , 'query' , query => wrapQuery ( query ) )
169
203
170
204
shimmer . wrap ( Bucket . prototype , '_n1qlReq' , _n1qlReq => function ( host , q , adhoc , emitter ) {
@@ -176,24 +210,25 @@ addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.12'] }, Buc
176
210
177
211
const n1qlQuery = getQueryResource ( q )
178
212
179
- const asyncResource = new AsyncResource ( 'bound-anonymous-fn' )
180
- return asyncResource . runInAsyncScope ( ( ) => {
181
- startCh . publish ( { resource : n1qlQuery , bucket : { name : this . name || this . _name } , seedNodes : this . _dd_hosts } )
182
-
183
- emitter . once ( 'rows' , asyncResource . bind ( ( ) => {
184
- finishCh . publish ( )
185
- } ) )
213
+ const ctx = { resource : n1qlQuery , bucket : { name : this . name || this . _name } , seedNodes : this . _dd_hosts }
214
+ return startCh . runStores ( ctx , ( ) => {
215
+ emitter . once ( 'rows' , ( ) => {
216
+ finishCh . publish ( ctx )
217
+ } )
186
218
187
- emitter . once ( errorMonitor , asyncResource . bind ( ( error ) => {
188
- errorCh . publish ( error )
189
- finishCh . publish ( )
190
- } ) )
219
+ emitter . once ( errorMonitor , ( error ) => {
220
+ if ( ! error ) return
221
+ ctx . error = error
222
+ errorCh . publish ( ctx )
223
+ finishCh . publish ( ctx )
224
+ } )
191
225
192
226
try {
193
227
return _n1qlReq . apply ( this , arguments )
194
228
} catch ( err ) {
195
229
err . stack // trigger getting the stack at the original throwing point
196
- errorCh . publish ( err )
230
+ ctx . error = err
231
+ errorCh . publish ( ctx )
197
232
198
233
throw err
199
234
}
@@ -208,9 +243,11 @@ addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.12'] }, Buc
208
243
} )
209
244
210
245
addHook ( { name : 'couchbase' , file : 'lib/cluster.js' , versions : [ '^2.6.12' ] } , Cluster => {
211
- shimmer . wrap ( Cluster . prototype , '_maybeInvoke' , maybeInvoke => wrapMaybeInvoke ( maybeInvoke ) )
212
- shimmer . wrap ( Cluster . prototype , 'query' , query => wrapQuery ( query ) )
246
+ shimmer . wrap ( Cluster . prototype , '_maybeInvoke' , maybeInvoke => {
247
+ return wrapMaybeInvoke ( maybeInvoke , 'apm:couchbase:cluster:maybeInvoke' )
248
+ } )
213
249
250
+ shimmer . wrap ( Cluster . prototype , 'query' , query => wrapQuery ( query ) )
214
251
shimmer . wrap ( Cluster . prototype , 'openBucket' , openBucket => {
215
252
return function ( ) {
216
253
const bucket = openBucket . apply ( this , arguments )
0 commit comments