dd-trace 4.45.0 → 4.47.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 (153) hide show
  1. package/LICENSE-3rdparty.csv +2 -0
  2. package/index.d.ts +20 -8
  3. package/package.json +11 -5
  4. package/packages/datadog-instrumentations/src/aerospike.js +1 -1
  5. package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
  6. package/packages/datadog-instrumentations/src/aws-sdk.js +4 -4
  7. package/packages/datadog-instrumentations/src/body-parser.js +4 -4
  8. package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
  9. package/packages/datadog-instrumentations/src/child_process.js +2 -2
  10. package/packages/datadog-instrumentations/src/connect.js +4 -4
  11. package/packages/datadog-instrumentations/src/cookie-parser.js +4 -4
  12. package/packages/datadog-instrumentations/src/couchbase.js +12 -12
  13. package/packages/datadog-instrumentations/src/cucumber.js +294 -56
  14. package/packages/datadog-instrumentations/src/dns.js +10 -10
  15. package/packages/datadog-instrumentations/src/elasticsearch.js +4 -4
  16. package/packages/datadog-instrumentations/src/express-mongo-sanitize.js +3 -3
  17. package/packages/datadog-instrumentations/src/express.js +4 -4
  18. package/packages/datadog-instrumentations/src/fastify.js +6 -6
  19. package/packages/datadog-instrumentations/src/fetch.js +1 -1
  20. package/packages/datadog-instrumentations/src/find-my-way.js +2 -2
  21. package/packages/datadog-instrumentations/src/fs.js +2 -2
  22. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +2 -2
  23. package/packages/datadog-instrumentations/src/grpc/client.js +4 -6
  24. package/packages/datadog-instrumentations/src/grpc/server.js +2 -2
  25. package/packages/datadog-instrumentations/src/hapi.js +10 -13
  26. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  27. package/packages/datadog-instrumentations/src/http/client.js +3 -3
  28. package/packages/datadog-instrumentations/src/jest.js +8 -5
  29. package/packages/datadog-instrumentations/src/kafkajs.js +67 -31
  30. package/packages/datadog-instrumentations/src/knex.js +2 -2
  31. package/packages/datadog-instrumentations/src/koa.js +5 -5
  32. package/packages/datadog-instrumentations/src/ldapjs.js +1 -1
  33. package/packages/datadog-instrumentations/src/mariadb.js +8 -8
  34. package/packages/datadog-instrumentations/src/memcached.js +2 -2
  35. package/packages/datadog-instrumentations/src/microgateway-core.js +7 -5
  36. package/packages/datadog-instrumentations/src/mocha/common.js +1 -1
  37. package/packages/datadog-instrumentations/src/mocha/main.js +139 -53
  38. package/packages/datadog-instrumentations/src/mocha/utils.js +37 -18
  39. package/packages/datadog-instrumentations/src/mocha/worker.js +29 -1
  40. package/packages/datadog-instrumentations/src/mocha.js +4 -0
  41. package/packages/datadog-instrumentations/src/moleculer/server.js +2 -2
  42. package/packages/datadog-instrumentations/src/mongodb-core.js +7 -7
  43. package/packages/datadog-instrumentations/src/mongoose.js +5 -6
  44. package/packages/datadog-instrumentations/src/mysql.js +3 -3
  45. package/packages/datadog-instrumentations/src/mysql2.js +6 -6
  46. package/packages/datadog-instrumentations/src/net.js +2 -2
  47. package/packages/datadog-instrumentations/src/next.js +5 -5
  48. package/packages/datadog-instrumentations/src/openai.js +62 -71
  49. package/packages/datadog-instrumentations/src/oracledb.js +8 -8
  50. package/packages/datadog-instrumentations/src/passport-http.js +1 -1
  51. package/packages/datadog-instrumentations/src/passport-local.js +1 -1
  52. package/packages/datadog-instrumentations/src/passport-utils.js +1 -1
  53. package/packages/datadog-instrumentations/src/pg.js +60 -5
  54. package/packages/datadog-instrumentations/src/pino.js +4 -4
  55. package/packages/datadog-instrumentations/src/playwright.js +6 -4
  56. package/packages/datadog-instrumentations/src/redis.js +2 -2
  57. package/packages/datadog-instrumentations/src/restify.js +4 -4
  58. package/packages/datadog-instrumentations/src/rhea.js +4 -4
  59. package/packages/datadog-instrumentations/src/router.js +5 -5
  60. package/packages/datadog-instrumentations/src/sharedb.js +2 -2
  61. package/packages/datadog-instrumentations/src/vitest.js +188 -12
  62. package/packages/datadog-instrumentations/src/winston.js +2 -3
  63. package/packages/datadog-plugin-amqplib/src/consumer.js +1 -3
  64. package/packages/datadog-plugin-aws-sdk/src/base.js +33 -0
  65. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  66. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -0
  67. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
  68. package/packages/datadog-plugin-cucumber/src/index.js +24 -1
  69. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +39 -10
  70. package/packages/datadog-plugin-cypress/src/support.js +4 -1
  71. package/packages/datadog-plugin-hapi/src/index.js +2 -2
  72. package/packages/datadog-plugin-http/src/client.js +1 -42
  73. package/packages/datadog-plugin-http2/src/client.js +1 -26
  74. package/packages/datadog-plugin-jest/src/index.js +18 -1
  75. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +20 -0
  76. package/packages/datadog-plugin-kafkajs/src/consumer.js +1 -2
  77. package/packages/datadog-plugin-kafkajs/src/index.js +3 -1
  78. package/packages/datadog-plugin-mocha/src/index.js +18 -0
  79. package/packages/datadog-plugin-openai/src/index.js +85 -65
  80. package/packages/datadog-plugin-playwright/src/index.js +9 -0
  81. package/packages/datadog-plugin-rhea/src/consumer.js +1 -3
  82. package/packages/datadog-plugin-vitest/src/index.js +68 -3
  83. package/packages/datadog-shimmer/src/shimmer.js +144 -10
  84. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  85. package/packages/dd-trace/src/appsec/blocking.js +23 -17
  86. package/packages/dd-trace/src/appsec/channels.js +4 -2
  87. package/packages/dd-trace/src/appsec/graphql.js +3 -1
  88. package/packages/dd-trace/src/appsec/iast/iast-log.js +2 -1
  89. package/packages/dd-trace/src/appsec/rasp/index.js +103 -0
  90. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +86 -0
  91. package/packages/dd-trace/src/appsec/rasp/ssrf.js +37 -0
  92. package/packages/dd-trace/src/appsec/rasp/utils.js +63 -0
  93. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -0
  94. package/packages/dd-trace/src/appsec/remote_config/index.js +16 -7
  95. package/packages/dd-trace/src/appsec/remote_config/manager.js +93 -52
  96. package/packages/dd-trace/src/appsec/rule_manager.js +8 -0
  97. package/packages/dd-trace/src/appsec/telemetry.js +3 -3
  98. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +33 -14
  99. package/packages/dd-trace/src/appsec/waf/waf_manager.js +2 -1
  100. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +4 -0
  101. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +15 -1
  102. package/packages/dd-trace/src/config.js +100 -40
  103. package/packages/dd-trace/src/constants.js +11 -1
  104. package/packages/dd-trace/src/data_streams_context.js +3 -0
  105. package/packages/dd-trace/src/datastreams/fnv.js +23 -0
  106. package/packages/dd-trace/src/datastreams/pathway.js +12 -5
  107. package/packages/dd-trace/src/datastreams/processor.js +35 -0
  108. package/packages/dd-trace/src/datastreams/schemas/schema.js +8 -0
  109. package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +125 -0
  110. package/packages/dd-trace/src/datastreams/schemas/schema_sampler.js +29 -0
  111. package/packages/dd-trace/src/debugger/devtools_client/config.js +24 -0
  112. package/packages/dd-trace/src/debugger/devtools_client/index.js +57 -0
  113. package/packages/dd-trace/src/debugger/devtools_client/inspector_promises_polyfill.js +23 -0
  114. package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +164 -0
  115. package/packages/dd-trace/src/debugger/devtools_client/send.js +28 -0
  116. package/packages/dd-trace/src/debugger/devtools_client/session.js +7 -0
  117. package/packages/dd-trace/src/debugger/devtools_client/state.js +47 -0
  118. package/packages/dd-trace/src/debugger/devtools_client/status.js +109 -0
  119. package/packages/dd-trace/src/debugger/index.js +92 -0
  120. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +29 -2
  121. package/packages/dd-trace/src/exporters/common/request.js +1 -1
  122. package/packages/dd-trace/src/lambda/handler.js +1 -0
  123. package/packages/dd-trace/src/lambda/index.js +12 -1
  124. package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -6
  125. package/packages/dd-trace/src/payload-tagging/config/aws.json +30 -0
  126. package/packages/dd-trace/src/payload-tagging/config/index.js +30 -0
  127. package/packages/dd-trace/src/payload-tagging/index.js +93 -0
  128. package/packages/dd-trace/src/payload-tagging/tagging.js +83 -0
  129. package/packages/dd-trace/src/plugin_manager.js +11 -10
  130. package/packages/dd-trace/src/plugins/ci_plugin.js +33 -8
  131. package/packages/dd-trace/src/plugins/util/env.js +5 -2
  132. package/packages/dd-trace/src/plugins/util/test.js +24 -4
  133. package/packages/dd-trace/src/profiler.js +15 -5
  134. package/packages/dd-trace/src/profiling/config.js +7 -4
  135. package/packages/dd-trace/src/profiling/exporter_cli.js +13 -1
  136. package/packages/dd-trace/src/profiling/exporters/agent.js +8 -2
  137. package/packages/dd-trace/src/profiling/profiler.js +0 -9
  138. package/packages/dd-trace/src/profiling/profilers/event_plugins/dns.js +13 -0
  139. package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_lookup.js +16 -0
  140. package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_lookupservice.js +16 -0
  141. package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_resolve.js +24 -0
  142. package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_reverse.js +16 -0
  143. package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +48 -0
  144. package/packages/dd-trace/src/profiling/profilers/event_plugins/net.js +24 -0
  145. package/packages/dd-trace/src/profiling/profilers/events.js +108 -32
  146. package/packages/dd-trace/src/profiling/profilers/shared.js +5 -0
  147. package/packages/dd-trace/src/profiling/profilers/wall.js +9 -3
  148. package/packages/dd-trace/src/profiling/ssi-heuristics.js +59 -60
  149. package/packages/dd-trace/src/proxy.js +31 -24
  150. package/packages/dd-trace/src/span_stats.js +4 -2
  151. package/packages/dd-trace/src/telemetry/index.js +23 -6
  152. package/packages/dd-trace/src/telemetry/logs/index.js +20 -0
  153. package/packages/dd-trace/src/appsec/rasp.js +0 -176
