dd-trace 2.0.0-appsec-beta.3 → 2.0.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 (91) hide show
  1. package/MIGRATING.md +65 -0
  2. package/NOTICE +4 -0
  3. package/ci/cypress/plugin.js +3 -0
  4. package/ci/cypress/support.js +1 -0
  5. package/ci/init.js +13 -0
  6. package/ci/jest/env.js +14 -0
  7. package/index.d.ts +35 -48
  8. package/package.json +7 -4
  9. package/packages/datadog-instrumentations/index.js +10 -0
  10. package/packages/datadog-instrumentations/src/bluebird.js +26 -0
  11. package/packages/datadog-instrumentations/src/dns.js +94 -0
  12. package/packages/datadog-instrumentations/src/helpers/instrument.js +120 -0
  13. package/packages/datadog-instrumentations/src/helpers/promise.js +29 -0
  14. package/packages/datadog-instrumentations/src/memcached.js +53 -0
  15. package/packages/datadog-instrumentations/src/mysql.js +67 -0
  16. package/packages/datadog-instrumentations/src/promise-js.js +15 -0
  17. package/packages/datadog-instrumentations/src/promise.js +14 -0
  18. package/packages/datadog-instrumentations/src/q.js +13 -0
  19. package/packages/datadog-instrumentations/src/when.js +14 -0
  20. package/packages/datadog-plugin-cucumber/src/index.js +4 -4
  21. package/packages/datadog-plugin-cypress/src/plugin.js +12 -2
  22. package/packages/datadog-plugin-cypress/src/support.js +21 -6
  23. package/packages/datadog-plugin-dns/src/index.js +65 -178
  24. package/packages/datadog-plugin-fs/src/index.js +7 -3
  25. package/packages/datadog-plugin-http/src/client.js +9 -24
  26. package/packages/datadog-plugin-http/src/server.js +5 -0
  27. package/packages/datadog-plugin-http2/src/client.js +1 -24
  28. package/packages/datadog-plugin-http2/src/server.js +2 -2
  29. package/packages/datadog-plugin-jest/src/jest-environment.js +4 -4
  30. package/packages/datadog-plugin-jest/src/jest-jasmine2.js +2 -2
  31. package/packages/datadog-plugin-knex/src/index.js +3 -3
  32. package/packages/datadog-plugin-memcached/src/index.js +41 -63
  33. package/packages/datadog-plugin-mocha/src/index.js +3 -2
  34. package/packages/datadog-plugin-moleculer/src/client.js +60 -0
  35. package/packages/datadog-plugin-moleculer/src/index.js +8 -0
  36. package/packages/datadog-plugin-moleculer/src/server.js +61 -0
  37. package/packages/datadog-plugin-moleculer/src/util.js +21 -0
  38. package/packages/datadog-plugin-mongoose/src/index.js +2 -2
  39. package/packages/datadog-plugin-mysql/src/index.js +37 -89
  40. package/packages/datadog-plugin-net/src/index.js +5 -0
  41. package/packages/datadog-plugin-pino/src/index.js +25 -1
  42. package/packages/datadog-plugin-redis/src/index.js +31 -1
  43. package/packages/datadog-plugin-router/src/index.js +28 -3
  44. package/packages/dd-trace/lib/version.js +1 -1
  45. package/packages/dd-trace/src/appsec/addresses.js +11 -4
  46. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +5 -8
  47. package/packages/dd-trace/src/{gateway → appsec/gateway}/als.js +1 -0
  48. package/packages/dd-trace/src/appsec/gateway/channels.js +11 -0
  49. package/packages/dd-trace/src/{gateway → appsec/gateway}/engine/engine.js +20 -30
  50. package/packages/dd-trace/src/{gateway → appsec/gateway}/engine/index.js +0 -0
  51. package/packages/dd-trace/src/{gateway → appsec/gateway}/engine/runner.js +2 -0
  52. package/packages/dd-trace/src/appsec/index.js +54 -38
  53. package/packages/dd-trace/src/appsec/recommended.json +1 -1
  54. package/packages/dd-trace/src/appsec/reporter.js +27 -10
  55. package/packages/dd-trace/src/config.js +31 -27
  56. package/packages/dd-trace/src/constants.js +6 -3
  57. package/packages/dd-trace/src/exporters/agent/request.js +8 -0
  58. package/packages/dd-trace/src/format.js +26 -39
  59. package/packages/dd-trace/src/instrumenter.js +6 -1
  60. package/packages/dd-trace/src/log.js +6 -15
  61. package/packages/dd-trace/src/noop/span_context.js +0 -1
  62. package/packages/dd-trace/src/noop/tracer.js +0 -6
  63. package/packages/dd-trace/src/opentracing/propagation/text_map.js +79 -46
  64. package/packages/dd-trace/src/opentracing/span.js +2 -7
  65. package/packages/dd-trace/src/opentracing/span_context.js +2 -4
  66. package/packages/dd-trace/src/opentracing/tracer.js +5 -23
  67. package/packages/dd-trace/src/plugin_manager.js +65 -0
  68. package/packages/dd-trace/src/plugins/index.js +1 -5
  69. package/packages/dd-trace/src/plugins/plugin.js +63 -0
  70. package/packages/dd-trace/src/plugins/util/ci.js +13 -4
  71. package/packages/dd-trace/src/plugins/util/redis.js +0 -2
  72. package/packages/dd-trace/src/plugins/util/test.js +9 -4
  73. package/packages/dd-trace/src/plugins/util/user-provided-git.js +17 -2
  74. package/packages/dd-trace/src/plugins/util/web.js +6 -16
  75. package/packages/dd-trace/src/priority_sampler.js +71 -19
  76. package/packages/dd-trace/src/profiling/exporters/agent.js +35 -34
  77. package/packages/dd-trace/src/proxy.js +39 -35
  78. package/packages/dd-trace/src/ritm.js +40 -16
  79. package/packages/dd-trace/src/span_processor.js +0 -7
  80. package/packages/dd-trace/src/tracer.js +5 -6
  81. package/scripts/install_plugin_modules.js +30 -1
  82. package/packages/datadog-plugin-bluebird/src/index.js +0 -69
  83. package/packages/datadog-plugin-promise/src/index.js +0 -17
  84. package/packages/datadog-plugin-promise-js/src/index.js +0 -20
  85. package/packages/datadog-plugin-q/src/index.js +0 -16
  86. package/packages/datadog-plugin-when/src/index.js +0 -17
  87. package/packages/dd-trace/src/gateway/channels.js +0 -8
  88. package/packages/dd-trace/src/gateway/dc_block.js +0 -68
  89. package/packages/dd-trace/src/plugins/util/ci-app-spec.json +0 -36
  90. package/packages/dd-trace/src/plugins/util/promise.js +0 -31
  91. package/packages/dd-trace/src/scope/noop/scope_manager.js +0 -28
