dd-trace 3.38.1 → 3.40.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 (82) hide show
  1. package/LICENSE-3rdparty.csv +2 -2
  2. package/README.md +3 -3
  3. package/ext/kinds.d.ts +1 -0
  4. package/ext/kinds.js +2 -1
  5. package/ext/tags.d.ts +2 -1
  6. package/ext/tags.js +6 -1
  7. package/index.d.ts +9 -1
  8. package/package.json +8 -8
  9. package/packages/datadog-core/src/storage/async_resource.js +1 -1
  10. package/packages/datadog-esbuild/index.js +1 -20
  11. package/packages/datadog-instrumentations/src/cucumber.js +5 -0
  12. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
  13. package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
  14. package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
  15. package/packages/datadog-instrumentations/src/jest.js +39 -10
  16. package/packages/datadog-instrumentations/src/knex.js +24 -17
  17. package/packages/datadog-instrumentations/src/mocha.js +16 -1
  18. package/packages/datadog-instrumentations/src/next.js +58 -23
  19. package/packages/datadog-instrumentations/src/playwright.js +11 -6
  20. package/packages/datadog-instrumentations/src/restify.js +14 -1
  21. package/packages/datadog-plugin-http/src/client.js +2 -0
  22. package/packages/datadog-plugin-jest/src/index.js +11 -3
  23. package/packages/datadog-plugin-kafkajs/src/consumer.js +8 -6
  24. package/packages/datadog-plugin-kafkajs/src/producer.js +9 -6
  25. package/packages/datadog-plugin-mocha/src/index.js +7 -1
  26. package/packages/datadog-plugin-next/src/index.js +4 -3
  27. package/packages/datadog-plugin-playwright/src/index.js +4 -1
  28. package/packages/dd-trace/src/appsec/channels.js +1 -1
  29. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  30. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-analyzer.js +60 -0
  31. package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +269 -0
  32. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +5 -2
  33. package/packages/dd-trace/src/appsec/iast/analyzers/missing-header-analyzer.js +22 -4
  34. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +9 -2
  35. package/packages/dd-trace/src/appsec/iast/analyzers/xcontenttype-header-missing-analyzer.js +2 -2
  36. package/packages/dd-trace/src/appsec/iast/iast-log.js +9 -4
  37. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  38. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  39. package/packages/dd-trace/src/appsec/iast/path-line.js +7 -2
  40. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +13 -2
  41. package/packages/dd-trace/src/appsec/iast/telemetry/index.js +1 -14
  42. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +19 -0
  43. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +2 -1
  44. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  45. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +5 -1
  46. package/packages/dd-trace/src/appsec/recommended.json +272 -48
  47. package/packages/dd-trace/src/appsec/reporter.js +31 -34
  48. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +16 -4
  49. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -0
  50. package/packages/dd-trace/src/config.js +35 -17
  51. package/packages/dd-trace/src/datastreams/processor.js +60 -15
  52. package/packages/dd-trace/src/format.js +6 -1
  53. package/packages/dd-trace/src/git_properties.js +16 -15
  54. package/packages/dd-trace/src/iitm.js +1 -1
  55. package/packages/dd-trace/src/log/channels.js +1 -1
  56. package/packages/dd-trace/src/opentelemetry/span.js +95 -2
  57. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
  58. package/packages/dd-trace/src/opentracing/span.js +4 -0
  59. package/packages/dd-trace/src/opentracing/span_context.js +5 -2
  60. package/packages/dd-trace/src/plugin_manager.js +1 -1
  61. package/packages/dd-trace/src/plugins/database.js +1 -1
  62. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  63. package/packages/dd-trace/src/plugins/util/ci.js +6 -19
  64. package/packages/dd-trace/src/plugins/util/git.js +2 -1
  65. package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
  66. package/packages/dd-trace/src/plugins/util/test.js +29 -1
  67. package/packages/dd-trace/src/plugins/util/url.js +26 -0
  68. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -14
  69. package/packages/dd-trace/src/profiling/config.js +23 -20
  70. package/packages/dd-trace/src/profiling/profilers/events.js +161 -0
  71. package/packages/dd-trace/src/profiling/profilers/shared.js +9 -0
  72. package/packages/dd-trace/src/profiling/profilers/wall.js +84 -47
  73. package/packages/dd-trace/src/ritm.js +1 -1
  74. package/packages/dd-trace/src/span_processor.js +4 -0
  75. package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
  76. package/packages/dd-trace/src/telemetry/index.js +5 -1
  77. package/packages/dd-trace/src/telemetry/logs/index.js +65 -0
  78. package/packages/dd-trace/src/{appsec/iast/telemetry/log → telemetry/logs}/log-collector.js +9 -22
  79. package/packages/dd-trace/src/tracer.js +4 -2
  80. package/packages/dd-trace/src/appsec/iast/telemetry/log/index.js +0 -87
  81. package/packages/diagnostics_channel/index.js +0 -3
  82. package/packages/diagnostics_channel/src/index.js +0 -121