@@ -0,0 +1,30 @@
1
+ const aws = require('./aws.json')
2
+ const sdks = { aws }
3
+
4
+ function getSDKRules (sdk, requestInput, responseInput) {
5
+ return Object.fromEntries(
6
+ Object.entries(sdk).map(([service, serviceRules]) => {
7
+ return [
8
+ service,
9
+ {
10
+ request: serviceRules.request.concat(requestInput || []),
11
+ response: serviceRules.response.concat(responseInput || []),
12
+ expand: serviceRules.expand || []
13
+ }
14
+ ]
15
+ })
16
+ )
17
+ }
18
+
19
+ function appendRules (requestInput, responseInput) {
20
+ return Object.fromEntries(
21
+ Object.entries(sdks).map(([name, sdk]) => {
22
+ return [
23
+ name,
24
+ getSDKRules(sdk, requestInput, responseInput)
25
+ ]
26
+ })
27
+ )
28
+ }
29
+
30
+ module.exports = { appendRules }
@@ -0,0 +1,93 @@
1
+ const rfdc = require('rfdc')({ proto: false, circles: false })
2
+
3
+ const {
4
+ PAYLOAD_TAG_REQUEST_PREFIX,
5
+ PAYLOAD_TAG_RESPONSE_PREFIX
6
+ } = require('../constants')
7
+
8
+ const jsonpath = require('jsonpath-plus').JSONPath
9
+
10
+ const { tagsFromObject } = require('./tagging')
11
+
12
+ /**
13
+ * Given an identified value, attempt to parse it as JSON if relevant
14
+ *
15
+ * @param {any} value
16
+ * @returns {any} the parsed object if parsing was successful, the input if not
17
+ */
18
+ function maybeJSONParseValue (value) {
19
+ if (typeof value !== 'string' || value[0] !== '{') {
20
+ return value
21
+ }
22
+
23
+ try {
24
+ return JSON.parse(value)
25
+ } catch (e) {
26
+ return value
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Apply expansion to all expansion JSONPath queries
32
+ *
33
+ * @param {Object} object
34
+ * @param {[String]} expansionRules list of JSONPath queries
35
+ */
36
+ function expand (object, expansionRules) {
37
+ for (const rule of expansionRules) {
38
+ jsonpath(rule, object, (value, _type, desc) => {
39
+ desc.parent[desc.parentProperty] = maybeJSONParseValue(value)
40
+ })
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Apply redaction to all redaction JSONPath queries
46
+ *
47
+ * @param {Object} object
48
+ * @param {[String]} redactionRules
49
+ */
50
+ function redact (object, redactionRules) {
51
+ for (const rule of redactionRules) {
52
+ jsonpath(rule, object, (_value, _type, desc) => {
53
+ desc.parent[desc.parentProperty] = 'redacted'
54
+ })
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Generate a map of tag names to tag values by performing:
60
+ * 1. Attempting to parse identified fields as JSON
61
+ * 2. Redacting fields identified by redaction rules
62
+ * 3. Flattening the resulting object, producing as many tag name/tag value pairs
63
+ * as there are leaf values in the object
64
+ * This function performs side-effects on a _copy_ of the input object.
65
+ *
66
+ * @param {Object} config sdk configuration for the service
67
+ * @param {[String]} config.expand expansion rules for the service
68
+ * @param {[String]} config.request redaction rules for the request
69
+ * @param {[String]} config.response redaction rules for the response
70
+ * @param {Object} object the input object to generate tags from
71
+ * @param {Object} opts tag generation options
72
+ * @param {String} opts.prefix prefix for all generated tags
73
+ * @param {number} opts.maxDepth maximum depth to traverse the object
74
+ * @returns
75
+ */
76
+ function computeTags (config, object, opts) {
77
+ const payload = rfdc(object)
78
+ const redactionRules = opts.prefix === PAYLOAD_TAG_REQUEST_PREFIX ? config.request : config.response
79
+ const expansionRules = config.expand
80
+ expand(payload, expansionRules)
81
+ redact(payload, redactionRules)
82
+ return tagsFromObject(payload, opts)
83
+ }
84
+
85
+ function tagsFromRequest (config, object, opts) {
86
+ return computeTags(config, object, { ...opts, prefix: PAYLOAD_TAG_REQUEST_PREFIX })
87
+ }
88
+
89
+ function tagsFromResponse (config, object, opts) {
90
+ return computeTags(config, object, { ...opts, prefix: PAYLOAD_TAG_RESPONSE_PREFIX })
91
+ }
92
+
93
+ module.exports = { computeTags, tagsFromRequest, tagsFromResponse }
@@ -0,0 +1,83 @@
1
+ const { PAYLOAD_TAGGING_MAX_TAGS } = require('../constants')
2
+
3
+ const redactedKeys = [
4
+ 'authorization', 'x-authorization', 'password', 'token'
5
+ ]
6
+ const truncated = 'truncated'
7
+ const redacted = 'redacted'
8
+
9
+ function escapeKey (key) {
10
+ return key.replaceAll('.', '\\.')
11
+ }
12
+
13
+ /**
14
+ * Compute normalized payload tags from any given object.
15
+ *
16
+ * @param {object} object
17
+ * @param {import('./mask').Mask} mask
18
+ * @param {number} maxDepth
19
+ * @param {string} prefix
20
+ * @returns
21
+ */
22
+ function tagsFromObject (object, opts) {
23
+ const { maxDepth, prefix } = opts
24
+
25
+ let tagCount = 0
26
+ let abort = false
27
+ const result = {}
28
+
29
+ function tagRec (prefix, object, depth = 0) {
30
+ // Off by one: _dd.payload_tags_trimmed counts as 1 tag
31
+ if (abort) { return }
32
+
33
+ if (tagCount >= PAYLOAD_TAGGING_MAX_TAGS - 1) {
34
+ abort = true
35
+ result['_dd.payload_tags_incomplete'] = true
36
+ return
37
+ }
38
+
39
+ if (depth >= maxDepth && typeof object === 'object') {
40
+ tagCount += 1
41
+ result[prefix] = truncated
42
+ return
43
+ }
44
+
45
+ if (object === undefined) {
46
+ tagCount += 1
47
+ result[prefix] = 'undefined'
48
+ return
49
+ }
50
+
51
+ if (object === null) {
52
+ tagCount += 1
53
+ result[prefix] = 'null'
54
+ return
55
+ }
56
+
57
+ if (['number', 'boolean'].includes(typeof object) || Buffer.isBuffer(object)) {
58
+ tagCount += 1
59
+ result[prefix] = object.toString().substring(0, 5000)
60
+ return
61
+ }
62
+
63
+ if (typeof object === 'string') {
64
+ tagCount += 1
65
+ result[prefix] = object.substring(0, 5000)
66
+ }
67
+
68
+ if (typeof object === 'object') {
69
+ for (const [key, value] of Object.entries(object)) {
70
+ if (redactedKeys.includes(key.toLowerCase())) {
71
+ tagCount += 1
72
+ result[`${prefix}.${escapeKey(key)}`] = redacted
73
+ } else {
74
+ tagRec(`${prefix}.${escapeKey(key)}`, value, depth + 1)
75
+ }
76
+ }
77
+ }
78
+ }
79
+ tagRec(prefix, object)
80
+ return result
81
+ }
82
+
83
+ module.exports = { tagsFromObject }
@@ -136,10 +136,19 @@ module.exports = class PluginManager {
136
136
  dbmPropagationMode,
137
137
  dsmEnabled,
138
138
  clientIpEnabled,
139
- memcachedCommandEnabled
139
+ memcachedCommandEnabled,
140
+ ciVisibilityTestSessionName
140
141
  } = this._tracerConfig
141
142
 
142
- const sharedConfig = {}
143
+ const sharedConfig = {
144
+ dbmPropagationMode,
145
+ dsmEnabled,
146
+ memcachedCommandEnabled,
147
+ site,
148
+ url,
149
+ headers: headerTags || [],
150
+ ciVisibilityTestSessionName
151
+ }
143
152
 
144
153
  if (logInjection !== undefined) {
145
154
  sharedConfig.logInjection = logInjection
@@ -149,10 +158,6 @@ module.exports = class PluginManager {
149
158
  sharedConfig.queryStringObfuscation = queryStringObfuscation
150
159
  }
151
160
 
152
- sharedConfig.dbmPropagationMode = dbmPropagationMode
153
- sharedConfig.dsmEnabled = dsmEnabled
154
- sharedConfig.memcachedCommandEnabled = memcachedCommandEnabled
155
-
156
161
  if (serviceMapping && serviceMapping[name]) {
157
162
  sharedConfig.service = serviceMapping[name]
158
163
  }
@@ -161,10 +166,6 @@ module.exports = class PluginManager {
161
166
  sharedConfig.clientIpEnabled = clientIpEnabled
162
167
  }
163
168
 
164
- sharedConfig.site = site
165
- sharedConfig.url = url
166
- sharedConfig.headers = headerTags || []
167
-
168
169
  return sharedConfig
169
170
  }
170
171
  }
@@ -1,5 +1,6 @@
1
1
  const {
2
2
  getTestEnvironmentMetadata,
3
+ getTestSessionName,
3
4
  getCodeOwnersFileEntries,
4
5
  getTestParentSpan,
5
6
  getTestCommonTags,
@@ -13,11 +14,14 @@ const {
13
14
  TEST_SESSION_ID,
14
15
  TEST_COMMAND,
15
16
  TEST_MODULE,
17
+ TEST_SESSION_NAME,
16
18
  getTestSuiteCommonTags,
17
19
  TEST_STATUS,
18
20
  TEST_SKIPPED_BY_ITR,
19
21
  ITR_CORRELATION_ID,
20
- TEST_SOURCE_FILE
22
+ TEST_SOURCE_FILE,
23
+ TEST_LEVEL_EVENT_TYPES,
24
+ TEST_SUITE
21
25
  } = require('./util/test')
22
26
  const Plugin = require('./plugin')
23
27
  const { COMPONENT } = require('../constants')
@@ -75,6 +79,19 @@ module.exports = class CiPlugin extends Plugin {
75
79
  // only for playwright
76
80
  this.rootDir = rootDir
77
81
 
82
+ const testSessionName = getTestSessionName(this.config, this.command, this.testEnvironmentMetadata)
83
+
84
+ const metadataTags = {}
85
+ for (const testLevel of TEST_LEVEL_EVENT_TYPES) {
86
+ metadataTags[testLevel] = {
87
+ [TEST_SESSION_NAME]: testSessionName
88
+ }
89
+ }
90
+ // tracer might not be initialized correctly
91
+ if (this.tracer._exporter.setMetadataTags) {
92
+ this.tracer._exporter.setMetadataTags(metadataTags)
93
+ }
94
+
78
95
  this.testSessionSpan = this.tracer.startSpan(`${this.constructor.id}.test_session`, {
79
96
  childOf,
80
97
  tags: {
@@ -97,6 +114,7 @@ module.exports = class CiPlugin extends Plugin {
97
114
  if (this.constructor.id === 'vitest') {
98
115
  process.env.DD_CIVISIBILITY_TEST_SESSION_ID = this.testSessionSpan.context().toTraceId()
99
116
  process.env.DD_CIVISIBILITY_TEST_MODULE_ID = this.testModuleSpan.context().toSpanId()
117
+ process.env.DD_CIVISIBILITY_TEST_COMMAND = this.command
100
118
  }
101
119
 
102
120
  this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'module')
@@ -194,6 +212,19 @@ module.exports = class CiPlugin extends Plugin {
194
212
  }
195
213
  }
196
214
 
215
+ getCodeOwners (tags) {
216
+ const {
217
+ [TEST_SOURCE_FILE]: testSourceFile,
218
+ [TEST_SUITE]: testSuite
219
+ } = tags
220
+ // We'll try with the test source file if available (it could be different from the test suite)
221
+ let codeOwners = getCodeOwnersForFilename(testSourceFile, this.codeOwnersEntries)
222
+ if (!codeOwners) {
223
+ codeOwners = getCodeOwnersForFilename(testSuite, this.codeOwnersEntries)
224
+ }
225
+ return codeOwners
226
+ }
227
+
197
228
  startTestSpan (testName, testSuite, testSuiteSpan, extraTags = {}) {
198
229
  const childOf = getTestParentSpan(this.tracer)
199
230
 
@@ -208,13 +239,7 @@ module.exports = class CiPlugin extends Plugin {
208
239
  ...extraTags
209
240
  }
210
241
 
211
- const { [TEST_SOURCE_FILE]: testSourceFile } = extraTags
212
- // We'll try with the test source file if available (it could be different from the test suite)
213
- let codeOwners = getCodeOwnersForFilename(testSourceFile, this.codeOwnersEntries)
214
- if (!codeOwners) {
215
- codeOwners = getCodeOwnersForFilename(testSuite, this.codeOwnersEntries)
216
- }
217
-
242
+ const codeOwners = this.getCodeOwners(testTags)
218
243
  if (codeOwners) {
219
244
  testTags[TEST_CODE_OWNERS] = codeOwners
220
245
  }
@@ -5,6 +5,7 @@ const OS_VERSION = 'os.version'
5
5
  const OS_ARCHITECTURE = 'os.architecture'
6
6
  const RUNTIME_NAME = 'runtime.name'
7
7
  const RUNTIME_VERSION = 'runtime.version'
8
+ const DD_HOST_CPU_COUNT = '_dd.host.vcpu_count'
8
9
 
9
10
  function getRuntimeAndOSMetadata () {
10
11
  return {
@@ -12,7 +13,8 @@ function getRuntimeAndOSMetadata () {
12
13
  [OS_ARCHITECTURE]: process.arch,
13
14
  [OS_PLATFORM]: process.platform,
14
15
  [RUNTIME_NAME]: 'node',
15
- [OS_VERSION]: os.release()
16
+ [OS_VERSION]: os.release(),
17
+ [DD_HOST_CPU_COUNT]: os.cpus().length
16
18
  }
17
19
  }
18
20
 
@@ -22,5 +24,6 @@ module.exports = {
22
24
  OS_VERSION,
23
25
  OS_ARCHITECTURE,
24
26
  RUNTIME_NAME,
25
- RUNTIME_VERSION
27
+ RUNTIME_VERSION,
28
+ DD_HOST_CPU_COUNT
26
29
  }
@@ -19,7 +19,8 @@ const {
19
19
  GIT_COMMIT_AUTHOR_NAME,
20
20
  GIT_COMMIT_MESSAGE,
21
21
  CI_WORKSPACE_PATH,
22
- CI_PIPELINE_URL
22
+ CI_PIPELINE_URL,
23
+ CI_JOB_NAME
23
24
  } = require('./tags')
24
25
  const id = require('../../id')
25
26
 
@@ -28,6 +29,9 @@ const { SAMPLING_RULE_DECISION } = require('../../constants')
28
29
  const { AUTO_KEEP } = require('../../../../../ext/priority')
29
30
  const { version: ddTraceVersion } = require('../../../../../package.json')
30
31
 
32
+ // session tags
33
+ const TEST_SESSION_NAME = 'test_session.name'
34
+
31
35
  const TEST_FRAMEWORK = 'test.framework'
32
36
  const TEST_FRAMEWORK_VERSION = 'test.framework_version'
33
37
  const TEST_TYPE = 'test.type'
@@ -95,11 +99,16 @@ const MOCHA_WORKER_TRACE_PAYLOAD_CODE = 80
95
99
  const EFD_STRING = "Retried by Datadog's Early Flake Detection"
96
100
  const EFD_TEST_NAME_REGEX = new RegExp(EFD_STRING + ' \\(#\\d+\\): ', 'g')
97
101
 
98
- // Flaky test retries
99
- const NUM_FAILED_TEST_RETRIES = 5
102
+ const TEST_LEVEL_EVENT_TYPES = [
103
+ 'test',
104
+ 'test_suite_end',
105
+ 'test_module_end',
106
+ 'test_session_end'
107
+ ]
100
108
 
101
109
  module.exports = {
102
110
  TEST_CODE_OWNERS,
111
+ TEST_SESSION_NAME,
103
112
  TEST_FRAMEWORK,
104
113
  TEST_FRAMEWORK_VERSION,
105
114
  JEST_TEST_RUNNER,
@@ -171,7 +180,8 @@ module.exports = {
171
180
  TEST_BROWSER_DRIVER_VERSION,
172
181
  TEST_BROWSER_NAME,
173
182
  TEST_BROWSER_VERSION,
174
- NUM_FAILED_TEST_RETRIES
183
+ getTestSessionName,
184
+ TEST_LEVEL_EVENT_TYPES
175
185
  }
176
186
 
177
187
  // Returns pkg manager and its version, separated by '-', e.g. npm-8.15.0 or yarn-1.22.19
@@ -619,3 +629,13 @@ function getIsFaultyEarlyFlakeDetection (projectSuites, testsBySuiteName, faulty
619
629
  newSuitesPercentage > faultyThresholdPercentage
620
630
  )
621
631
  }
632
+
633
+ function getTestSessionName (config, testCommand, envTags) {
634
+ if (config.ciVisibilityTestSessionName) {
635
+ return config.ciVisibilityTestSessionName
636
+ }
637
+ if (envTags[CI_JOB_NAME]) {
638
+ return `${envTags[CI_JOB_NAME]}-${testCommand}`
639
+ }
640
+ return testCommand
641
+ }
@@ -8,8 +8,8 @@ process.once('beforeExit', () => { profiler.stop() })
8
8
 
9
9
  module.exports = {
10
10
  start: config => {
11
- const { service, version, env, url, hostname, port, tags, repositoryUrl, commitSHA } = config
12
- const { enabled, sourceMap, exporters, heuristicsEnabled } = config.profiling
11
+ const { service, version, env, url, hostname, port, tags, repositoryUrl, commitSHA, injectionEnabled } = config
12
+ const { enabled, sourceMap, exporters } = config.profiling
13
13
  const logger = {
14
14
  debug: (message) => log.debug(message),
15
15
  info: (message) => log.info(message),
@@ -17,9 +17,17 @@ module.exports = {
17
17
  error: (message) => log.error(message)
18
18
  }
19
19
 
20
+ const libraryInjected = injectionEnabled.length > 0
21
+ let activation
22
+ if (enabled === 'auto') {
23
+ activation = 'auto'
24
+ } else if (enabled === 'true') {
25
+ activation = 'manual'
26
+ } else if (injectionEnabled.includes('profiler')) {
27
+ activation = 'injection'
28
+ } // else activation = undefined
29
+
20
30
  return profiler.start({
21
- enabled,
22
- heuristicsEnabled,
23
31
  service,
24
32
  version,
25
33
  env,
@@ -31,7 +39,9 @@ module.exports = {
31
39
  port,
32
40
  tags,
33
41
  repositoryUrl,
34
- commitSHA
42
+ commitSHA,
43
+ libraryInjected,
44
+ activation
35
45
  })
36
46
  },
37
47
 
@@ -23,7 +23,6 @@ class Config {
23
23
  DD_PROFILING_CODEHOTSPOTS_ENABLED,
24
24
  DD_PROFILING_CPU_ENABLED,
25
25
  DD_PROFILING_DEBUG_SOURCE_MAPS,
26
- DD_PROFILING_ENABLED,
27
26
  DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
28
27
  DD_PROFILING_EXPERIMENTAL_CODEHOTSPOTS_ENABLED,
29
28
  DD_PROFILING_EXPERIMENTAL_CPU_ENABLED,
@@ -49,7 +48,6 @@ class Config {
49
48
  DD_VERSION
50
49
  } = process.env
51
50
 
52
- const enabled = isTrue(coalesce(options.enabled, DD_PROFILING_ENABLED, true))
53
51
  const env = coalesce(options.env, DD_ENV)
54
52
  const service = options.service || DD_SERVICE || 'node'
55
53
  const host = os.hostname()
@@ -64,8 +62,6 @@ class Config {
64
62
  const pprofPrefix = coalesce(options.pprofPrefix,
65
63
  DD_PROFILING_PPROF_PREFIX, '')
66
64
 
67
- this.enabled = enabled
68
- this.heuristicsEnabled = options.heuristicsEnabled
69
65
  this.service = service
70
66
  this.env = env
71
67
  this.host = host
@@ -101,6 +97,11 @@ class Config {
101
97
  const samplingContextsAvailable = process.platform !== 'win32'
102
98
  function checkOptionAllowed (option, description, condition) {
103
99
  if (option && !condition) {
100
+ // injection hardening: all of these can only happen if user explicitly
101
+ // sets an environment variable to its non-default value on the platform.
102
+ // In practical terms, it'd require someone explicitly turning on OOM
103
+ // monitoring, code hotspots, endpoint profiling, or CPU profiling on
104
+ // Windows, where it is not supported.
104
105
  throw new Error(`${description} not supported on ${process.platform}.`)
105
106
  }
106
107
  }
@@ -129,6 +130,8 @@ class Config {
129
130
  port
130
131
  })))
131
132
 
133
+ this.libraryInjected = options.libraryInjected
134
+ this.activation = options.activation
132
135
  this.exporters = ensureExporters(options.exporters || [
133
136
  new AgentExporter(this)
134
137
  ], this)
@@ -16,10 +16,22 @@ function exporterFromURL (url) {
16
16
  if (url.protocol === 'file:') {
17
17
  return new FileExporter({ pprofPrefix: fileURLToPath(url) })
18
18
  } else {
19
+ const injectionEnabled = (process.env.DD_INJECTION_ENABLED || '').split(',')
20
+ const libraryInjected = injectionEnabled.length > 0
21
+ const profilingEnabled = (process.env.DD_PROFILING_ENABLED || '').toLowerCase()
22
+ const activation = ['true', '1'].includes(profilingEnabled)
23
+ ? 'manual'
24
+ : profilingEnabled === 'auto'
25
+ ? 'auto'
26
+ : injectionEnabled.includes('profiling')
27
+ ? 'injection'
28
+ : 'unknown'
19
29
  return new AgentExporter({
20
30
  url,
21
31
  logger,
22
- uploadTimeout: timeoutMs
32
+ uploadTimeout: timeoutMs,
33
+ libraryInjected,
34
+ activation
23
35
  })
24
36
  }
25
37
  }
@@ -53,7 +53,7 @@ function computeRetries (uploadTimeout) {
53
53
  }
54
54
 
55
55
  class AgentExporter {
56
- constructor ({ url, logger, uploadTimeout, env, host, service, version } = {}) {
56
+ constructor ({ url, logger, uploadTimeout, env, host, service, version, libraryInjected, activation } = {}) {
57
57
  this._url = url
58
58
  this._logger = logger
59
59
 
@@ -65,6 +65,8 @@ class AgentExporter {
65
65
  this._host = host
66
66
  this._service = service
67
67
  this._appVersion = version
68
+ this._libraryInjected = !!libraryInjected
69
+ this._activation = activation || 'unknown'
68
70
  }
69
71
 
70
72
  export ({ profiles, start, end, tags }) {
@@ -105,6 +107,10 @@ class AgentExporter {
105
107
  kernel_version: os.version()
106
108
  },
107
109
  profiler: {
110
+ activation: this._activation,
111
+ ssi: {
112
+ mechanism: this._libraryInjected ? 'injected_agent' : 'none'
113
+ },
108
114
  version
109
115
  },
110
116
  runtime: {
@@ -193,7 +199,7 @@ class AgentExporter {
193
199
  this._logger.error(`Error from the agent: ${err.message}`)
194
200
  return
195
201
  } else if (err) {
196
- reject(new Error('Profiler agent export back-off period expired'))
202
+ reject(err)
197
203
  return
198
204
  }
199
205
 
@@ -5,7 +5,6 @@ const { Config } = require('./config')
5
5
  const { snapshotKinds } = require('./constants')
6
6
  const { threadNamePrefix } = require('./profilers/shared')
7
7
  const dc = require('dc-polyfill')
8
- const telemetryLog = dc.channel('datadog:telemetry:log')
9
8
 
10
9
  const profileSubmittedChannel = dc.channel('datadog:profiling:profile-submitted')
11
10
 
@@ -20,13 +19,6 @@ function logError (logger, err) {
20
19
  if (logger) {
21
20
  logger.error(err)
22
21
  }
23
- if (telemetryLog.hasSubscribers) {
24
- telemetryLog.publish({
25
- message: err.message,
26
- level: 'ERROR',
27
- stack_trace: err.stack
28
- })
29
- }
30
22
  }
31
23
 
32
24
  class Profiler extends EventEmitter {
@@ -55,7 +47,6 @@ class Profiler extends EventEmitter {
55
47
  if (this._enabled) return true
56
48
 
57
49
  const config = this._config = new Config(options)
58
- if (!config.enabled && !config.heuristicsEnabled) return false
59
50
 
60
51
  this._logger = config.logger
61
52
  this._enabled = true
@@ -0,0 +1,13 @@
1
+ const EventPlugin = require('./event')
2
+
3
+ class DNSPlugin extends EventPlugin {
4
+ static get id () {
5
+ return 'dns'
6
+ }
7
+
8
+ static get entryType () {
9
+ return 'dns'
10
+ }
11
+ }
12
+
13
+ module.exports = DNSPlugin
@@ -0,0 +1,16 @@
1
+ const DNSPlugin = require('./dns')
2
+
3
+ class DNSLookupPlugin extends DNSPlugin {
4
+ static get operation () {
5
+ return 'lookup'
6
+ }
7
+
8
+ extendEvent (event, startEvent) {
9
+ event.name = 'lookup'
10
+ event.detail = { hostname: startEvent[0] }
11
+
12
+ return event
13
+ }
14
+ }
15
+
16
+ module.exports = DNSLookupPlugin
@@ -0,0 +1,16 @@
1
+ const DNSPlugin = require('./dns')
2
+
3
+ class DNSLookupServicePlugin extends DNSPlugin {
4
+ static get operation () {
5
+ return 'lookup_service'
6
+ }
7
+
8
+ extendEvent (event, startEvent) {
9
+ event.name = 'lookupService'
10
+ event.detail = { host: startEvent[0], port: startEvent[1] }
11
+
12
+ return event
13
+ }
14
+ }
15
+
16
+ module.exports = DNSLookupServicePlugin
@@ -0,0 +1,24 @@
1
+ const DNSPlugin = require('./dns')
2
+
3
+ const queryNames = new Map()
4
+
5
+ class DNSResolvePlugin extends DNSPlugin {
6
+ static get operation () {
7
+ return 'resolve'
8
+ }
9
+
10
+ extendEvent (event, startEvent) {
11
+ const rrtype = startEvent[1]
12
+ let name = queryNames.get(rrtype)
13
+ if (!name) {
14
+ name = `query${rrtype}`
15
+ queryNames.set(rrtype, name)
16
+ }
17
+ event.name = name
18
+ event.detail = { host: startEvent[0] }
19
+
20
+ return event
21
+ }
22
+ }
23
+
24
+ module.exports = DNSResolvePlugin
@@ -0,0 +1,16 @@
1
+ const DNSPlugin = require('./dns')
2
+
3
+ class DNSReversePlugin extends DNSPlugin {
4
+ static get operation () {
5
+ return 'reverse'
6
+ }
7
+
8
+ extendEvent (event, startEvent) {
9
+ event.name = 'getHostByAddr'
10
+ event.detail = { host: startEvent[0] }
11
+
12
+ return event
13
+ }
14
+ }
15
+
16
+ module.exports = DNSReversePlugin