package/MIGRATING.md ADDED
@@ -0,0 +1,65 @@
1
+ # Migrating
2
+
3
+ This guide describes the steps to upgrade dd-trace from a major version to the
4
+ next. If you are having any issues related to migrating, please feel free to
5
+ open an issue or contact our [support](https://www.datadoghq.com/support/) team.
6
+
7
+ ## 1.0 to 2.0
8
+
9
+ ### Configuration
10
+
11
+ The following configuraton options are no longer available programmatically and
12
+ must be configured using these environment variables:
13
+
14
+ * `enabled` -> `DD_TRACE_ENABLED=true|false`
15
+ * `debug` -> `DD_TRACE_DEBUG=true|false`
16
+
17
+ If environment variables were already used for these options, no action is
18
+ needed.
19
+
20
+ The following configuration options were completely removed and will no longer
21
+ have any effect:
22
+
23
+ * `scope`
24
+
25
+ Startup logs are now disabled by default and can be enabled if needed with
26
+ `DD_TRACE_STARTUP_LOGS=true`.
27
+
28
+ ### Removed APIs
29
+
30
+ The original scope manager has been replaced several years ago and has now been
31
+ removed. Any code referencing `tracer.scopeManager()` should be removed or
32
+ replaced with `tracer.scope()` which is documented
33
+ [here](https://datadoghq.dev/dd-trace-js/#scope-manager).
34
+
35
+ ### Nested objects as tags
36
+
37
+ Support for nested objects as tags as been removed. When adding an object as a
38
+ tag value, only properties that exist on that object directly will be added as
39
+ tags. If nested properties are also needed, these should be added by hand.
40
+
41
+ For example:
42
+
43
+ ```js
44
+ const obj = {
45
+ a: 'foo',
46
+ b: {
47
+ c: 'bar'
48
+ }
49
+ }
50
+
51
+ // 1.0
52
+ span.setTag('test', obj) // add test.a and test.b.c
53
+
54
+ // 2.0
55
+ span.setTag('test', obj) // add test.a
56
+ span.setTag('test.b', obj.b) // add test.b.c
57
+ ```
58
+
59
+ Arrays are no longer supported and must be converted to string manually.
60
+
61
+ ### Outgoing request filtering
62
+
63
+ Outgoing request filtering is no longer supported and is now only available for
64
+ incoming requests. This means that the `blocklist` and `allowlist` options on
65
+ the `http` integration no longer have any effect.
package/NOTICE ADDED
@@ -0,0 +1,4 @@
1
+ Datadog dd-trace-js
2
+ Copyright 2016-Present Datadog, Inc.
3
+
4
+ This product includes software developed at Datadog, Inc. (https://www.datadoghq.com/).
@@ -0,0 +1,3 @@
1
+ require('../init')
2
+
3
+ module.exports = require('../../packages/datadog-plugin-cypress/src/plugin')
@@ -0,0 +1 @@
1
+ require('../../packages/datadog-plugin-cypress/src/support')
package/ci/init.js ADDED
@@ -0,0 +1,13 @@
1
+ const tracer = require('../packages/dd-trace')
2
+ const { ORIGIN_KEY } = require('../packages/dd-trace/src/constants')
3
+
4
+ tracer.init({
5
+ startupLogs: false,
6
+ tags: {
7
+ [ORIGIN_KEY]: 'ciapp-test'
8
+ }
9
+ })
10
+
11
+ tracer.use('fs', false)
12
+
13
+ module.exports = tracer
package/ci/jest/env.js ADDED
@@ -0,0 +1,14 @@
1
+ const tracer = require('../../packages/dd-trace')
2
+ const { ORIGIN_KEY } = require('../../packages/dd-trace/src/constants')
3
+
4
+ tracer.init({
5
+ startupLogs: false,
6
+ flushInterval: 400000,
7
+ tags: {
8
+ [ORIGIN_KEY]: 'ciapp-test'
9
+ }
10
+ })
11
+
12
+ tracer.use('fs', false)
13
+
14
+ module.exports = tracer
package/index.d.ts CHANGED
@@ -268,8 +268,7 @@ export declare interface TracerOptions {
268
268
  version?: string;
269
269
 
270
270
  /**
271
- * Percentage of spans to sample as a float between 0 and 1.
272
- * @default 1
271
+ * Controls the ingestion sample rate (between 0 and 1) between the agent and the backend.
273
272
  */
274
273
  sampleRate?: number;
275
274
 
@@ -358,12 +357,6 @@ export declare interface TracerOptions {
358
357
  * @default false
359
358
  */
360
359
  enableGetRumData?: boolean
361
-
362
- /**
363
- * Whether to set the error flag when an error occurs in an internal span.
364
- * @default false
365
- */
366
- internalErrors?: boolean
367
360
  };
368
361
 
369
362
  /**
@@ -476,7 +469,6 @@ interface Plugins {
476
469
  "amqp10": plugins.amqp10;
477
470
  "amqplib": plugins.amqplib;
478
471
  "aws-sdk": plugins.aws_sdk;
479
- "bluebird": plugins.bluebird;
480
472
  "bunyan": plugins.bunyan;
481
473
  "cassandra-driver": plugins.cassandra_driver;
482
474
  "connect": plugins.connect;
@@ -504,6 +496,7 @@ interface Plugins {
504
496
  "memcached": plugins.memcached;
505
497
  "microgateway-core": plugins.microgateway_core;
506
498
  "mocha": plugins.mocha;
499
+ "moleculer": plugins.moleculer;
507
500
  "mongodb-core": plugins.mongodb_core;
508
501
  "mongoose": plugins.mongoose;
509
502
  "mysql": plugins.mysql;
@@ -514,16 +507,12 @@ interface Plugins {
514
507
  "paperplane": plugins.paperplane;
515
508
  "pg": plugins.pg;
516
509
  "pino": plugins.pino;
517
- "promise-js": plugins.promise_js;
518
- "promise": plugins.promise;
519
- "q": plugins.q;
520
510
  "redis": plugins.redis;
521
511
  "restify": plugins.restify;
522
512
  "rhea": plugins.rhea;
523
513
  "router": plugins.router;
524
514
  "sharedb": plugins.sharedb;
525
515
  "tedious": plugins.tedious;
526
- "when": plugins.when;
527
516
  "winston": plugins.winston;
528
517
  }
529
518
 
@@ -707,6 +696,16 @@ declare namespace plugins {
707
696
  metadata?: string[] | ((variables: { [key: string]: any }) => { [key: string]: any });
708
697
  }
709
698
 
699
+ /** @hidden */
700
+ interface Moleculer extends Instrumentation {
701
+ /**
702
+ * Whether to include context meta as tags.
703
+ *
704
+ * @default false
705
+ */
706
+ meta?: boolean;
707
+ }
708
+
710
709
  /**
711
710
  * This plugin automatically instruments the
712
711
  * [amqp10](https://github.com/noodlefrenzy/node-amqp10) module.
@@ -750,12 +749,6 @@ declare namespace plugins {
750
749
  [key: string]: boolean | Object | undefined;
751
750
  }
752
751
 
753
- /**
754
- * This plugin patches the [bluebird](https://github.com/petkaantonov/bluebird)
755
- * module to bind the promise callback the the caller context.
756
- */
757
- interface bluebird extends Integration {}
758
-
759
752
  /**
760
753
  * This plugin patches the [bunyan](https://github.com/trentm/node-bunyan)
761
754
  * to automatically inject trace identifiers in log records when the
@@ -786,7 +779,7 @@ declare namespace plugins {
786
779
  * This plugin automatically instruments the
787
780
  * [cucumber](https://www.npmjs.com/package/@cucumber/cucumber) module.
788
781
  */
789
- interface cucumber extends Instrumentation {}
782
+ interface cucumber extends Integration {}
790
783
 
791
784
  /**
792
785
  * This plugin automatically instruments the
@@ -972,12 +965,12 @@ declare namespace plugins {
972
965
  /**
973
966
  * Configuration for HTTP clients.
974
967
  */
975
- client?: HttpClient,
968
+ client?: HttpClient | boolean,
976
969
 
977
970
  /**
978
971
  * Configuration for HTTP servers.
979
972
  */
980
- server?: HttpServer
973
+ server?: HttpServer | boolean
981
974
 
982
975
  /**
983
976
  * Hooks to run before spans are finished.
@@ -1006,12 +999,12 @@ declare namespace plugins {
1006
999
  /**
1007
1000
  * Configuration for HTTP clients.
1008
1001
  */
1009
- client?: Http2Client,
1002
+ client?: Http2Client | boolean,
1010
1003
 
1011
1004
  /**
1012
1005
  * Configuration for HTTP servers.
1013
1006
  */
1014
- server?: Http2Server
1007
+ server?: Http2Server | boolean
1015
1008
  }
1016
1009
 
1017
1010
  /**
@@ -1107,6 +1100,24 @@ declare namespace plugins {
1107
1100
  */
1108
1101
  interface mocha extends Integration {}
1109
1102
 
1103
+ /**
1104
+ * This plugin automatically instruments the
1105
+ * [moleculer](https://moleculer.services/) module.
1106
+ */
1107
+ interface moleculer extends Moleculer {
1108
+ /**
1109
+ * Configuration for Moleculer clients. Set to false to disable client
1110
+ * instrumentation.
1111
+ */
1112
+ client?: boolean | Moleculer;
1113
+
1114
+ /**
1115
+ * Configuration for Moleculer servers. Set to false to disable server
1116
+ * instrumentation.
1117
+ */
1118
+ server?: boolean | Moleculer;
1119
+ }
1120
+
1110
1121
  /**
1111
1122
  * This plugin automatically instruments the
1112
1123
  * [mongodb-core](https://github.com/mongodb-js/mongodb-core) module.
@@ -1189,24 +1200,6 @@ declare namespace plugins {
1189
1200
  */
1190
1201
  interface pino extends Integration {}
1191
1202
 
1192
- /**
1193
- * This plugin patches the [promise-js](https://github.com/kevincennis/promise)
1194
- * module to bind the promise callback the the caller context.
1195
- */
1196
- interface promise_js extends Integration {}
1197
-
1198
- /**
1199
- * This plugin patches the [promise](https://github.com/then/promise)
1200
- * module to bind the promise callback the the caller context.
1201
- */
1202
- interface promise extends Integration {}
1203
-
1204
- /**
1205
- * This plugin patches the [q](https://github.com/kriskowal/q)
1206
- * module to bind the promise callback the the caller context.
1207
- */
1208
- interface q extends Integration {}
1209
-
1210
1203
  /**
1211
1204
  * This plugin automatically instruments the
1212
1205
  * [redis](https://github.com/NodeRedis/node_redis) module.
@@ -1289,12 +1282,6 @@ declare namespace plugins {
1289
1282
  */
1290
1283
  interface tedious extends Instrumentation {}
1291
1284
 
1292
- /**
1293
- * This plugin patches the [when](https://github.com/cujojs/when)
1294
- * module to bind the promise callback the the caller context.
1295
- */
1296
- interface when extends Integration {}
1297
-
1298
1285
  /**
1299
1286
  * This plugin patches the [winston](https://github.com/winstonjs/winston)
1300
1287
  * to automatically inject trace identifiers in log records when the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "2.0.0-appsec-beta.3",
3
+ "version": "2.0.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -10,6 +10,7 @@
10
10
  "bench": "node benchmark",
11
11
  "bench:profiler": "node benchmark/profiler",
12
12
  "bench:e2e": "SERVICES=mongo yarn services && cd benchmark/e2e && node benchmark-run.js --duration=30",
13
+ "bench:e2e:ci-visibility": "node benchmark/e2e-ci/benchmark-run.js",
13
14
  "type:doc": "cd docs && yarn && yarn build",
14
15
  "type:test": "cd docs && yarn && yarn test",
15
16
  "lint": "node scripts/check_licenses.js && eslint . && yarn audit --groups dependencies",
@@ -18,6 +19,8 @@
18
19
  "test": "SERVICES=* yarn services && mocha --exit --expose-gc 'packages/dd-trace/test/setup/node.js' 'packages/*/test/**/*.spec.js'",
19
20
  "test:trace:core": "mocha --exit --expose-gc --file packages/dd-trace/test/setup/core.js \"packages/dd-trace/test/**/*.spec.js\"",
20
21
  "test:trace:core:ci": "nyc --include \"packages/dd-trace/src/**/*.js\" -- npm run test:trace:core -- --reporter mocha-multi-reporters --reporter-options configFile=mocha-reporter-config.json",
22
+ "test:instrumentations": "mocha --file 'packages/dd-trace/test/setup/core.js' 'packages/datadog-instrumentations/test/**/*.spec.js'",
23
+ "test:instrumentations:ci": "nyc --include 'packages/datadog-instrumentations/src/**/*.js' -- npm run test:instrumentations -- --reporter mocha-multi-reporters --reporter-options configFile=mocha-reporter-config.json",
21
24
  "test:core": "mocha --file packages/datadog-core/test/setup.js 'packages/datadog-core/test/**/*.spec.js'",
22
25
  "test:core:ci": "nyc --include 'packages/datadog-core/src/**/*.js' -- npm run test:core -- --reporter mocha-multi-reporters --reporter-options configFile=mocha-reporter-config.json",
23
26
  "test:plugins": "mocha --exit --file \"packages/dd-trace/test/setup/core.js\" \"packages/datadog-plugin-@($(echo $PLUGINS))/test/**/*.spec.js\"",
@@ -58,11 +61,11 @@
58
61
  "node": ">=12"
59
62
  },
60
63
  "dependencies": {
61
- "@datadog/native-appsec": "^0.6.1",
62
- "@datadog/native-metrics": "^1.0.1",
64
+ "@datadog/native-appsec": "^0.8.0",
65
+ "@datadog/native-metrics": "^1.1.0",
63
66
  "@datadog/pprof": "^0.3.0",
64
67
  "@datadog/sketches-js": "^1.0.4",
65
- "@types/node": "^10.12.18",
68
+ "@types/node": ">=12",
66
69
  "crypto-randomuuid": "^1.0.0",
67
70
  "diagnostics_channel": "^1.1.0",
68
71
  "form-data": "^3.0.0",
@@ -0,0 +1,10 @@
1
+ 'use strict'
2
+
3
+ require('./src/dns')
4
+ require('./src/memcached')
5
+ require('./src/mysql')
6
+ require('./src/bluebird')
7
+ require('./src/when')
8
+ require('./src/promise')
9
+ require('./src/q')
10
+ require('./src/promise-js')
@@ -0,0 +1,26 @@
1
+ 'use strict'
2
+
3
+ const { addHook } = require('./helpers/instrument')
4
+ const { wrapThen } = require('./helpers/promise')
5
+ const shimmer = require('../../datadog-shimmer')
6
+
7
+ function createGetNewLibraryCopyWrap (originalLib) {
8
+ return function wrapGetNewLibraryCopy (getNewLibraryCopy) {
9
+ return function getNewLibraryCopyWithTrace () {
10
+ const libraryCopy = getNewLibraryCopy.apply(this, arguments)
11
+ shimmer.wrap(libraryCopy.prototype, '_then', wrapThen)
12
+ shimmer.wrap(libraryCopy, 'getNewLibraryCopy', createGetNewLibraryCopyWrap(originalLib))
13
+ return libraryCopy
14
+ }
15
+ }
16
+ }
17
+
18
+ addHook({ name: 'bluebird', versions: ['>=2.0.2'] }, Promise => {
19
+ shimmer.wrap(Promise.prototype, '_then', wrapThen)
20
+ return Promise
21
+ })
22
+
23
+ addHook({ name: 'bluebird', versions: ['^2.11.0', '^3.4.1'] }, Promise => {
24
+ shimmer.wrap(Promise, 'getNewLibraryCopy', createGetNewLibraryCopyWrap(Promise))
25
+ return Promise
26
+ })
@@ -0,0 +1,94 @@
1
+ 'use strict'
2
+
3
+ const { channel, addHook, AsyncResource } = require('./helpers/instrument')
4
+ const shimmer = require('../../datadog-shimmer')
5
+
6
+ const rrtypes = {
7
+ resolveAny: 'ANY',
8
+ resolve4: 'A',
9
+ resolve6: 'AAAA',
10
+ resolveCname: 'CNAME',
11
+ resolveMx: 'MX',
12
+ resolveNs: 'NS',
13
+ resolveTxt: 'TXT',
14
+ resolveSrv: 'SRV',
15
+ resolvePtr: 'PTR',
16
+ resolveNaptr: 'NAPTR',
17
+ resolveSoa: 'SOA'
18
+ }
19
+
20
+ const rrtypeMap = new WeakMap()
21
+
22
+ addHook({ name: 'dns' }, dns => {
23
+ dns.lookup = wrap('apm:dns:lookup', dns.lookup, 2)
24
+ dns.lookupService = wrap('apm:dns:lookup_service', dns.lookupService, 3)
25
+ dns.resolve = wrap('apm:dns:resolve', dns.resolve, 2)
26
+ dns.reverse = wrap('apm:dns:reverse', dns.reverse, 2)
27
+
28
+ patchResolveShorthands(dns)
29
+
30
+ if (dns.Resolver) {
31
+ dns.Resolver.prototype.resolve = wrap('apm:dns:resolve', dns.Resolver.prototype.resolve, 2)
32
+ dns.Resolver.prototype.reverse = wrap('apm:dns:reverse', dns.Resolver.prototype.reverse, 2)
33
+
34
+ patchResolveShorthands(dns.Resolver.prototype)
35
+ }
36
+
37
+ return dns
38
+ })
39
+
40
+ function patchResolveShorthands (prototype) {
41
+ Object.keys(rrtypes)
42
+ .filter(method => !!prototype[method])
43
+ .forEach(method => {
44
+ rrtypeMap.set(prototype[method], rrtypes[method])
45
+ prototype[method] = wrap('apm:dns:resolve', prototype[method], 2, rrtypes[method])
46
+ })
47
+ }
48
+
49
+ function wrap (prefix, fn, expectedArgs, rrtype) {
50
+ const startCh = channel(prefix + ':start')
51
+ const endCh = channel(prefix + ':end')
52
+ const asyncEndCh = channel(prefix + ':async-end')
53
+ const errorCh = channel(prefix + ':error')
54
+
55
+ const wrapped = function () {
56
+ const cb = AsyncResource.bind(arguments[arguments.length - 1])
57
+ if (
58
+ !startCh.hasSubscribers ||
59
+ arguments.length < expectedArgs ||
60
+ typeof cb !== 'function'
61
+ ) {
62
+ return fn.apply(this, arguments)
63
+ }
64
+
65
+ const startArgs = Array.from(arguments)
66
+ startArgs.pop() // gets rid of the callback
67
+ if (rrtype) {
68
+ startArgs.push(rrtype)
69
+ }
70
+ startCh.publish(startArgs)
71
+
72
+ arguments[arguments.length - 1] = function (error, result) {
73
+ if (error) {
74
+ errorCh.publish(error)
75
+ }
76
+ asyncEndCh.publish(result)
77
+ cb.apply(this, arguments)
78
+ }
79
+
80
+ try {
81
+ return fn.apply(this, arguments)
82
+ // TODO deal with promise versions when we support `dns/promises`
83
+ } catch (error) {
84
+ error.stack // trigger getting the stack at the original throwing point
85
+ errorCh.publish(error)
86
+
87
+ throw error
88
+ } finally {
89
+ endCh.publish(undefined)
90
+ }
91
+ }
92
+
93
+ return shimmer.wrap(fn, wrapped)
94
+ }
@@ -0,0 +1,120 @@
1
+ 'use strict'
2
+
3
+ const dc = require('diagnostics_channel')
4
+ const path = require('path')
5
+ const semver = require('semver')
6
+ const iitm = require('../../../dd-trace/src/iitm')
7
+ const ritm = require('../../../dd-trace/src/ritm')
8
+ const parse = require('module-details-from-path')
9
+ const requirePackageJson = require('../../../dd-trace/src/require-package-json')
10
+ const { AsyncResource } = require('async_hooks')
11
+
12
+ const pathSepExpr = new RegExp(`\\${path.sep}`, 'g')
13
+ const channelMap = {}
14
+ exports.channel = function channel (name) {
15
+ const maybe = channelMap[name]
16
+ if (maybe) return maybe
17
+ const ch = dc.channel(name)
18
+ channelMap[name] = ch
19
+ return ch
20
+ }
21
+
22
+ exports.addHook = function addHook ({ name, versions, file }, hook) {
23
+ file = filename(name, file)
24
+ const loaderHook = (moduleExports, moduleName, moduleBaseDir) => {
25
+ moduleName = moduleName.replace(pathSepExpr, '/')
26
+ const moduleVersion = getVersion(moduleBaseDir)
27
+ if (moduleName !== file || !matchVersion(moduleVersion, versions)) {
28
+ return moduleExports
29
+ }
30
+ return hook(moduleExports)
31
+ }
32
+ ritm([name], loaderHook)
33
+ cjsPostLoad({ name, versions, file }, hook)
34
+ iitm([name], loaderHook)
35
+ }
36
+
37
+ function matchVersion (version, ranges) {
38
+ return !version || (ranges && ranges.some(range => semver.satisfies(semver.coerce(version), range)))
39
+ }
40
+
41
+ function getVersion (moduleBaseDir) {
42
+ if (moduleBaseDir) {
43
+ return requirePackageJson(moduleBaseDir, module).version
44
+ }
45
+ }
46
+
47
+ function filename (name, file) {
48
+ return [name, file].filter(val => val).join('/')
49
+ }
50
+
51
+ // TODO this is basically Loader#_getModules + running the hook. DRY up.
52
+ function cjsPostLoad (instrumentation, hook) {
53
+ const ids = Object.keys(require.cache)
54
+
55
+ let pkg
56
+
57
+ for (let i = 0, l = ids.length; i < l; i++) {
58
+ if (ids[i] === instrumentation.name) {
59
+ hook(require.cache[ids[i]].exports)
60
+ continue
61
+ }
62
+
63
+ const id = ids[i].replace(pathSepExpr, '/')
64
+
65
+ if (!id.includes(`/node_modules/${instrumentation.name}/`)) continue
66
+
67
+ if (instrumentation.file) {
68
+ if (!id.endsWith(`/node_modules/${filename(instrumentation)}`)) continue
69
+
70
+ const basedir = getBasedir(ids[i])
71
+
72
+ pkg = requirePackageJson(basedir, module)
73
+ } else {
74
+ const basedir = getBasedir(ids[i])
75
+
76
+ pkg = requirePackageJson(basedir, module)
77
+
78
+ const mainFile = path.posix.normalize(pkg.main || 'index.js')
79
+ if (!id.endsWith(`/node_modules/${instrumentation.name}/${mainFile}`)) continue
80
+ }
81
+
82
+ if (!matchVersion(pkg.version, instrumentation.versions)) continue
83
+
84
+ hook(require.cache[ids[i]].exports)
85
+ }
86
+ }
87
+
88
+ function getBasedir (id) {
89
+ return parse(id).basedir.replace(pathSepExpr, '/')
90
+ }
91
+
92
+ if (semver.satisfies(process.versions.node, '>=16.0.0')) {
93
+ exports.AsyncResource = AsyncResource
94
+ } else {
95
+ exports.AsyncResource = class extends AsyncResource {
96
+ static bind (fn, type, thisArg) {
97
+ type = type || fn.name
98
+ return (new exports.AsyncResource(type || 'bound-anonymous-fn')).bind(fn, thisArg)
99
+ }
100
+
101
+ bind (fn, thisArg = this) {
102
+ const ret = this.runInAsyncScope.bind(this, fn, thisArg)
103
+ Object.defineProperties(ret, {
104
+ 'length': {
105
+ configurable: true,
106
+ enumerable: false,
107
+ value: fn.length,
108
+ writable: false
109
+ },
110
+ 'asyncResource': {
111
+ configurable: true,
112
+ enumerable: true,
113
+ value: this,
114
+ writable: true
115
+ }
116
+ })
117
+ return ret
118
+ }
119
+ }
120
+ }
@@ -0,0 +1,29 @@
1
+ 'use strict'
2
+
3
+ const { AsyncResource } = require('async_hooks')
4
+
5
+ exports.wrapThen = function wrapThen (origThen) {
6
+ return function then (onFulfilled, onRejected, onProgress) {
7
+ const ar = new AsyncResource('bound-anonymous-fn')
8
+
9
+ arguments[0] = wrapCallback(ar, onFulfilled)
10
+ arguments[1] = wrapCallback(ar, onRejected)
11
+
12
+ // not standard but sometimes supported
13
+ if (onProgress) {
14
+ arguments[2] = wrapCallback(ar, onProgress)
15
+ }
16
+
17
+ return origThen.apply(this, arguments)
18
+ }
19
+ }
20
+
21
+ function wrapCallback (ar, callback) {
22
+ if (typeof callback !== 'function') return callback
23
+
24
+ return function () {
25
+ return ar.runInAsyncScope(() => {
26
+ return callback.apply(this, arguments)
27
+ })
28
+ }
29
+ }
@@ -0,0 +1,53 @@
1
+ 'use strict'
2
+
3
+ const {
4
+ channel,
5
+ addHook,
6
+ AsyncResource
7
+ } = require('./helpers/instrument')
8
+ const shimmer = require('../../datadog-shimmer')
9
+
10
+ addHook({ name: 'memcached', versions: ['>=2.2'] }, Memcached => {
11
+ const startCh = channel('apm:memcached:command:start')
12
+ const startWithArgsCh = channel('apm:memcached:command:start:with-args')
13
+ const asyncEndCh = channel('apm:memcached:command:async-end')
14
+ const endCh = channel('apm:memcached:command:end')
15
+ const errorCh = channel('apm:memcached:command:error')
16
+
17
+ shimmer.wrap(Memcached.prototype, 'command', command => function (queryCompiler, server) {
18
+ if (!startCh.hasSubscribers) {
19
+ return command.apply(this, arguments)
20
+ }
21
+
22
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
23
+
24
+ const client = this
25
+
26
+ const wrappedQueryCompiler = function () {
27
+ const query = queryCompiler.apply(this, arguments)
28
+ const callback = asyncResource.bind(query.callback)
29
+
30
+ query.callback = AsyncResource.bind(function (err) {
31
+ if (err) {
32
+ errorCh.publish(err)
33
+ }
34
+ asyncEndCh.publish(undefined)
35
+
36
+ return callback.apply(this, arguments)
37
+ })
38
+ startWithArgsCh.publish({ client, server, query })
39
+
40
+ return query
41
+ }
42
+
43
+ startCh.publish(undefined)
44
+
45
+ arguments[0] = wrappedQueryCompiler
46
+
47
+ const result = command.apply(this, arguments)
48
+ endCh.publish(undefined)
49
+ return result
50
+ })
51
+
52
+ return Memcached
53
+ })