@redthreadlabs/tracelog 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +126 -0
  3. package/index.d.ts +464 -0
  4. package/index.js +11 -0
  5. package/lib/InflightEventSet.js +53 -0
  6. package/lib/activation-method.js +97 -0
  7. package/lib/agent.js +1226 -0
  8. package/lib/apm-client/apm-client.js +107 -0
  9. package/lib/apm-client/channel-writer.js +334 -0
  10. package/lib/apm-client/jsonl-file-client.js +241 -0
  11. package/lib/apm-client/ndjson.js +20 -0
  12. package/lib/apm-client/noop-apm-client.js +79 -0
  13. package/lib/apm-client/s3-uploader.js +308 -0
  14. package/lib/apm-client/truncate.js +507 -0
  15. package/lib/async-hooks-polyfill.js +58 -0
  16. package/lib/cloud-metadata/aws.js +175 -0
  17. package/lib/cloud-metadata/azure.js +123 -0
  18. package/lib/cloud-metadata/callback-coordination.js +159 -0
  19. package/lib/cloud-metadata/gcp.js +133 -0
  20. package/lib/cloud-metadata/index.js +175 -0
  21. package/lib/config/config.js +431 -0
  22. package/lib/config/normalizers.js +649 -0
  23. package/lib/config/schema.js +946 -0
  24. package/lib/constants.js +35 -0
  25. package/lib/errors.js +303 -0
  26. package/lib/filters/sanitize-field-names.js +69 -0
  27. package/lib/http-request.js +249 -0
  28. package/lib/instrumentation/context.js +56 -0
  29. package/lib/instrumentation/dropped-spans-stats.js +112 -0
  30. package/lib/instrumentation/elasticsearch-shared.js +63 -0
  31. package/lib/instrumentation/express-utils.js +91 -0
  32. package/lib/instrumentation/generic-span.js +322 -0
  33. package/lib/instrumentation/http-shared.js +424 -0
  34. package/lib/instrumentation/ids.js +39 -0
  35. package/lib/instrumentation/index.js +1078 -0
  36. package/lib/instrumentation/modules/@apollo/server.js +39 -0
  37. package/lib/instrumentation/modules/@aws-sdk/client-dynamodb.js +143 -0
  38. package/lib/instrumentation/modules/@aws-sdk/client-s3.js +230 -0
  39. package/lib/instrumentation/modules/@aws-sdk/client-sns.js +197 -0
  40. package/lib/instrumentation/modules/@aws-sdk/client-sqs.js +336 -0
  41. package/lib/instrumentation/modules/@elastic/elasticsearch.js +343 -0
  42. package/lib/instrumentation/modules/@hapi/hapi.js +221 -0
  43. package/lib/instrumentation/modules/@redis/client/dist/lib/client/commands-queue.js +178 -0
  44. package/lib/instrumentation/modules/@redis/client/dist/lib/client/index.js +49 -0
  45. package/lib/instrumentation/modules/@smithy/smithy-client.js +198 -0
  46. package/lib/instrumentation/modules/apollo-server-core.js +49 -0
  47. package/lib/instrumentation/modules/aws-sdk/dynamodb.js +155 -0
  48. package/lib/instrumentation/modules/aws-sdk/s3.js +184 -0
  49. package/lib/instrumentation/modules/aws-sdk/sns.js +232 -0
  50. package/lib/instrumentation/modules/aws-sdk/sqs.js +361 -0
  51. package/lib/instrumentation/modules/aws-sdk.js +76 -0
  52. package/lib/instrumentation/modules/bluebird.js +93 -0
  53. package/lib/instrumentation/modules/cassandra-driver.js +280 -0
  54. package/lib/instrumentation/modules/elasticsearch.js +200 -0
  55. package/lib/instrumentation/modules/express-graphql.js +66 -0
  56. package/lib/instrumentation/modules/express-queue.js +28 -0
  57. package/lib/instrumentation/modules/express.js +162 -0
  58. package/lib/instrumentation/modules/fastify.js +179 -0
  59. package/lib/instrumentation/modules/finalhandler.js +41 -0
  60. package/lib/instrumentation/modules/generic-pool.js +85 -0
  61. package/lib/instrumentation/modules/graphql.js +256 -0
  62. package/lib/instrumentation/modules/handlebars.js +33 -0
  63. package/lib/instrumentation/modules/http.js +112 -0
  64. package/lib/instrumentation/modules/http2.js +320 -0
  65. package/lib/instrumentation/modules/https.js +68 -0
  66. package/lib/instrumentation/modules/ioredis.js +94 -0
  67. package/lib/instrumentation/modules/jade.js +29 -0
  68. package/lib/instrumentation/modules/kafkajs.js +476 -0
  69. package/lib/instrumentation/modules/knex.js +91 -0
  70. package/lib/instrumentation/modules/koa-router.js +74 -0
  71. package/lib/instrumentation/modules/koa.js +15 -0
  72. package/lib/instrumentation/modules/memcached.js +100 -0
  73. package/lib/instrumentation/modules/mimic-response.js +45 -0
  74. package/lib/instrumentation/modules/mongodb/lib/cmap/connection_pool.js +40 -0
  75. package/lib/instrumentation/modules/mongodb-core.js +206 -0
  76. package/lib/instrumentation/modules/mongodb.js +259 -0
  77. package/lib/instrumentation/modules/mysql.js +200 -0
  78. package/lib/instrumentation/modules/mysql2.js +140 -0
  79. package/lib/instrumentation/modules/pg.js +148 -0
  80. package/lib/instrumentation/modules/pug.js +29 -0
  81. package/lib/instrumentation/modules/redis.js +176 -0
  82. package/lib/instrumentation/modules/restify.js +52 -0
  83. package/lib/instrumentation/modules/tedious.js +159 -0
  84. package/lib/instrumentation/modules/undici.js +270 -0
  85. package/lib/instrumentation/modules/ws.js +59 -0
  86. package/lib/instrumentation/noop-transaction.js +81 -0
  87. package/lib/instrumentation/run-context/AbstractRunContextManager.js +215 -0
  88. package/lib/instrumentation/run-context/AsyncHooksRunContextManager.js +106 -0
  89. package/lib/instrumentation/run-context/AsyncLocalStorageRunContextManager.js +73 -0
  90. package/lib/instrumentation/run-context/BasicRunContextManager.js +82 -0
  91. package/lib/instrumentation/run-context/RunContext.js +151 -0
  92. package/lib/instrumentation/run-context/index.js +23 -0
  93. package/lib/instrumentation/shimmer.js +123 -0
  94. package/lib/instrumentation/span-compression.js +239 -0
  95. package/lib/instrumentation/span.js +621 -0
  96. package/lib/instrumentation/template-shared.js +43 -0
  97. package/lib/instrumentation/timer.js +84 -0
  98. package/lib/instrumentation/transaction.js +571 -0
  99. package/lib/load-source-map.js +100 -0
  100. package/lib/logging.js +212 -0
  101. package/lib/metrics/index.js +92 -0
  102. package/lib/metrics/platforms/generic/index.js +40 -0
  103. package/lib/metrics/platforms/generic/process-cpu.js +22 -0
  104. package/lib/metrics/platforms/generic/process-top.js +157 -0
  105. package/lib/metrics/platforms/generic/stats.js +34 -0
  106. package/lib/metrics/platforms/generic/system-cpu.js +51 -0
  107. package/lib/metrics/platforms/linux/index.js +19 -0
  108. package/lib/metrics/platforms/linux/stats.js +213 -0
  109. package/lib/metrics/queue.js +90 -0
  110. package/lib/metrics/registry.js +52 -0
  111. package/lib/metrics/reporter.js +119 -0
  112. package/lib/metrics/runtime.js +77 -0
  113. package/lib/middleware/connect.js +16 -0
  114. package/lib/parsers.js +225 -0
  115. package/lib/propwrap.js +147 -0
  116. package/lib/stacktraces.js +537 -0
  117. package/lib/symbols.js +15 -0
  118. package/lib/tracecontext/index.js +115 -0
  119. package/lib/tracecontext/traceparent.js +185 -0
  120. package/lib/tracecontext/tracestate.js +388 -0
  121. package/lib/wildcard-matcher.js +52 -0
  122. package/loader.mjs +7 -0
  123. package/package.json +98 -0
  124. package/start.d.ts +8 -0
  125. package/start.js +29 -0
  126. package/types/aws-lambda.d.ts +98 -0
  127. package/types/connect.d.ts +23 -0
