dd-trace 3.7.1 → 3.8.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "3.7.1",
3
+ "version": "3.8.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -58,7 +58,7 @@
58
58
  "node": ">=14"
59
59
  },
60
60
  "dependencies": {
61
- "@datadog/native-appsec": "^1.2.1",
61
+ "@datadog/native-appsec": "1.3.0",
62
62
  "@datadog/native-metrics": "^1.5.0",
63
63
  "@datadog/pprof": "^1.1.1",
64
64
  "@datadog/sketches-js": "^2.1.0",
@@ -263,6 +263,9 @@ function jestAdapterWrapper (jestAdapter) {
263
263
  const adapter = jestAdapter.default ? jestAdapter.default : jestAdapter
264
264
  const newAdapter = shimmer.wrap(adapter, function () {
265
265
  const environment = arguments[2]
266
+ if (!environment) {
267
+ return adapter.apply(this, arguments)
268
+ }
266
269
  const asyncResource = new AsyncResource('bound-anonymous-fn')
267
270
  return asyncResource.runInAsyncScope(() => {
268
271
  testSuiteStartCh.publish({
@@ -280,7 +283,9 @@ function jestAdapterWrapper (jestAdapter) {
280
283
  testSuiteFinishCh.publish({ status, errorMessage })
281
284
  if (environment.global.__coverage__) {
282
285
  const coverageFiles = extractCoverageInformation(environment.global.__coverage__, environment.rootDir)
283
- if (coverageFiles.length) {
286
+ if (coverageFiles.length &&
287
+ environment.testEnvironmentOptions &&
288
+ environment.testEnvironmentOptions._ddTestCodeCoverageEnabled) {
284
289
  testSuiteCodeCoverageCh.publish([...coverageFiles, environment.testSuite])
285
290
  }
286
291
  }
@@ -314,6 +319,11 @@ function configureTestEnvironment (readConfigsResult) {
314
319
  sessionAsyncResource.runInAsyncScope(() => {
315
320
  testSessionConfigurationCh.publish(configs.map(config => config.testEnvironmentOptions))
316
321
  })
322
+ // We can't directly use isCodeCoverageEnabled when reporting coverage in `jestAdapterWrapper`
323
+ // because `jestAdapterWrapper` runs in a different process. We have to go through `testEnvironmentOptions`
324
+ configs.forEach(config => {
325
+ config.testEnvironmentOptions._ddTestCodeCoverageEnabled = isCodeCoverageEnabled
326
+ })
317
327
  if (isCodeCoverageEnabled) {
318
328
  const globalConfig = {
319
329
  ...readConfigsResult.globalConfig,
@@ -31,9 +31,10 @@ class HttpClientPlugin extends Plugin {
31
31
  const host = options.port ? `${hostname}:${options.port}` : hostname
32
32
  const path = options.path ? options.path.split(/[?#]/)[0] : '/'
33
33
  const uri = `${protocol}//${host}${path}`
34
+ const allowed = this.config.filter(uri)
34
35
 
35
36
  const method = (options.method || 'GET').toUpperCase()
36
- const childOf = store ? store.span : store
37
+ const childOf = store && allowed ? store.span : null
37
38
  const span = this.tracer.startSpan('http.request', {
38
39
  childOf,
39
40
  tags: {
@@ -46,6 +47,11 @@ class HttpClientPlugin extends Plugin {
46
47
  }
47
48
  })
48
49
 
50
+ // TODO: Figure out a better way to do this for any span.
51
+ if (!allowed) {
52
+ span._spanContext._trace.record = false
53
+ }
54
+
49
55
  if (!(hasAmazonSignature(options) || !this.config.propagationFilter(uri))) {
50
56
  this.tracer.inject(span, HTTP_HEADERS, options.headers)
51
57
  }
@@ -116,12 +122,14 @@ function addRequestHeaders (req, span, config) {
116
122
 
117
123
  function normalizeClientConfig (config) {
118
124
  const validateStatus = getStatusValidator(config)
125
+ const filter = getFilter(config)
119
126
  const propagationFilter = getFilter({ blocklist: config.propagationBlocklist })
120
127
  const headers = getHeaders(config)
121
128
  const hooks = getHooks(config)
122
129
 
123
130
  return Object.assign({}, config, {
124
131
  validateStatus,
132
+ filter,
125
133
  propagationFilter,
126
134
  headers,
127
135
  hooks
@@ -9,6 +9,7 @@ const tags = require('../../../ext/tags')
9
9
  const kinds = require('../../../ext/kinds')
10
10
  const formats = require('../../../ext/formats')
11
11
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
12
+ const urlFilter = require('../../dd-trace/src/plugins/util/urlfilter')
12
13
 
13
14
  const HTTP_HEADERS = formats.HTTP_HEADERS
14
15
  const HTTP_STATUS_CODE = tags.HTTP_STATUS_CODE
@@ -36,9 +37,10 @@ class Http2ClientPlugin extends Plugin {
36
37
  const pathname = path.split(/[?#]/)[0]
37
38
  const method = headers[HTTP2_HEADER_METHOD] || HTTP2_METHOD_GET
38
39
  const uri = `${sessionDetails.protocol}//${sessionDetails.host}:${sessionDetails.port}${pathname}`
40
+ const allowed = this.config.filter(uri)
39
41
 
40
42
  const store = storage.getStore()
41
- const childOf = store ? store.span : store
43
+ const childOf = store && allowed ? store.span : null
42
44
  const span = this.tracer.startSpan('http.request', {
43
45
  childOf,
44
46
  tags: {
@@ -51,6 +53,11 @@ class Http2ClientPlugin extends Plugin {
51
53
  }
52
54
  })
53
55
 
56
+ // TODO: Figure out a better way to do this for any span.
57
+ if (!allowed) {
58
+ span._spanContext._trace.record = false
59
+ }
60
+
54
61
  addHeaderTags(span, headers, HTTP_REQUEST_HEADERS, this.config)
55
62
 
56
63
  if (!hasAmazonSignature(headers, path)) {
@@ -155,14 +162,24 @@ function getStatusValidator (config) {
155
162
 
156
163
  function normalizeConfig (config) {
157
164
  const validateStatus = getStatusValidator(config)
165
+ const filter = getFilter(config)
158
166
  const headers = getHeaders(config)
159
167
 
160
168
  return Object.assign({}, config, {
161
169
  validateStatus,
170
+ filter,
162
171
  headers
163
172
  })
164
173
  }
165
174
 
175
+ function getFilter (config) {
176
+ config = Object.assign({}, config, {
177
+ blocklist: config.blocklist || []
178
+ })
179
+
180
+ return urlFilter.getFilter(config)
181
+ }
182
+
166
183
  function addHeaderTags (span, headers, prefix, config) {
167
184
  if (!headers) return
168
185
 
@@ -99,6 +99,7 @@ class JestPlugin extends Plugin {
99
99
  return
100
100
  }
101
101
  const testConfiguration = {
102
+ url: this.config.url,
102
103
  site: this.config.site,
103
104
  env: this.tracer._env,
104
105
  service: this.config.service || this.tracer._service,
@@ -130,6 +131,7 @@ class JestPlugin extends Plugin {
130
131
  return onError(gitUploadError)
131
132
  }
132
133
  const testConfiguration = {
134
+ url: this.config.url,
133
135
  site: this.config.site,
134
136
  env: this.tracer._env,
135
137
  service: this.config.service || this.tracer._service,
@@ -17,7 +17,6 @@ class OracledbPlugin extends DatabasePlugin {
17
17
  type: 'sql',
18
18
  kind: 'client',
19
19
  meta: {
20
- 'sql.query': query,
21
20
  'db.user': this.config.user,
22
21
  'db.instance': url.pathname && url.pathname.substring(1),
23
22
  'db.hostname': url.hostname,
@@ -2,6 +2,7 @@ const request = require('../../exporters/common/request')
2
2
  const id = require('../../id')
3
3
 
4
4
  function getItrConfiguration ({
5
+ url,
5
6
  site,
6
7
  env,
7
8
  service,
@@ -14,7 +15,7 @@ function getItrConfiguration ({
14
15
  runtimeVersion,
15
16
  branch
16
17
  }, done) {
17
- const url = new URL(`https://api.${site}`)
18
+ const intakeUrl = url || new URL(`https://api.${site}`)
18
19
 
19
20
  const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
20
21
  const appKey = process.env.DATADOG_APP_KEY ||
@@ -35,9 +36,9 @@ function getItrConfiguration ({
35
36
  'dd-application-key': appKey,
36
37
  'Content-Type': 'application/json'
37
38
  },
38
- protocol: url.protocol,
39
- hostname: url.hostname,
40
- port: url.port
39
+ protocol: intakeUrl.protocol,
40
+ hostname: intakeUrl.hostname,
41
+ port: intakeUrl.port
41
42
  }
42
43
 
43
44
  const data = JSON.stringify({
@@ -1,6 +1,7 @@
1
1
  const request = require('../../exporters/common/request')
2
2
 
3
3
  function getSkippableSuites ({
4
+ url,
4
5
  site,
5
6
  env,
6
7
  service,
@@ -12,7 +13,7 @@ function getSkippableSuites ({
12
13
  runtimeName,
13
14
  runtimeVersion
14
15
  }, done) {
15
- const url = new URL(`https://api.${site}`)
16
+ const intakeUrl = url || new URL(`https://api.${site}`)
16
17
 
17
18
  const apiKey = process.env.DATADOG_API_KEY || process.env.DD_API_KEY
18
19
  const appKey = process.env.DATADOG_APP_KEY ||
@@ -33,9 +34,9 @@ function getSkippableSuites ({
33
34
  'Content-Type': 'application/json'
34
35
  },
35
36
  timeout: 15000,
36
- protocol: url.protocol,
37
- hostname: url.hostname,
38
- port: url.port
37
+ protocol: intakeUrl.protocol,
38
+ hostname: intakeUrl.hostname,
39
+ port: intakeUrl.port
39
40
  }
40
41
 
41
42
  const data = JSON.stringify({
@@ -4,6 +4,7 @@ const fs = require('fs')
4
4
  const os = require('os')
5
5
  const URL = require('url').URL
6
6
  const path = require('path')
7
+ const log = require('./log')
7
8
  const pkg = require('./pkg')
8
9
  const coalesce = require('koalas')
9
10
  const tagger = require('./tagger')
@@ -47,6 +48,21 @@ class Config {
47
48
  constructor (options) {
48
49
  options = options || {}
49
50
 
51
+ // Configure the logger first so it can be used to warn about other configs
52
+ this.debug = isTrue(coalesce(
53
+ process.env.DD_TRACE_DEBUG,
54
+ false
55
+ ))
56
+ this.logger = options.logger
57
+ this.logLevel = coalesce(
58
+ options.logLevel,
59
+ process.env.DD_TRACE_LOG_LEVEL,
60
+ 'debug'
61
+ )
62
+
63
+ log.use(this.logger)
64
+ log.toggle(this.debug, this.logLevel, this)
65
+
50
66
  this.tags = {}
51
67
 
52
68
  tagger.add(this.tags, process.env.DD_TAGS)
@@ -131,10 +147,6 @@ class Config {
131
147
  process.env.DD_TRACE_TELEMETRY_ENABLED,
132
148
  !process.env.AWS_LAMBDA_FUNCTION_NAME
133
149
  )
134
- const DD_TRACE_DEBUG = coalesce(
135
- process.env.DD_TRACE_DEBUG,
136
- false
137
- )
138
150
  const DD_TRACE_AGENT_PROTOCOL_VERSION = coalesce(
139
151
  options.protocolVersion,
140
152
  process.env.DD_TRACE_AGENT_PROTOCOL_VERSION,
@@ -298,7 +310,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
298
310
  const defaultFlushInterval = inAWSLambda ? 0 : 2000
299
311
 
300
312
  this.tracing = !isFalse(DD_TRACING_ENABLED)
301
- this.debug = isTrue(DD_TRACE_DEBUG)
302
313
  this.logInjection = isTrue(DD_LOGS_INJECTION)
303
314
  this.env = DD_ENV
304
315
  this.url = DD_CIVISIBILITY_AGENTLESS_URL ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
@@ -312,7 +323,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
312
323
  this.queryStringObfuscation = DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP
313
324
  this.clientIpHeaderDisabled = !isTrue(DD_APPSEC_ENABLED)
314
325
  this.clientIpHeader = DD_TRACE_CLIENT_IP_HEADER
315
- this.logger = options.logger
316
326
  this.plugins = !!coalesce(options.plugins, true)
317
327
  this.service = DD_SERVICE
318
328
  this.serviceMapping = DD_SERVICE_MAPPING.length ? fromEntries(
@@ -334,11 +344,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
334
344
  this.sampler = sampler
335
345
  this.reportHostname = isTrue(coalesce(options.reportHostname, process.env.DD_TRACE_REPORT_HOSTNAME, false))
336
346
  this.scope = process.env.DD_TRACE_SCOPE
337
- this.logLevel = coalesce(
338
- options.logLevel,
339
- process.env.DD_TRACE_LOG_LEVEL,
340
- 'debug'
341
- )
342
347
  this.profiling = {
343
348
  enabled: isTrue(DD_PROFILING_ENABLED),
344
349
  sourceMap: !isFalse(DD_PROFILING_SOURCE_MAP),
@@ -124,7 +124,8 @@ module.exports = class PluginManager {
124
124
  clientIpHeader,
125
125
  isIntelligentTestRunnerEnabled,
126
126
  site,
127
- experimental
127
+ experimental,
128
+ url
128
129
  } = this._tracerConfig
129
130
 
130
131
  const sharedConfig = {}
@@ -156,6 +157,7 @@ module.exports = class PluginManager {
156
157
  }
157
158
 
158
159
  sharedConfig.site = site
160
+ sharedConfig.url = url
159
161
 
160
162
  return sharedConfig
161
163
  }
@@ -29,9 +29,6 @@ class Tracer extends NoopProxy {
29
29
  try {
30
30
  const config = new Config(options) // TODO: support dynamic config
31
31
 
32
- log.use(config.logger)
33
- log.toggle(config.debug, config.logLevel, this)
34
-
35
32
  if (config.profiling.enabled) {
36
33
  // do not stop tracer initialization if the profiler fails to be imported
37
34
  try {
@@ -27,6 +27,7 @@ class SpanProcessor {
27
27
  const { flushMinSpans } = this._config
28
28
  const { started, finished } = trace
29
29
 
30
+ if (trace.record === false) return
30
31
  if (started.length === finished.length || finished.length >= flushMinSpans) {
31
32
  this._prioritySampler.sample(spanContext)
32
33
  this._spanSampler.sample(spanContext)