@@ -10,7 +10,7 @@ const coalesce = require('koalas')
10
10
  const tagger = require('./tagger')
11
11
  const { isTrue, isFalse } = require('./util')
12
12
  const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('./plugins/util/tags')
13
- const { getGitMetadataFromGitProperties } = require('./git_properties')
13
+ const { getGitMetadataFromGitProperties, removeUserSensitiveInfo } = require('./git_properties')
14
14
  const { updateConfig } = require('./telemetry')
15
15
  const { getIsGCPFunction, getIsAzureFunctionConsumptionPlan } = require('./serverless')
16
16
 
@@ -235,8 +235,9 @@ class Config {
235
235
 
236
236
  const inServerlessEnvironment = inAWSLambda || isGCPFunction || isAzureFunctionConsumptionPlan
237
237
 
238
- const DD_TRACE_TELEMETRY_ENABLED = coalesce(
239
- process.env.DD_TRACE_TELEMETRY_ENABLED,
238
+ const DD_INSTRUMENTATION_TELEMETRY_ENABLED = coalesce(
239
+ process.env.DD_TRACE_TELEMETRY_ENABLED, // for backward compatibility
240
+ process.env.DD_INSTRUMENTATION_TELEMETRY_ENABLED, // to comply with instrumentation telemetry specs
240
241
  !inServerlessEnvironment
241
242
  )
242
243
  const DD_TELEMETRY_HEARTBEAT_INTERVAL = process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL
@@ -251,7 +252,7 @@ class Config {
251
252
  )
252
253
  const DD_TELEMETRY_METRICS_ENABLED = coalesce(
253
254
  process.env.DD_TELEMETRY_METRICS_ENABLED,
254
- false
255
+ true
255
256
  )
256
257
  const DD_TRACE_AGENT_PROTOCOL_VERSION = coalesce(
257
258
  options.protocolVersion,
@@ -367,10 +368,11 @@ class Config {
367
368
  isGCPFunction || isAzureFunctionConsumptionPlan
368
369
  )
369
370
 
371
+ // the tracer generates 128 bit IDs by default as of v5
370
372
  const DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED = coalesce(
371
373
  options.traceId128BitGenerationEnabled,
372
374
  process.env.DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED,
373
- false
375
+ true
374
376
  )
375
377
 
376
378
  const DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED = coalesce(
@@ -447,7 +449,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
447
449
  5 // seconds
448
450
  )
449
451
 
450
- const iastOptions = options.experimental && options.experimental.iast
452
+ const iastOptions = options?.experimental?.iast
451
453
  const DD_IAST_ENABLED = coalesce(
452
454
  iastOptions &&
453
455
  (iastOptions === true || iastOptions.enabled === true),
@@ -461,7 +463,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
461
463
 
462
464
  const defaultIastRequestSampling = 30
463
465
  const iastRequestSampling = coalesce(
464
- parseInt(iastOptions && iastOptions.requestSampling),
466
+ parseInt(iastOptions?.requestSampling),
465
467
  parseInt(process.env.DD_IAST_REQUEST_SAMPLING),
466
468
  defaultIastRequestSampling
467
469
  )
@@ -469,31 +471,43 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
469
471
  iastRequestSampling > 100 ? defaultIastRequestSampling : iastRequestSampling
470
472
 
471
473
  const DD_IAST_MAX_CONCURRENT_REQUESTS = coalesce(
472
- parseInt(iastOptions && iastOptions.maxConcurrentRequests),
474
+ parseInt(iastOptions?.maxConcurrentRequests),
473
475
  parseInt(process.env.DD_IAST_MAX_CONCURRENT_REQUESTS),
474
476
  2
475
477
  )
476
478
 
477
479
  const DD_IAST_MAX_CONTEXT_OPERATIONS = coalesce(
478
- parseInt(iastOptions && iastOptions.maxContextOperations),
480
+ parseInt(iastOptions?.maxContextOperations),
479
481
  parseInt(process.env.DD_IAST_MAX_CONTEXT_OPERATIONS),
480
482
  2
481
483
  )
482
484
 
483
485
  const DD_IAST_DEDUPLICATION_ENABLED = coalesce(
484
- iastOptions && iastOptions.deduplicationEnabled,
486
+ iastOptions?.deduplicationEnabled,
485
487
  process.env.DD_IAST_DEDUPLICATION_ENABLED && isTrue(process.env.DD_IAST_DEDUPLICATION_ENABLED),
486
488
  true
487
489
  )
488
490
 
489
491
  const DD_IAST_REDACTION_ENABLED = coalesce(
490
- iastOptions && iastOptions.redactionEnabled,
492
+ iastOptions?.redactionEnabled,
491
493
  !isFalse(process.env.DD_IAST_REDACTION_ENABLED),
492
494
  true
493
495
  )
494
496
 
497
+ const DD_IAST_REDACTION_NAME_PATTERN = coalesce(
498
+ iastOptions?.redactionNamePattern,
499
+ process.env.DD_IAST_REDACTION_NAME_PATTERN,
500
+ null
501
+ )
502
+
503
+ const DD_IAST_REDACTION_VALUE_PATTERN = coalesce(
504
+ iastOptions?.redactionValuePattern,
505
+ process.env.DD_IAST_REDACTION_VALUE_PATTERN,
506
+ null
507
+ )
508
+
495
509
  const DD_IAST_TELEMETRY_VERBOSITY = coalesce(
496
- iastOptions && iastOptions.telemetryVerbosity,
510
+ iastOptions?.telemetryVerbosity,
497
511
  process.env.DD_IAST_TELEMETRY_VERBOSITY,
498
512
  'INFORMATION'
499
513
  )
@@ -586,10 +600,10 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
586
600
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
587
601
  // Disabled for CI Visibility's agentless
588
602
  this.telemetry = {
589
- enabled: DD_TRACE_EXPORTER !== 'datadog' && isTrue(DD_TRACE_TELEMETRY_ENABLED),
603
+ enabled: DD_TRACE_EXPORTER !== 'datadog' && isTrue(DD_INSTRUMENTATION_TELEMETRY_ENABLED),
590
604
  heartbeatInterval: DD_TELEMETRY_HEARTBEAT_INTERVAL,
591
- logCollection: isTrue(DD_TELEMETRY_LOG_COLLECTION_ENABLED),
592
605
  debug: isTrue(DD_TELEMETRY_DEBUG),
606
+ logCollection: isTrue(DD_TELEMETRY_LOG_COLLECTION_ENABLED),
593
607
  metrics: isTrue(DD_TELEMETRY_METRICS_ENABLED)
594
608
  }
595
609
  this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
@@ -620,6 +634,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
620
634
  maxContextOperations: DD_IAST_MAX_CONTEXT_OPERATIONS,
621
635
  deduplicationEnabled: DD_IAST_DEDUPLICATION_ENABLED,
622
636
  redactionEnabled: DD_IAST_REDACTION_ENABLED,
637
+ redactionNamePattern: DD_IAST_REDACTION_NAME_PATTERN,
638
+ redactionValuePattern: DD_IAST_REDACTION_VALUE_PATTERN,
623
639
  telemetryVerbosity: DD_IAST_TELEMETRY_VERBOSITY
624
640
  }
625
641
 
@@ -638,9 +654,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
638
654
  this.memcachedCommandEnabled = isTrue(DD_TRACE_MEMCACHED_COMMAND_ENABLED)
639
655
 
640
656
  if (this.gitMetadataEnabled) {
641
- this.repositoryUrl = coalesce(
642
- process.env.DD_GIT_REPOSITORY_URL,
643
- this.tags[GIT_REPOSITORY_URL]
657
+ this.repositoryUrl = removeUserSensitiveInfo(
658
+ coalesce(
659
+ process.env.DD_GIT_REPOSITORY_URL,
660
+ this.tags[GIT_REPOSITORY_URL]
661
+ )
644
662
  )
645
663
  this.commitSHA = coalesce(
646
664
  process.env.DD_GIT_COMMIT_SHA,
@@ -4,12 +4,16 @@ const pkg = require('../../../../package.json')
4
4
  const Uint64 = require('int64-buffer').Uint64BE
5
5
 
6
6
  const { LogCollapsingLowestDenseDDSketch } = require('@datadog/sketches-js')
7
-
7
+ const { encodePathwayContext } = require('./pathway')
8
8
  const { DataStreamsWriter } = require('./writer')
9
9
  const { computePathwayHash } = require('./pathway')
10
+ const { types } = require('util')
11
+ const { PATHWAY_HASH } = require('../../../../ext/tags')
12
+
10
13
  const ENTRY_PARENT_HASH = Buffer.from('0000000000000000', 'hex')
11
14
 
12
15
  const HIGH_ACCURACY_DISTRIBUTION = 0.0075
16
+ const CONTEXT_PROPAGATION_KEY = 'dd-pathway-ctx'
13
17
 
14
18
  class StatsPoint {
15
19
  constructor (hash, parentHash, edgeTags) {
@@ -18,6 +22,7 @@ class StatsPoint {
18
22
  this.edgeTags = edgeTags
19
23
  this.edgeLatency = new LogCollapsingLowestDenseDDSketch(HIGH_ACCURACY_DISTRIBUTION)
20
24
  this.pathwayLatency = new LogCollapsingLowestDenseDDSketch(HIGH_ACCURACY_DISTRIBUTION)
25
+ this.payloadSize = new LogCollapsingLowestDenseDDSketch(HIGH_ACCURACY_DISTRIBUTION)
21
26
  }
22
27
 
23
28
  addLatencies (checkpoint) {
@@ -25,6 +30,7 @@ class StatsPoint {
25
30
  const pathwayLatencySec = checkpoint.pathwayLatencyNs / 1e9
26
31
  this.edgeLatency.accept(edgeLatencySec)
27
32
  this.pathwayLatency.accept(pathwayLatencySec)
33
+ this.payloadSize.accept(checkpoint.payloadSize)
28
34
  }
29
35
 
30
36
  encode () {
@@ -33,7 +39,8 @@ class StatsPoint {
33
39
  ParentHash: this.parentHash,
34
40
  EdgeTags: this.edgeTags,
35
41
  EdgeLatency: this.edgeLatency.toProto(),
36
- PathwayLatency: this.pathwayLatency.toProto()
42
+ PathwayLatency: this.pathwayLatency.toProto(),
43
+ PayloadSize: this.payloadSize.toProto()
37
44
  }
38
45
  }
39
46
  }
@@ -49,6 +56,29 @@ class StatsBucket extends Map {
49
56
  }
50
57
  }
51
58
 
59
+ function getSizeOrZero (obj) {
60
+ if (typeof obj === 'string') {
61
+ return Buffer.from(obj, 'utf-8').length
62
+ }
63
+ if (types.isArrayBuffer(obj)) {
64
+ return obj.byteLength
65
+ }
66
+ if (Buffer.isBuffer(obj)) {
67
+ return obj.length
68
+ }
69
+ return 0
70
+ }
71
+
72
+ function getHeadersSize (headers) {
73
+ if (headers === undefined) return 0
74
+ return Object.entries(headers).reduce((prev, [key, val]) => getSizeOrZero(key) + getSizeOrZero(val) + prev, 0)
75
+ }
76
+
77
+ function getMessageSize (message) {
78
+ const { key, value, headers } = message
79
+ return getSizeOrZero(key) + getSizeOrZero(value) + getHeadersSize(headers)
80
+ }
81
+
52
82
  class TimeBuckets extends Map {
53
83
  forTime (time) {
54
84
  if (!this.has(time)) {
@@ -105,15 +135,19 @@ class DataStreamsProcessor {
105
135
  this.writer.flush(payload)
106
136
  }
107
137
 
108
- recordCheckpoint (checkpoint) {
138
+ recordCheckpoint (checkpoint, span = null) {
109
139
  if (!this.enabled) return
110
140
  const bucketTime = Math.round(checkpoint.currentTimestamp - (checkpoint.currentTimestamp % this.bucketSizeNs))
111
141
  this.buckets.forTime(bucketTime)
112
142
  .forCheckpoint(checkpoint)
113
143
  .addLatencies(checkpoint)
144
+ // set DSM pathway hash on span to enable related traces feature on DSM tab, convert from buffer to uint64
145
+ if (span) {
146
+ span.setTag(PATHWAY_HASH, checkpoint.hash.readBigUInt64BE(0).toString())
147
+ }
114
148
  }
115
149
 
116
- setCheckpoint (edgeTags, ctx = null) {
150
+ setCheckpoint (edgeTags, span, ctx = null, payloadSize = 0) {
117
151
  if (!this.enabled) return null
118
152
  const nowNs = Date.now() * 1e6
119
153
  const direction = edgeTags.find(t => t.startsWith('direction:'))
@@ -147,16 +181,7 @@ class DataStreamsProcessor {
147
181
  const hash = computePathwayHash(this.service, this.env, edgeTags, parentHash)
148
182
  const edgeLatencyNs = nowNs - edgeStartNs
149
183
  const pathwayLatencyNs = nowNs - pathwayStartNs
150
- const checkpoint = {
151
- currentTimestamp: nowNs,
152
- parentHash: parentHash,
153
- hash: hash,
154
- edgeTags: edgeTags,
155
- edgeLatencyNs: edgeLatencyNs,
156
- pathwayLatencyNs: pathwayLatencyNs
157
- }
158
- this.recordCheckpoint(checkpoint)
159
- return {
184
+ const dataStreamsContext = {
160
185
  hash: hash,
161
186
  edgeStartNs: edgeStartNs,
162
187
  pathwayStartNs: pathwayStartNs,
@@ -164,6 +189,22 @@ class DataStreamsProcessor {
164
189
  closestOppositeDirectionHash: closestOppositeDirectionHash,
165
190
  closestOppositeDirectionEdgeStart: closestOppositeDirectionEdgeStart
166
191
  }
192
+ if (direction === 'direction:out') {
193
+ // Add the header for this now, as the callee doesn't have access to context when producing
194
+ payloadSize += getSizeOrZero(encodePathwayContext(dataStreamsContext))
195
+ payloadSize += CONTEXT_PROPAGATION_KEY.length
196
+ }
197
+ const checkpoint = {
198
+ currentTimestamp: nowNs,
199
+ parentHash: parentHash,
200
+ hash: hash,
201
+ edgeTags: edgeTags,
202
+ edgeLatencyNs: edgeLatencyNs,
203
+ pathwayLatencyNs: pathwayLatencyNs,
204
+ payloadSize: payloadSize
205
+ }
206
+ this.recordCheckpoint(checkpoint, span)
207
+ return dataStreamsContext
167
208
  }
168
209
 
169
210
  _serializeBuckets () {
@@ -194,5 +235,9 @@ module.exports = {
194
235
  StatsPoint: StatsPoint,
195
236
  StatsBucket: StatsBucket,
196
237
  TimeBuckets,
197
- ENTRY_PARENT_HASH
238
+ getMessageSize,
239
+ getHeadersSize,
240
+ getSizeOrZero,
241
+ ENTRY_PARENT_HASH,
242
+ CONTEXT_PROPAGATION_KEY
198
243
  }
@@ -14,7 +14,7 @@ const SPAN_SAMPLING_MECHANISM = constants.SPAN_SAMPLING_MECHANISM
14
14
  const SPAN_SAMPLING_RULE_RATE = constants.SPAN_SAMPLING_RULE_RATE
15
15
  const SPAN_SAMPLING_MAX_PER_SECOND = constants.SPAN_SAMPLING_MAX_PER_SECOND
16
16
  const SAMPLING_MECHANISM_SPAN = constants.SAMPLING_MECHANISM_SPAN
17
- const { MEASURED, BASE_SERVICE } = tags
17
+ const { MEASURED, BASE_SERVICE, ANALYTICS } = tags
18
18
  const ORIGIN_KEY = constants.ORIGIN_KEY
19
19
  const HOSTNAME_KEY = constants.HOSTNAME_KEY
20
20
  const TOP_LEVEL_KEY = constants.TOP_LEVEL_KEY
@@ -24,6 +24,7 @@ const ERROR_STACK = constants.ERROR_STACK
24
24
  const ERROR_TYPE = constants.ERROR_TYPE
25
25
 
26
26
  const map = {
27
+ 'operation.name': 'name',
27
28
  'service.name': 'service',
28
29
  'span.type': 'type',
29
30
  'resource.name': 'resource'
@@ -83,6 +84,7 @@ function extractTags (trace, span) {
83
84
 
84
85
  for (const tag in tags) {
85
86
  switch (tag) {
87
+ case 'operation.name':
86
88
  case 'service.name':
87
89
  case 'span.type':
88
90
  case 'resource.name':
@@ -92,6 +94,9 @@ function extractTags (trace, span) {
92
94
  case 'http.status_code':
93
95
  addTag(trace.meta, {}, tag, tags[tag] && String(tags[tag]))
94
96
  break
97
+ case 'analytics.event':
98
+ addTag({}, trace.metrics, ANALYTICS, tags[tag] === undefined || tags[tag] ? 1 : 0)
99
+ break
95
100
  case HOSTNAME_KEY:
96
101
  case MEASURED:
97
102
  addTag({}, trace.metrics, tag, tags[tag] === undefined || tags[tag] ? 1 : 0)
@@ -1,6 +1,20 @@
1
1
  const commitSHARegex = /git\.commit\.sha=([a-f\d]{40})/
2
2
  const repositoryUrlRegex = /git\.repository_url=([\w\d:@/.-]+)/
3
3
 
4
+ function removeUserSensitiveInfo (repositoryUrl) {
5
+ try {
6
+ // repository URLs can contain username and password, so we want to filter those out
7
+ const parsedUrl = new URL(repositoryUrl)
8
+ if (parsedUrl.username || parsedUrl.password) {
9
+ return `${parsedUrl.origin}${parsedUrl.pathname}`
10
+ }
11
+ return repositoryUrl
12
+ } catch (e) {
13
+ // if protocol isn't https, no password will be used
14
+ return repositoryUrl
15
+ }
16
+ }
17
+
4
18
  function getGitMetadataFromGitProperties (gitPropertiesString) {
5
19
  if (!gitPropertiesString) {
6
20
  return {}
@@ -9,24 +23,11 @@ function getGitMetadataFromGitProperties (gitPropertiesString) {
9
23
  const repositoryUrlMatch = gitPropertiesString.match(repositoryUrlRegex)
10
24
 
11
25
  const repositoryUrl = repositoryUrlMatch ? repositoryUrlMatch[1] : undefined
12
- let parsedUrl = repositoryUrl
13
-
14
- if (repositoryUrl) {
15
- try {
16
- // repository URLs can contain username and password, so we want to filter those out
17
- parsedUrl = new URL(repositoryUrl)
18
- if (parsedUrl.password) {
19
- parsedUrl = `${parsedUrl.origin}${parsedUrl.pathname}`
20
- }
21
- } catch (e) {
22
- // if protocol isn't https, no password will be used
23
- }
24
- }
25
26
 
26
27
  return {
27
28
  commitSHA: commitSHAMatch ? commitSHAMatch[1] : undefined,
28
- repositoryUrl: parsedUrl
29
+ repositoryUrl: removeUserSensitiveInfo(repositoryUrl)
29
30
  }
30
31
  }
31
32
 
32
- module.exports = { getGitMetadataFromGitProperties }
33
+ module.exports = { getGitMetadataFromGitProperties, removeUserSensitiveInfo }
@@ -3,7 +3,7 @@
3
3
  const semver = require('semver')
4
4
  const logger = require('./log')
5
5
  const { addHook } = require('import-in-the-middle')
6
- const dc = require('../../diagnostics_channel')
6
+ const dc = require('dc-polyfill')
7
7
 
8
8
  if (semver.satisfies(process.versions.node, '>=14.13.1')) {
9
9
  const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart')
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { channel } = require('../../../diagnostics_channel')
3
+ const { channel } = require('dc-polyfill')
4
4
 
5
5
  const Level = {
6
6
  Debug: 'debug',
@@ -11,6 +11,7 @@ const tracer = require('../../')
11
11
  const DatadogSpan = require('../opentracing/span')
12
12
  const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../constants')
13
13
  const { SERVICE_NAME, RESOURCE_NAME } = require('../../../../ext/tags')
14
+ const kinds = require('../../../../ext/kinds')
14
15
 
15
16
  const SpanContext = require('./span_context')
16
17
 
@@ -19,6 +20,93 @@ function hrTimeToMilliseconds (time) {
19
20
  return time[0] * 1e3 + time[1] / 1e6
20
21
  }
21
22
 
23
+ const spanKindNames = {
24
+ [api.SpanKind.INTERNAL]: kinds.INTERNAL,
25
+ [api.SpanKind.SERVER]: kinds.SERVER,
26
+ [api.SpanKind.CLIENT]: kinds.CLIENT,
27
+ [api.SpanKind.PRODUCER]: kinds.PRODUCER,
28
+ [api.SpanKind.CONSUMER]: kinds.CONSUMER
29
+ }
30
+
31
+ /**
32
+ * Several of these attributes are not yet supported by the Node.js OTel API.
33
+ * We check for old equivalents where we can, but not all had equivalents.
34
+ */
35
+ function spanNameMapper (spanName, kind, attributes) {
36
+ if (spanName) return spanName
37
+
38
+ const opName = attributes['operation.name']
39
+ if (opName) return opName
40
+
41
+ const { INTERNAL, SERVER, CLIENT } = api.SpanKind
42
+
43
+ // HTTP server and client requests
44
+ // TODO: Drop http.method when http.request.method is supported.
45
+ for (const key of ['http.method', 'http.request.method']) {
46
+ if (key in attributes) {
47
+ if (kind === SERVER) {
48
+ return 'http.server.request'
49
+ }
50
+ if (kind === CLIENT) {
51
+ return 'http.client.request'
52
+ }
53
+ }
54
+ }
55
+
56
+ // Databases
57
+ const dbSystem = attributes['db.system']
58
+ if (dbSystem && kind === CLIENT) {
59
+ return `${dbSystem}.query`
60
+ }
61
+
62
+ // Messaging
63
+ const msgSys = attributes['messaging.system']
64
+ const msgOp = attributes['messaging.operation']
65
+ if (msgSys && msgOp && kind !== INTERNAL) {
66
+ return `${msgSys}.${msgOp}`
67
+ }
68
+
69
+ // RPC (and AWS)
70
+ const rpcSystem = attributes['rpc.system']
71
+ if (rpcSystem) {
72
+ if (kind === CLIENT) {
73
+ return rpcSystem === 'aws-api'
74
+ ? `aws.${attributes['rpc.service'] || 'client'}.request`
75
+ : `${rpcSystem}.client.request`
76
+ }
77
+ if (kind === SERVER) {
78
+ return `${rpcSystem}.server.request`
79
+ }
80
+ }
81
+
82
+ // FaaS
83
+ const faasProvider = attributes['faas.invoked_provider']
84
+ const faasName = attributes['faas.invoked_name']
85
+ const faasTrigger = attributes['faas.trigger']
86
+ if (kind === CLIENT && faasProvider && faasName) {
87
+ return `${faasProvider}.${faasName}.invoke`
88
+ }
89
+ if (kind === SERVER && faasTrigger) {
90
+ return `${faasTrigger}.invoke`
91
+ }
92
+
93
+ // GraphQL
94
+ // NOTE: Not part of Semantic Convention spec yet, but is used in the GraphQL
95
+ // integration.
96
+ const isGraphQL = 'graphql.operation.type' in attributes
97
+ if (isGraphQL) return 'graphql.server.request'
98
+
99
+ // Network
100
+ // TODO: Doesn't exist yet. No equivalent.
101
+ const protocol = attributes['network.protocol.name']
102
+ const protocolPrefix = protocol ? `${protocol}.` : ''
103
+ if (kind === SERVER) return `${protocolPrefix}server.request`
104
+ if (kind === CLIENT) return `${protocolPrefix}client.request`
105
+
106
+ // If all else fails, default to stringified span.kind.
107
+ return spanKindNames[kind]
108
+ }
109
+
22
110
  class Span {
23
111
  constructor (
24
112
  parentTracer,
@@ -27,7 +115,8 @@ class Span {
27
115
  spanContext,
28
116
  kind,
29
117
  links = [],
30
- timeInput
118
+ timeInput,
119
+ attributes
31
120
  ) {
32
121
  const { _tracer } = tracer
33
122
 
@@ -35,7 +124,7 @@ class Span {
35
124
  const startTime = hrTimeToMilliseconds(hrStartTime)
36
125
 
37
126
  this._ddSpan = new DatadogSpan(_tracer, _tracer._processor, _tracer._prioritySampler, {
38
- operationName: spanName,
127
+ operationName: spanNameMapper(spanName, kind, attributes),
39
128
  context: spanContext._ddContext,
40
129
  startTime,
41
130
  hostname: _tracer._hostname,
@@ -46,6 +135,10 @@ class Span {
46
135
  }
47
136
  }, _tracer._debug)
48
137
 
138
+ if (attributes) {
139
+ this.setAttributes(attributes)
140
+ }
141
+
49
142
  this._parentTracer = parentTracer
50
143
  this._context = context
51
144
 
@@ -78,23 +78,22 @@ class Tracer {
78
78
  // return api.trace.wrapSpanContext(spanContext)
79
79
  // }
80
80
 
81
- const span = new Span(
81
+ return new Span(
82
82
  this,
83
83
  context,
84
84
  name,
85
85
  spanContext,
86
86
  spanKind,
87
87
  links,
88
- options.startTime
88
+ options.startTime,
89
+
90
+ // Set initial span attributes. The attributes object may have been mutated
91
+ // by the sampler, so we sanitize the merged attributes before setting them.
92
+ sanitizeAttributes(
93
+ // Object.assign(attributes, samplingResult.attributes)
94
+ attributes
95
+ )
89
96
  )
90
- // Set initial span attributes. The attributes object may have been mutated
91
- // by the sampler, so we sanitize the merged attributes before setting them.
92
- const initAttributes = sanitizeAttributes(
93
- // Object.assign(attributes, samplingResult.attributes)
94
- attributes
95
- )
96
- span.setAttributes(initAttributes)
97
- return span
98
97
  }
99
98
 
100
99
  startActiveSpan (name, options, context, fn) {
@@ -12,6 +12,7 @@ const runtimeMetrics = require('../runtime_metrics')
12
12
  const log = require('../log')
13
13
  const { storage } = require('../../../datadog-core')
14
14
  const telemetryMetrics = require('../telemetry/metrics')
15
+ const { channel } = require('dc-polyfill')
15
16
 
16
17
  const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
17
18
 
@@ -30,6 +31,8 @@ const integrationCounters = {
30
31
  span_finished: {}
31
32
  }
32
33
 
34
+ const finishCh = channel('dd-trace:span:finish')
35
+
33
36
  function getIntegrationCounter (event, integration) {
34
37
  const counters = integrationCounters[event]
35
38
 
@@ -176,6 +179,7 @@ class DatadogSpan {
176
179
  this._duration = finishTime - this._startTime
177
180
  this._spanContext._trace.finished.push(this)
178
181
  this._spanContext._isFinished = true
182
+ finishCh.publish(this)
179
183
  this._processor.process(this)
180
184
  }
181
185
 
@@ -2,6 +2,9 @@
2
2
 
3
3
  const { AUTO_KEEP } = require('../../../../ext/priority')
4
4
 
5
+ // the lowercase, hex encoded upper 64 bits of a 128-bit trace id, if present
6
+ const TRACE_ID_128 = '_dd.p.tid'
7
+
5
8
  class DatadogSpanContext {
6
9
  constructor (props) {
7
10
  props = props || {}
@@ -35,8 +38,8 @@ class DatadogSpanContext {
35
38
 
36
39
  toTraceparent () {
37
40
  const flags = this._sampling.priority >= AUTO_KEEP ? '01' : '00'
38
- const traceId = this._traceId.toBuffer().length <= 8 && this._trace.tags['_dd.p.tid']
39
- ? this._trace.tags['_dd.p.tid'] + this._traceId.toString(16).padStart(16, '0')
41
+ const traceId = this._traceId.toBuffer().length <= 8 && this._trace.tags[TRACE_ID_128]
42
+ ? this._trace.tags[TRACE_ID_128] + this._traceId.toString(16).padStart(16, '0')
40
43
  : this._traceId.toString(16).padStart(32, '0')
41
44
  const spanId = this._spanId.toString(16).padStart(16, '0')
42
45
  const version = (this._traceparent && this._traceparent.version) || '00'
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { channel } = require('../../diagnostics_channel')
3
+ const { channel } = require('dc-polyfill')
4
4
  const { isFalse } = require('./util')
5
5
  const plugins = require('./plugins')
6
6
  const log = require('./log')
@@ -36,7 +36,7 @@ class DatabasePlugin extends StoragePlugin {
36
36
  const { encodedDddbs, encodedDde, encodedDdps, encodedDdpv } = this.serviceTags
37
37
 
38
38
  return `dddbs='${encodedDddbs}',dde='${encodedDde}',` +
39
- `ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
39
+ `ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
40
40
  }
41
41
 
42
42
  getDbmServiceName (span, tracerService) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  // TODO: move anything related to tracing to TracingPlugin instead
4
4
 
5
- const dc = require('../../../diagnostics_channel')
5
+ const dc = require('dc-polyfill')
6
6
  const { storage } = require('../../../datadog-core')
7
7
 
8
8
  class Subscription {