@@ -0,0 +1,361 @@
1
+ /*
2
+ * Copyright Elasticsearch B.V. and other contributors where applicable.
3
+ * Licensed under the BSD 2-Clause License; you may not use this file except in
4
+ * compliance with the BSD 2-Clause License.
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ const { URL } = require('url');
10
+ const {
11
+ MAX_MESSAGES_PROCESSED_FOR_TRACE_CONTEXT,
12
+ } = require('../../../constants');
13
+
14
+ const OPERATIONS_TO_ACTIONS = {
15
+ deleteMessage: 'delete',
16
+ deleteMessageBatch: 'delete_batch',
17
+ receiveMessage: 'poll',
18
+ sendMessageBatch: 'send_batch',
19
+ sendMessage: 'send',
20
+ unknown: 'unknown',
21
+ };
22
+ const OPERATIONS = Object.keys(OPERATIONS_TO_ACTIONS);
23
+ const TYPE = 'messaging';
24
+ const SUBTYPE = 'sqs';
25
+ const queueMetrics = new Map();
26
+
27
+ const MAX_SQS_MESSAGE_ATTRIBUTES = 10;
28
+
29
+ // Returns Message Queue action from AWS SDK method name
30
+ function getActionFromRequest(request) {
31
+ request = request || {};
32
+ const operation = request.operation ? request.operation : 'unknown';
33
+ const action = OPERATIONS_TO_ACTIONS[operation];
34
+
35
+ return action;
36
+ }
37
+
38
+ // Returns preposition to use in span name
39
+ //
40
+ // POLL from ...
41
+ // SEND to ...
42
+ function getToFromFromOperation(operation) {
43
+ let result = 'from';
44
+ if (operation === 'sendMessage' || operation === 'sendMessageBatch') {
45
+ result = 'to';
46
+ }
47
+ return result;
48
+ }
49
+
50
+ // Parses queue/topic name from AWS queue URL
51
+ function getQueueNameFromRequest(request) {
52
+ const unknown = 'unknown';
53
+ if (!request || !request.params || !request.params.QueueUrl) {
54
+ return unknown;
55
+ }
56
+ try {
57
+ const url = new URL(request.params.QueueUrl);
58
+ return url.pathname.split('/').pop();
59
+ } catch (e) {
60
+ return unknown;
61
+ }
62
+ }
63
+
64
+ // Parses region name from AWS service configuration
65
+ function getRegionFromRequest(request) {
66
+ const region =
67
+ request &&
68
+ request.service &&
69
+ request.service.config &&
70
+ request.service.config.region;
71
+ return region || '';
72
+ }
73
+
74
+ function getAddressFromRequest(request) {
75
+ return (
76
+ request &&
77
+ request.service &&
78
+ request.service.endpoint &&
79
+ request.service.endpoint.hostname
80
+ );
81
+ }
82
+
83
+ function getPortFromRequest(request) {
84
+ return (
85
+ request &&
86
+ request.service &&
87
+ request.service.endpoint &&
88
+ request.service.endpoint.port
89
+ );
90
+ }
91
+
92
+ // Creates message destination context suitable for setDestinationContext
93
+ function getMessageDestinationContextFromRequest(request) {
94
+ const destination = {
95
+ address: getAddressFromRequest(request),
96
+ port: getPortFromRequest(request),
97
+ cloud: {
98
+ region: getRegionFromRequest(request),
99
+ },
100
+ };
101
+ return destination;
102
+ }
103
+
104
+ // create message context suitable for setMessageContext
105
+ function getMessageContextFromRequest(request) {
106
+ const message = {
107
+ queue: {
108
+ name: getQueueNameFromRequest(request),
109
+ },
110
+ };
111
+ return message;
112
+ }
113
+
114
+ // Record queue related metrics
115
+ //
116
+ // Creates metric collector objects on first run, and
117
+ // updates their data with data from received messages
118
+ function recordMetrics(queueName, data, agent) {
119
+ const messages = data && data.Messages;
120
+ if (!messages || messages.length < 1) {
121
+ return;
122
+ }
123
+ if (!queueMetrics.get(queueName)) {
124
+ const collector = agent._metrics.createQueueMetricsCollector(queueName);
125
+ if (!collector) {
126
+ return;
127
+ }
128
+ queueMetrics.set(queueName, collector);
129
+ }
130
+ const metrics = queueMetrics.get(queueName);
131
+
132
+ for (const message of messages) {
133
+ const sentTimestamp =
134
+ message.Attributes && message.Attributes.SentTimestamp;
135
+ const delay = new Date().getTime() - sentTimestamp;
136
+ metrics.updateStats(delay);
137
+ }
138
+ }
139
+
140
+ // Creates the span name from request information
141
+ function getSpanNameFromRequest(request) {
142
+ const action = getActionFromRequest(request);
143
+ const toFrom = getToFromFromOperation(request.operation);
144
+ const queueName = getQueueNameFromRequest(request);
145
+
146
+ const name = `${SUBTYPE.toUpperCase()} ${action.toUpperCase()} ${toFrom} ${queueName}`;
147
+ return name;
148
+ }
149
+
150
+ // Extract span links from up to 1000 messages in this batch.
151
+ // https://github.com/elastic/apm/blob/main/specs/agents/tracing-instrumentation-messaging.md#receiving-trace-context
152
+ //
153
+ // A span link is created from a `traceparent` message attribute in a message.
154
+ // `msg.messageAttributes` is of the form:
155
+ // { <attribute-name>: { DataType: <attr-type>, StringValue: <attr-value>, ... } }
156
+ // For example:
157
+ // { traceparent: { DataType: 'String', StringValue: 'test-traceparent' } }
158
+ function getSpanLinksFromResponseData(data) {
159
+ if (!data || !data.Messages || data.Messages.length === 0) {
160
+ return null;
161
+ }
162
+ const links = [];
163
+ const limit = Math.min(
164
+ data.Messages.length,
165
+ MAX_MESSAGES_PROCESSED_FOR_TRACE_CONTEXT,
166
+ );
167
+ for (let i = 0; i < limit; i++) {
168
+ const attrs = data.Messages[i].MessageAttributes;
169
+ if (!attrs) {
170
+ continue;
171
+ }
172
+
173
+ let traceparent;
174
+ const attrNames = Object.keys(attrs);
175
+ for (let j = 0; j < attrNames.length; j++) {
176
+ const attrVal = attrs[attrNames[j]];
177
+ if (attrVal.DataType !== 'String') {
178
+ continue;
179
+ }
180
+ const attrNameLc = attrNames[j].toLowerCase();
181
+ if (attrNameLc === 'traceparent') {
182
+ traceparent = attrVal.StringValue;
183
+ break;
184
+ }
185
+ }
186
+ if (traceparent) {
187
+ links.push({ context: traceparent });
188
+ }
189
+ }
190
+ return links;
191
+ }
192
+
193
+ function shouldIgnoreRequest(request, agent) {
194
+ const operation = request && request.operation;
195
+ // are we interested in this operation/method call?
196
+ if (OPERATIONS.indexOf(operation) === -1) {
197
+ return true;
198
+ }
199
+
200
+ // is the named queue on our ignore list?
201
+ if (agent._conf && agent._conf.ignoreMessageQueuesRegExp) {
202
+ const queueName = getQueueNameFromRequest(request);
203
+ for (const rule of agent._conf.ignoreMessageQueuesRegExp) {
204
+ if (rule.test(queueName)) {
205
+ return true;
206
+ }
207
+ }
208
+ }
209
+
210
+ return false;
211
+ }
212
+
213
+ function propagateTraceContextInMessageAttributes(
214
+ parentSpan,
215
+ msgParams,
216
+ log,
217
+ queueUrl,
218
+ ) {
219
+ const msgAttrs = msgParams.MessageAttributes;
220
+ if (
221
+ msgAttrs &&
222
+ Object.keys(msgAttrs).length + 2 > MAX_SQS_MESSAGE_ATTRIBUTES
223
+ ) {
224
+ log.warn(
225
+ { QueueUrl: queueUrl },
226
+ 'cannot propagate trace-context with SQS message, too many MessageAttributes',
227
+ );
228
+ } else {
229
+ parentSpan.propagateTraceContextHeaders(
230
+ msgAttrs,
231
+ function (msgAttrs, name, value) {
232
+ if (name.startsWith('elastic-')) {
233
+ return;
234
+ }
235
+ msgAttrs[name] = { DataType: 'String', StringValue: value };
236
+ },
237
+ );
238
+ }
239
+ }
240
+
241
+ // Main entrypoint for SQS instrumentation
242
+ //
243
+ // Must call (or one of its function calls must call) the
244
+ // `orig` function/method
245
+ function instrumentationSqs(
246
+ orig,
247
+ origArguments,
248
+ request,
249
+ AWS,
250
+ agent,
251
+ { version, enabled },
252
+ ) {
253
+ if (shouldIgnoreRequest(request, agent)) {
254
+ return orig.apply(request, origArguments);
255
+ }
256
+
257
+ const ins = agent._instrumentation;
258
+ const log = agent.logger;
259
+ const action = getActionFromRequest(request);
260
+ const name = getSpanNameFromRequest(request);
261
+ const parentRunContext = ins.currRunContext();
262
+ const span = ins.createSpan(name, TYPE, SUBTYPE, action, { exitSpan: true });
263
+
264
+ // W3C trace-context propagation.
265
+ const parent =
266
+ span || parentRunContext.currSpan() || parentRunContext.currTransaction();
267
+ if (parent) {
268
+ if (!request.params || typeof request.params !== 'object') {
269
+ // Pass. This is a sanity guard against bogus user input.
270
+ } else if (request.operation === 'sendMessage') {
271
+ const paramsCopy = Object.assign({}, request.params);
272
+ paramsCopy.MessageAttributes = Object.assign(
273
+ {},
274
+ paramsCopy.MessageAttributes,
275
+ );
276
+ request.params = paramsCopy;
277
+ propagateTraceContextInMessageAttributes(
278
+ parent,
279
+ request.params,
280
+ log,
281
+ request.params.QueueUrl,
282
+ );
283
+ } else if (
284
+ request.operation === 'sendMessageBatch' &&
285
+ Array.isArray(request.params.Entries)
286
+ ) {
287
+ const paramsCopy = Object.assign({}, request.params);
288
+ paramsCopy.Entries = paramsCopy.Entries.map((msgParams) => {
289
+ const msgParamsCopy = Object.assign({}, msgParams);
290
+ msgParamsCopy.MessageAttributes = Object.assign(
291
+ {},
292
+ msgParamsCopy.MessageAttributes,
293
+ );
294
+ propagateTraceContextInMessageAttributes(
295
+ parent,
296
+ msgParamsCopy,
297
+ log,
298
+ request.params.QueueUrl,
299
+ );
300
+ return msgParamsCopy;
301
+ });
302
+ request.params = paramsCopy;
303
+ }
304
+ }
305
+
306
+ if (!span) {
307
+ return orig.apply(request, origArguments);
308
+ }
309
+
310
+ span._setDestinationContext(getMessageDestinationContextFromRequest(request));
311
+ span.setMessageContext(getMessageContextFromRequest(request));
312
+
313
+ const onComplete = function (response) {
314
+ if (response && response.error) {
315
+ agent.captureError(response.error);
316
+ }
317
+
318
+ const receiveMsgData =
319
+ request.operation === 'receiveMessage' && response && response.data;
320
+ if (receiveMsgData) {
321
+ const links = getSpanLinksFromResponseData(receiveMsgData);
322
+ if (links) {
323
+ span.addLinks(links);
324
+ }
325
+ }
326
+
327
+ span.end();
328
+
329
+ if (receiveMsgData) {
330
+ recordMetrics(getQueueNameFromRequest(request), receiveMsgData, agent);
331
+ }
332
+ };
333
+ // Bind onComplete to the span's run context so that `captureError` picks
334
+ // up the correct currentSpan.
335
+ const spanRunContext = parentRunContext.enterSpan(span);
336
+ request.on(
337
+ 'complete',
338
+ ins.bindFunctionToRunContext(spanRunContext, onComplete),
339
+ );
340
+
341
+ const cb = origArguments[origArguments.length - 1];
342
+ if (typeof cb === 'function') {
343
+ origArguments[origArguments.length - 1] = ins.bindFunctionToRunContext(
344
+ parentRunContext,
345
+ cb,
346
+ );
347
+ }
348
+ return ins.withRunContext(spanRunContext, orig, request, ...origArguments);
349
+ }
350
+
351
+ module.exports = {
352
+ instrumentationSqs,
353
+
354
+ // exported for tests
355
+ getToFromFromOperation,
356
+ getActionFromRequest,
357
+ getQueueNameFromRequest,
358
+ getRegionFromRequest,
359
+ getMessageDestinationContextFromRequest,
360
+ shouldIgnoreRequest,
361
+ };
@@ -0,0 +1,76 @@
1
+ /*
2
+ * Copyright Elasticsearch B.V. and other contributors where applicable.
3
+ * Licensed under the BSD 2-Clause License; you may not use this file except in
4
+ * compliance with the BSD 2-Clause License.
5
+ */
6
+
7
+ 'use strict';
8
+ const semver = require('semver');
9
+ const shimmer = require('../shimmer');
10
+ const { instrumentationS3 } = require('./aws-sdk/s3');
11
+ const { instrumentationSqs } = require('./aws-sdk/sqs');
12
+ const { instrumentationDynamoDb } = require('./aws-sdk/dynamodb.js');
13
+ const { instrumentationSns } = require('./aws-sdk/sns.js');
14
+
15
+ const instrumentorFromSvcId = {
16
+ s3: instrumentationS3,
17
+ sqs: instrumentationSqs,
18
+ dynamodb: instrumentationDynamoDb,
19
+ sns: instrumentationSns,
20
+ };
21
+
22
+ // Called in place of AWS.Request.send and AWS.Request.promise
23
+ //
24
+ // Determines which amazon service an API request is for
25
+ // and then passes call on to an appropriate instrumentation
26
+ // function.
27
+ function instrumentOperation(
28
+ orig,
29
+ origArguments,
30
+ request,
31
+ AWS,
32
+ agent,
33
+ { version, enabled },
34
+ ) {
35
+ const instrumentor = instrumentorFromSvcId[request.service.serviceIdentifier];
36
+ if (instrumentor) {
37
+ return instrumentor(orig, origArguments, request, AWS, agent, {
38
+ version,
39
+ enabled,
40
+ });
41
+ }
42
+
43
+ // if we're still here, then we still need to call the original method
44
+ return orig.apply(request, origArguments);
45
+ }
46
+
47
+ // main entry point for aws-sdk instrumentation
48
+ module.exports = function (AWS, agent, { version, enabled }) {
49
+ if (!enabled) return AWS;
50
+ if (!semver.satisfies(version, '>1 <3')) {
51
+ agent.logger.debug(
52
+ 'aws-sdk version %s not supported - aborting...',
53
+ version,
54
+ );
55
+ return AWS;
56
+ }
57
+
58
+ shimmer.wrap(AWS.Request.prototype, 'send', function (orig) {
59
+ return function _wrappedAWSRequestSend() {
60
+ return instrumentOperation(orig, arguments, this, AWS, agent, {
61
+ version,
62
+ enabled,
63
+ });
64
+ };
65
+ });
66
+
67
+ shimmer.wrap(AWS.Request.prototype, 'promise', function (orig) {
68
+ return function _wrappedAWSRequestPromise() {
69
+ return instrumentOperation(orig, arguments, this, AWS, agent, {
70
+ version,
71
+ enabled,
72
+ });
73
+ };
74
+ });
75
+ return AWS;
76
+ };
@@ -0,0 +1,93 @@
1
+ /*
2
+ * Copyright Elasticsearch B.V. and other contributors where applicable.
3
+ * Licensed under the BSD 2-Clause License; you may not use this file except in
4
+ * compliance with the BSD 2-Clause License.
5
+ */
6
+
7
+ 'use strict';
8
+
9
+ var semver = require('semver');
10
+
11
+ var shimmer = require('../shimmer');
12
+
13
+ var massWrap = shimmer.massWrap;
14
+ var wrap = shimmer.wrap;
15
+
16
+ var BLUEBIRD_FNS = ['_then', '_addCallbacks'];
17
+
18
+ module.exports = function (bluebird, agent, { version }) {
19
+ var ins = agent._instrumentation;
20
+
21
+ if (!semver.satisfies(version, '>=2 <4')) {
22
+ agent.logger.debug(
23
+ 'bluebird version %s not supported - aborting...',
24
+ version,
25
+ );
26
+ return bluebird;
27
+ }
28
+
29
+ agent.logger.debug('shimming bluebird.prototype functions: %j', BLUEBIRD_FNS);
30
+ massWrap(bluebird.prototype, BLUEBIRD_FNS, wrapThen);
31
+
32
+ // Calling bluebird.config might overwrite the
33
+ // bluebird.prototype._attachCancellationCallback function with a new
34
+ // function. We need to hook into this new function
35
+ agent.logger.debug('shimming bluebird.config');
36
+ wrap(bluebird, 'config', function wrapConfig(original) {
37
+ return function wrappedConfig() {
38
+ var result = original.apply(this, arguments);
39
+
40
+ agent.logger.debug(
41
+ 'shimming bluebird.prototype._attachCancellationCallback',
42
+ );
43
+ wrap(
44
+ bluebird.prototype,
45
+ '_attachCancellationCallback',
46
+ function wrapAttachCancellationCallback(original) {
47
+ return function wrappedAttachCancellationCallback(onCancel) {
48
+ if (arguments.length !== 1) return original.apply(this, arguments);
49
+ return original.call(this, ins.bindFunction(onCancel));
50
+ };
51
+ },
52
+ );
53
+
54
+ return result;
55
+ };
56
+ });
57
+
58
+ // WARNING: even if you remove these two shims, the tests might still pass
59
+ // for bluebird@2. The tests are flaky and will only fail sometimes and in
60
+ // some cases only if run together with the other tests.
61
+ //
62
+ // To test, run in a while-loop:
63
+ //
64
+ // while :; do node test/instrumentation/modules/bluebird/bluebird.js || exit $?; done
65
+ if (semver.satisfies(version, '<3')) {
66
+ agent.logger.debug('shimming bluebird.each');
67
+ wrap(bluebird, 'each', function wrapEach(original) {
68
+ return function wrappedEach(promises, fn) {
69
+ if (arguments.length !== 2) return original.apply(this, arguments);
70
+ return original.call(this, promises, ins.bindFunction(fn));
71
+ };
72
+ });
73
+
74
+ agent.logger.debug('shimming bluebird.prototype.each');
75
+ wrap(bluebird.prototype, 'each', function wrapEach(original) {
76
+ return function wrappedEach(fn) {
77
+ if (arguments.length !== 1) return original.apply(this, arguments);
78
+ return original.call(this, ins.bindFunction(fn));
79
+ };
80
+ });
81
+ }
82
+
83
+ return bluebird;
84
+
85
+ function wrapThen(original) {
86
+ return function wrappedThen() {
87
+ var args = Array.prototype.slice.call(arguments);
88
+ if (typeof args[0] === 'function') args[0] = ins.bindFunction(args[0]);
89
+ if (typeof args[1] === 'function') args[1] = ins.bindFunction(args[1]);
90
+ return original.apply(this, args);
91
+ };
92
+ }
93
+ };