dd-trace 4.6.0 → 4.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.
Files changed (91) hide show
  1. package/README.md +2 -2
  2. package/package.json +4 -4
  3. package/packages/datadog-core/src/storage/async_resource.js +4 -0
  4. package/packages/datadog-instrumentations/src/couchbase.js +4 -4
  5. package/packages/datadog-instrumentations/src/cucumber.js +5 -2
  6. package/packages/datadog-instrumentations/src/grpc/client.js +44 -42
  7. package/packages/datadog-instrumentations/src/grpc/server.js +69 -60
  8. package/packages/datadog-instrumentations/src/http2/client.js +25 -26
  9. package/packages/datadog-instrumentations/src/jest.js +9 -5
  10. package/packages/datadog-instrumentations/src/mocha.js +5 -3
  11. package/packages/datadog-plugin-cypress/src/plugin.js +4 -2
  12. package/packages/datadog-plugin-graphql/src/execute.js +6 -4
  13. package/packages/datadog-plugin-grpc/src/client.js +29 -11
  14. package/packages/datadog-plugin-grpc/src/server.js +22 -6
  15. package/packages/datadog-plugin-http2/src/client.js +46 -29
  16. package/packages/datadog-plugin-jest/src/index.js +8 -3
  17. package/packages/datadog-plugin-openai/src/index.js +39 -16
  18. package/packages/datadog-plugin-openai/src/services.js +13 -9
  19. package/packages/datadog-plugin-router/src/index.js +1 -1
  20. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +3 -1
  21. package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +3 -0
  22. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +7 -1
  23. package/packages/dd-trace/src/appsec/iast/analyzers/hsts-header-missing-analyzer.js +45 -0
  24. package/packages/dd-trace/src/appsec/iast/analyzers/index.js +3 -3
  25. package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +3 -0
  26. package/packages/dd-trace/src/appsec/iast/analyzers/missing-header-analyzer.js +66 -0
  27. package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +19 -15
  28. package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +5 -2
  29. package/packages/dd-trace/src/appsec/iast/analyzers/ssrf-analyzer.js +2 -0
  30. package/packages/dd-trace/src/appsec/iast/analyzers/unvalidated-redirect-analyzer.js +27 -8
  31. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +18 -19
  32. package/packages/dd-trace/src/appsec/iast/analyzers/weak-cipher-analyzer.js +3 -0
  33. package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +3 -0
  34. package/packages/dd-trace/src/appsec/iast/analyzers/xcontenttype-header-missing-analyzer.js +19 -0
  35. package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
  36. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +205 -0
  37. package/packages/dd-trace/src/appsec/iast/index.js +11 -7
  38. package/packages/dd-trace/src/appsec/iast/tags.js +2 -1
  39. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +6 -6
  40. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +7 -5
  41. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +23 -4
  42. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +49 -17
  43. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +33 -0
  44. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +23 -16
  45. package/packages/dd-trace/src/appsec/iast/taint-tracking/{origin-types.js → source-types.js} +1 -0
  46. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +76 -37
  47. package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +101 -0
  48. package/packages/dd-trace/src/appsec/iast/telemetry/index.js +45 -0
  49. package/packages/dd-trace/src/appsec/iast/telemetry/{logs.js → log/index.js} +5 -5
  50. package/packages/dd-trace/src/appsec/iast/telemetry/{log_collector.js → log/log-collector.js} +1 -1
  51. package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +76 -0
  52. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +53 -0
  53. package/packages/dd-trace/src/appsec/iast/telemetry/verbosity.js +42 -0
  54. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +5 -1
  55. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +3 -1
  56. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
  57. package/packages/dd-trace/src/config.js +47 -12
  58. package/packages/dd-trace/src/constants.js +1 -0
  59. package/packages/dd-trace/src/external-logger/src/index.js +9 -1
  60. package/packages/dd-trace/src/external-logger/test/index.spec.js +1 -1
  61. package/packages/dd-trace/src/format.js +1 -1
  62. package/packages/dd-trace/src/lambda/handler.js +8 -1
  63. package/packages/dd-trace/src/opentelemetry/span.js +3 -1
  64. package/packages/dd-trace/src/opentracing/span_context.js +2 -1
  65. package/packages/dd-trace/src/opentracing/tracer.js +1 -0
  66. package/packages/dd-trace/src/plugins/ci_plugin.js +6 -1
  67. package/packages/dd-trace/src/plugins/outbound.js +29 -12
  68. package/packages/dd-trace/src/plugins/plugin.js +28 -0
  69. package/packages/dd-trace/src/plugins/tracing.js +33 -16
  70. package/packages/dd-trace/src/plugins/util/ci.js +3 -2
  71. package/packages/dd-trace/src/plugins/util/test.js +55 -11
  72. package/packages/dd-trace/src/plugins/util/user-provided-git.js +1 -22
  73. package/packages/dd-trace/src/plugins/util/web.js +1 -0
  74. package/packages/dd-trace/src/profiling/config.js +8 -8
  75. package/packages/dd-trace/src/profiling/exporters/agent.js +4 -1
  76. package/packages/dd-trace/src/profiling/index.js +0 -2
  77. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  78. package/packages/dd-trace/src/profiling/profilers/wall.js +162 -10
  79. package/packages/dd-trace/src/service-naming/index.js +2 -2
  80. package/packages/dd-trace/src/service-naming/schemas/v0/graphql.js +12 -0
  81. package/packages/dd-trace/src/service-naming/schemas/v0/index.js +2 -1
  82. package/packages/dd-trace/src/service-naming/schemas/v1/graphql.js +12 -0
  83. package/packages/dd-trace/src/service-naming/schemas/v1/index.js +2 -1
  84. package/packages/dd-trace/src/span_processor.js +0 -4
  85. package/packages/dd-trace/src/span_sampler.js +1 -1
  86. package/packages/dd-trace/src/telemetry/dependencies.js +24 -12
  87. package/packages/dd-trace/src/telemetry/metrics.js +11 -1
  88. package/packages/diagnostics_channel/src/index.js +64 -0
  89. package/scripts/install_plugin_modules.js +1 -0
  90. package/packages/dd-trace/src/profiling/profilers/cpu.js +0 -126
  91. package/scripts/version.js +0 -66
@@ -0,0 +1,76 @@
1
+ 'use strict'
2
+
3
+ const log = require('../../../log')
4
+ const { Namespace } = require('../../../telemetry/metrics')
5
+ const { addMetricsToSpan, filterTags } = require('./span-tags')
6
+ const { IAST_TRACE_METRIC_PREFIX } = require('../tags')
7
+
8
+ const DD_IAST_METRICS_NAMESPACE = Symbol('_dd.iast.request.metrics.namespace')
9
+
10
+ function initRequestNamespace (context) {
11
+ if (!context) return
12
+
13
+ const namespace = new Namespace('iast')
14
+ context[DD_IAST_METRICS_NAMESPACE] = namespace
15
+ return namespace
16
+ }
17
+
18
+ function getNamespaceFromContext (context) {
19
+ return context && context[DD_IAST_METRICS_NAMESPACE]
20
+ }
21
+
22
+ function finalizeRequestNamespace (context, rootSpan) {
23
+ try {
24
+ const namespace = getNamespaceFromContext(context)
25
+ if (!namespace) return
26
+
27
+ const metrics = [...namespace.metrics.values()]
28
+ namespace.metrics.clear()
29
+
30
+ addMetricsToSpan(rootSpan, metrics, IAST_TRACE_METRIC_PREFIX)
31
+
32
+ merge(metrics)
33
+ } catch (e) {
34
+ log.error(e)
35
+ } finally {
36
+ if (context) {
37
+ delete context[DD_IAST_METRICS_NAMESPACE]
38
+ }
39
+ }
40
+ }
41
+
42
+ function merge (metrics) {
43
+ metrics.forEach(metric => metric.points.forEach(point => {
44
+ globalNamespace
45
+ .count(metric.metric, getTagsObject(metric.tags))
46
+ .inc(point[1])
47
+ }))
48
+ }
49
+
50
+ function getTagsObject (tags) {
51
+ if (tags && tags.length > 0) {
52
+ return filterTags(tags)
53
+ }
54
+ }
55
+
56
+ class IastNamespace extends Namespace {
57
+ constructor () {
58
+ super('iast')
59
+ }
60
+
61
+ reset () {
62
+ this.metrics.clear()
63
+ this.distributions.clear()
64
+ }
65
+ }
66
+
67
+ const globalNamespace = new IastNamespace()
68
+
69
+ module.exports = {
70
+ initRequestNamespace,
71
+ getNamespaceFromContext,
72
+ finalizeRequestNamespace,
73
+ globalNamespace,
74
+
75
+ DD_IAST_METRICS_NAMESPACE
76
+ }
@@ -0,0 +1,53 @@
1
+ 'use strict'
2
+
3
+ function addMetricsToSpan (rootSpan, metrics, tagPrefix) {
4
+ if (!rootSpan || !rootSpan.addTags || !metrics) return
5
+
6
+ const flattenMap = new Map()
7
+ metrics
8
+ .filter(data => data && data.metric)
9
+ .forEach(data => {
10
+ const name = taggedMetricName(data)
11
+ let total = flattenMap.get(name)
12
+ const value = flatten(data)
13
+ if (!total) {
14
+ total = value
15
+ } else {
16
+ total += value
17
+ }
18
+ flattenMap.set(name, total)
19
+ })
20
+
21
+ for (const [key, value] of flattenMap) {
22
+ const tagName = `${tagPrefix}.${key}`
23
+ rootSpan.addTags({
24
+ [tagName]: value
25
+ })
26
+ }
27
+ }
28
+
29
+ function flatten (metricData) {
30
+ return metricData.points && metricData.points.map(point => point[1]).reduce((total, value) => total + value, 0)
31
+ }
32
+
33
+ function taggedMetricName (data) {
34
+ const metric = data.metric
35
+ const tags = data.tags && filterTags(data.tags)
36
+ return !tags || !tags.length
37
+ ? metric
38
+ : `${metric}.${processTagValue(tags)}`
39
+ }
40
+
41
+ function filterTags (tags) {
42
+ return tags.filter(tag => !tag.startsWith('lib_language') && !tag.startsWith('version'))
43
+ }
44
+
45
+ function processTagValue (tags) {
46
+ return tags.map(tag => tag.includes(':') ? tag.split(':')[1] : tag)
47
+ .join('_').replace(/\./g, '_')
48
+ }
49
+
50
+ module.exports = {
51
+ addMetricsToSpan,
52
+ filterTags
53
+ }
@@ -0,0 +1,42 @@
1
+ 'use strict'
2
+
3
+ const Verbosity = {
4
+ OFF: 0,
5
+ MANDATORY: 1,
6
+ INFORMATION: 2,
7
+ DEBUG: 3
8
+ }
9
+
10
+ function isDebugAllowed (value) {
11
+ return value >= Verbosity.DEBUG
12
+ }
13
+
14
+ function isInfoAllowed (value) {
15
+ return value >= Verbosity.INFORMATION
16
+ }
17
+
18
+ function getVerbosity (verbosity) {
19
+ if (verbosity) {
20
+ verbosity = verbosity.toUpperCase()
21
+ return Verbosity[verbosity] !== undefined ? Verbosity[verbosity] : Verbosity.INFORMATION
22
+ } else {
23
+ return Verbosity.INFORMATION
24
+ }
25
+ }
26
+
27
+ function getName (verbosityValue) {
28
+ for (const name in Verbosity) {
29
+ if (Verbosity[name] === verbosityValue) {
30
+ return name
31
+ }
32
+ }
33
+ return 'OFF'
34
+ }
35
+
36
+ module.exports = {
37
+ Verbosity,
38
+ isDebugAllowed,
39
+ isInfoAllowed,
40
+ getVerbosity,
41
+ getName
42
+ }
@@ -54,7 +54,11 @@ class VulnerabilityFormatter {
54
54
 
55
55
  formatEvidence (type, evidence, sourcesIndexes, sources) {
56
56
  if (!evidence.ranges) {
57
- return { value: evidence.value }
57
+ if (typeof evidence.value === 'undefined') {
58
+ return undefined
59
+ } else {
60
+ return { value: evidence.value }
61
+ }
58
62
  }
59
63
 
60
64
  return this._redactVulnearbilities
@@ -1,5 +1,6 @@
1
1
  module.exports = {
2
2
  COMMAND_INJECTION: 'COMMAND_INJECTION',
3
+ HSTS_HEADER_MISSING: 'HSTS_HEADER_MISSING',
3
4
  INSECURE_COOKIE: 'INSECURE_COOKIE',
4
5
  LDAP_INJECTION: 'LDAP_INJECTION',
5
6
  NO_HTTPONLY_COOKIE: 'NO_HTTPONLY_COOKIE',
@@ -9,5 +10,6 @@ module.exports = {
9
10
  SSRF: 'SSRF',
10
11
  UNVALIDATED_REDIRECT: 'UNVALIDATED_REDIRECT',
11
12
  WEAK_CIPHER: 'WEAK_CIPHER',
12
- WEAK_HASH: 'WEAK_HASH'
13
+ WEAK_HASH: 'WEAK_HASH',
14
+ XCONTENTTYPE_HEADER_MISSING: 'XCONTENTTYPE_HEADER_MISSING'
13
15
  }
@@ -28,7 +28,7 @@ function addVulnerability (iastContext, vulnerability) {
28
28
 
29
29
  function isValidVulnerability (vulnerability) {
30
30
  return vulnerability && vulnerability.type &&
31
- vulnerability.evidence && vulnerability.evidence.value &&
31
+ vulnerability.evidence &&
32
32
  vulnerability.location && vulnerability.location.spanId
33
33
  }
34
34
 
@@ -247,6 +247,10 @@ class Config {
247
247
  process.env.DD_TELEMETRY_DEBUG,
248
248
  false
249
249
  )
250
+ const DD_TELEMETRY_METRICS_ENABLED = coalesce(
251
+ process.env.DD_TELEMETRY_METRICS_ENABLED,
252
+ false
253
+ )
250
254
  const DD_TRACE_AGENT_PROTOCOL_VERSION = coalesce(
251
255
  options.protocolVersion,
252
256
  process.env.DD_TRACE_AGENT_PROTOCOL_VERSION,
@@ -277,7 +281,7 @@ class Config {
277
281
  process.env.DD_TRACE_EXPERIMENTAL_B3_ENABLED,
278
282
  false
279
283
  )
280
- const defaultPropagationStyle = ['tracecontext', 'datadog']
284
+ const defaultPropagationStyle = ['datadog', 'tracecontext']
281
285
  if (isTrue(DD_TRACE_B3_ENABLED)) {
282
286
  defaultPropagationStyle.push('b3')
283
287
  defaultPropagationStyle.push('b3 single header')
@@ -317,13 +321,38 @@ class Config {
317
321
  false
318
322
  )
319
323
  const DD_TRACE_SPAN_ATTRIBUTE_SCHEMA = validateNamingVersion(
320
- process.env.DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
324
+ coalesce(
325
+ options.spanAttributeSchema,
326
+ process.env.DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
327
+ )
328
+ )
329
+ const DD_TRACE_PEER_SERVICE_MAPPING = coalesce(
330
+ options.peerServiceMapping,
331
+ process.env.DD_TRACE_PEER_SERVICE_MAPPING ? fromEntries(
332
+ process.env.DD_TRACE_PEER_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
333
+ ) : {}
334
+ )
335
+
336
+ const peerServiceSet = (
337
+ options.hasOwnProperty('spanComputePeerService') ||
338
+ process.env.hasOwnProperty('DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED')
339
+ )
340
+ const peerServiceValue = coalesce(
341
+ options.spanComputePeerService,
342
+ process.env.DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED
343
+ )
344
+
345
+ const DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED = (
346
+ DD_TRACE_SPAN_ATTRIBUTE_SCHEMA === 'v0'
347
+ // In v0, peer service is computed only if it is explicitly set to true
348
+ ? peerServiceSet && isTrue(peerServiceValue)
349
+ // In >v0, peer service is false only if it is explicitly set to false
350
+ : (peerServiceSet ? !isFalse(peerServiceValue) : true)
321
351
  )
322
- const DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED = process.env.DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED
323
352
 
324
353
  const DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED = coalesce(
325
- isTrue(process.env.DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED),
326
- false
354
+ options.spanRemoveIntegrationFromService,
355
+ isTrue(process.env.DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED)
327
356
  )
328
357
  const DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH = coalesce(
329
358
  process.env.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH,
@@ -461,6 +490,12 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
461
490
  true
462
491
  )
463
492
 
493
+ const DD_IAST_TELEMETRY_VERBOSITY = coalesce(
494
+ iastOptions && iastOptions.telemetryVerbosity,
495
+ process.env.DD_IAST_TELEMETRY_VERBOSITY,
496
+ 'INFORMATION'
497
+ )
498
+
464
499
  const DD_CIVISIBILITY_GIT_UPLOAD_ENABLED = coalesce(
465
500
  process.env.DD_CIVISIBILITY_GIT_UPLOAD_ENABLED,
466
501
  true
@@ -549,11 +584,9 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
549
584
  exporters: DD_PROFILING_EXPORTERS
550
585
  }
551
586
  this.spanAttributeSchema = DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
552
- this.spanComputePeerService = (this.spanAttributeSchema === 'v0'
553
- ? isTrue(DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED)
554
- : true
555
- )
556
- this.traceRemoveIntegrationServiceNamesEnabled = DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED
587
+ this.spanComputePeerService = DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED
588
+ this.spanRemoveIntegrationFromService = DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED
589
+ this.peerServiceMapping = DD_TRACE_PEER_SERVICE_MAPPING
557
590
  this.lookup = options.lookup
558
591
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
559
592
  // Disabled for CI Visibility's agentless
@@ -561,7 +594,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
561
594
  enabled: DD_TRACE_EXPORTER !== 'datadog' && isTrue(DD_TRACE_TELEMETRY_ENABLED),
562
595
  heartbeatInterval: DD_TELEMETRY_HEARTBEAT_INTERVAL,
563
596
  logCollection: isTrue(DD_TELEMETRY_LOG_COLLECTION_ENABLED),
564
- debug: isTrue(DD_TELEMETRY_DEBUG)
597
+ debug: isTrue(DD_TELEMETRY_DEBUG),
598
+ metrics: isTrue(DD_TELEMETRY_METRICS_ENABLED)
565
599
  }
566
600
  this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
567
601
  this.tagsHeaderMaxLength = parseInt(DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH)
@@ -590,7 +624,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
590
624
  maxConcurrentRequests: DD_IAST_MAX_CONCURRENT_REQUESTS,
591
625
  maxContextOperations: DD_IAST_MAX_CONTEXT_OPERATIONS,
592
626
  deduplicationEnabled: DD_IAST_DEDUPLICATION_ENABLED,
593
- redactionEnabled: DD_IAST_REDACTION_ENABLED
627
+ redactionEnabled: DD_IAST_REDACTION_ENABLED,
628
+ telemetryVerbosity: DD_IAST_TELEMETRY_VERBOSITY
594
629
  }
595
630
 
596
631
  this.isCiVisibility = isTrue(DD_IS_CIVISIBILITY)
@@ -28,6 +28,7 @@ module.exports = {
28
28
  CLIENT_PORT_KEY: 'network.destination.port',
29
29
  PEER_SERVICE_KEY: 'peer.service',
30
30
  PEER_SERVICE_SOURCE_KEY: '_dd.peer.service.source',
31
+ PEER_SERVICE_REMAP_KEY: '_dd.peer.service.remapped_from',
31
32
  SCI_REPOSITORY_URL: '_dd.git.repository_url',
32
33
  SCI_COMMIT_SHA: '_dd.git.commit.sha'
33
34
  }
@@ -127,4 +127,12 @@ class ExternalLogger {
127
127
  }
128
128
  }
129
129
 
130
- module.exports = ExternalLogger
130
+ class NoopExternalLogger {
131
+ log () { }
132
+ enqueue () { }
133
+ shutdown () { }
134
+ flush () { }
135
+ }
136
+
137
+ module.exports.ExternalLogger = ExternalLogger
138
+ module.exports.NoopExternalLogger = NoopExternalLogger
@@ -15,7 +15,7 @@ describe('External Logger', () => {
15
15
  beforeEach(() => {
16
16
  errorLog = sinon.spy(tracerLogger, 'error')
17
17
 
18
- const ExternalLogger = proxyquire('../src', {
18
+ const { ExternalLogger } = proxyquire('../src', {
19
19
  '../../log': {
20
20
  error: errorLog
21
21
  }
@@ -107,7 +107,7 @@ function extractTags (trace, span) {
107
107
  }
108
108
  }
109
109
 
110
- setSingleSpanIngestionTags(trace, context._sampling.spanSampling)
110
+ setSingleSpanIngestionTags(trace, context._spanSampling)
111
111
 
112
112
  addTag(trace.meta, trace.metrics, 'language', 'javascript')
113
113
  addTag(trace.meta, trace.metrics, PROCESS_ID, process.pid)
@@ -86,6 +86,13 @@ exports.datadog = function datadog (lambdaHandler) {
86
86
  const context = extractContext(args)
87
87
 
88
88
  checkTimeout(context)
89
- return lambdaHandler.apply(this, args).then((res) => { clearTimeout(__lambdaTimeout); return res })
89
+ const result = lambdaHandler.apply(this, args)
90
+ if (result && typeof result.then === 'function') {
91
+ return result.then((res) => {
92
+ clearTimeout(__lambdaTimeout)
93
+ return res
94
+ })
95
+ }
96
+ return result
90
97
  }
91
98
  }
@@ -10,6 +10,7 @@ const { timeInputToHrTime } = require('@opentelemetry/core')
10
10
  const tracer = require('../../')
11
11
  const DatadogSpan = require('../opentracing/span')
12
12
  const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../constants')
13
+ const { SERVICE_NAME, RESOURCE_NAME } = require('../../../../ext/tags')
13
14
 
14
15
  const SpanContext = require('./span_context')
15
16
 
@@ -40,7 +41,8 @@ class Span {
40
41
  hostname: _tracer._hostname,
41
42
  integrationName: 'otel',
42
43
  tags: {
43
- 'service.name': _tracer._service
44
+ [SERVICE_NAME]: _tracer._service,
45
+ [RESOURCE_NAME]: spanName
44
46
  }
45
47
  }, _tracer._debug)
46
48
 
@@ -12,7 +12,8 @@ class DatadogSpanContext {
12
12
  this._name = props.name
13
13
  this._isFinished = props.isFinished || false
14
14
  this._tags = props.tags || {}
15
- this._sampling = Object.assign({}, props.sampling)
15
+ this._sampling = props.sampling || {}
16
+ this._spanSampling = undefined
16
17
  this._baggageItems = props.baggageItems || {}
17
18
  this._traceparent = props.traceparent
18
19
  this._tracestate = props.tracestate
@@ -27,6 +27,7 @@ class DatadogTracer {
27
27
  this._env = config.env
28
28
  this._tags = config.tags
29
29
  this._computePeerService = config.spanComputePeerService
30
+ this._peerServiceMapping = config.peerServiceMapping
30
31
  this._logInjection = config.logInjection
31
32
  this._debug = config.debug
32
33
  this._prioritySampler = new PrioritySampler(config.env, config.sampler)
@@ -111,7 +111,12 @@ module.exports = class CiPlugin extends Plugin {
111
111
  const childOf = getTestParentSpan(this.tracer)
112
112
 
113
113
  let testTags = {
114
- ...getTestCommonTags(testName, testSuite, this.frameworkVersion),
114
+ ...getTestCommonTags(
115
+ testName,
116
+ testSuite,
117
+ this.frameworkVersion,
118
+ this.constructor.id
119
+ ),
115
120
  [COMPONENT]: this.constructor.id,
116
121
  ...extraTags
117
122
  }
@@ -3,7 +3,8 @@
3
3
  const {
4
4
  CLIENT_PORT_KEY,
5
5
  PEER_SERVICE_KEY,
6
- PEER_SERVICE_SOURCE_KEY
6
+ PEER_SERVICE_SOURCE_KEY,
7
+ PEER_SERVICE_REMAP_KEY
7
8
  } = require('../constants')
8
9
  const TracingPlugin = require('./tracing')
9
10
 
@@ -34,9 +35,11 @@ class OutboundPlugin extends TracingPlugin {
34
35
  * - If `peer.service` was defined _before_ we compute it (for example in custom instrumentation),
35
36
  * `_dd.peer.service.source`'s value is `peer.service`
36
37
  */
37
-
38
- if (tags['peer.service'] !== undefined) {
39
- return { [PEER_SERVICE_SOURCE_KEY]: 'peer.service' }
38
+ if (tags[PEER_SERVICE_KEY] !== undefined) {
39
+ return {
40
+ [PEER_SERVICE_KEY]: tags[PEER_SERVICE_KEY],
41
+ [PEER_SERVICE_SOURCE_KEY]: PEER_SERVICE_KEY
42
+ }
40
43
  }
41
44
 
42
45
  const sourceTags = [
@@ -52,23 +55,37 @@ class OutboundPlugin extends TracingPlugin {
52
55
  }
53
56
  }
54
57
  }
55
- return {}
58
+ return undefined
56
59
  }
57
60
 
58
- startSpan (name, options) {
59
- const span = super.startSpan(name, options)
60
- return span
61
+ getPeerServiceRemap (peerData) {
62
+ /**
63
+ * If DD_TRACE_PEER_SERVICE_MAPPING is matched, we need to override the existing
64
+ * peer service and add the value we overrode.
65
+ */
66
+ const peerService = peerData[PEER_SERVICE_KEY]
67
+ if (peerService && this.tracer._peerServiceMapping[peerService]) {
68
+ return {
69
+ ...peerData,
70
+ [PEER_SERVICE_KEY]: this.tracer._peerServiceMapping[peerService],
71
+ [PEER_SERVICE_REMAP_KEY]: peerService
72
+ }
73
+ }
74
+ return peerData
61
75
  }
62
76
 
63
77
  finish () {
64
- const span = this.activeSpan
78
+ this.tagPeerService(this.activeSpan)
79
+ super.finish(...arguments)
80
+ }
81
+
82
+ tagPeerService (span) {
65
83
  if (this.tracer._computePeerService) {
66
84
  const peerData = this.getPeerService(span.context()._tags)
67
- if (peerData) {
68
- span.addTags(peerData)
85
+ if (peerData !== undefined) {
86
+ span.addTags(this.getPeerServiceRemap(peerData))
69
87
  }
70
88
  }
71
- super.finish(...arguments)
72
89
  }
73
90
 
74
91
  connect (url) {
@@ -25,9 +25,31 @@ class Subscription {
25
25
  }
26
26
  }
27
27
 
28
+ class StoreBinding {
29
+ constructor (event, transform) {
30
+ this._channel = dc.channel(event)
31
+ this._transform = data => {
32
+ const store = storage.getStore()
33
+
34
+ return !store || !store.noop
35
+ ? transform(data)
36
+ : store
37
+ }
38
+ }
39
+
40
+ enable () {
41
+ this._channel.bindStore(storage, this._transform)
42
+ }
43
+
44
+ disable () {
45
+ this._channel.unbindStore(storage, this._transform)
46
+ }
47
+ }
48
+
28
49
  module.exports = class Plugin {
29
50
  constructor (tracer, tracerConfig) {
30
51
  this._subscriptions = []
52
+ this._bindings = []
31
53
  this._enabled = false
32
54
  this._tracer = tracer
33
55
  this.config = {} // plugin-specific configuration, unset until .configure() is called
@@ -53,6 +75,10 @@ module.exports = class Plugin {
53
75
  this._subscriptions.push(new Subscription(channelName, handler))
54
76
  }
55
77
 
78
+ addBind (channelName, transform) {
79
+ this._bindings.push(new StoreBinding(channelName, transform))
80
+ }
81
+
56
82
  addError (error) {
57
83
  const store = storage.getStore()
58
84
 
@@ -71,9 +97,11 @@ module.exports = class Plugin {
71
97
  if (config.enabled && !this._enabled) {
72
98
  this._enabled = true
73
99
  this._subscriptions.forEach(sub => sub.enable())
100
+ this._bindings.forEach(sub => sub.enable())
74
101
  } else if (!config.enabled && this._enabled) {
75
102
  this._enabled = false
76
103
  this._subscriptions.forEach(sub => sub.disable())
104
+ this._bindings.forEach(sub => sub.disable())
77
105
  }
78
106
  }
79
107
  }
@@ -13,17 +13,7 @@ class TracingPlugin extends Plugin {
13
13
  this.component = this.constructor.component || this.constructor.id
14
14
  this.operation = this.constructor.operation
15
15
 
16
- this.addTraceSub('start', message => {
17
- this.start(message)
18
- })
19
-
20
- this.addTraceSub('error', err => {
21
- this.error(err)
22
- })
23
-
24
- this.addTraceSub('finish', message => {
25
- this.finish(message)
26
- })
16
+ this.addTraceSubs()
27
17
  }
28
18
 
29
19
  get activeSpan () {
@@ -65,19 +55,43 @@ class TracingPlugin extends Plugin {
65
55
  this.addError(error)
66
56
  }
67
57
 
58
+ addTraceSubs () {
59
+ const events = ['start', 'end', 'asyncStart', 'asyncEnd', 'error', 'finish']
60
+
61
+ for (const event of events) {
62
+ const bindName = `bind${event.charAt(0).toUpperCase()}${event.slice(1)}`
63
+
64
+ if (this[event]) {
65
+ this.addTraceSub(event, message => {
66
+ this[event](message)
67
+ })
68
+ }
69
+
70
+ if (this[bindName]) {
71
+ this.addTraceBind(event, message => this[bindName](message))
72
+ }
73
+ }
74
+ }
75
+
68
76
  addTraceSub (eventName, handler) {
69
- this.addSub(`apm:${this.component}:${this.operation}:${eventName}`, handler)
77
+ const prefix = this.constructor.prefix || `apm:${this.component}:${this.operation}`
78
+ this.addSub(`${prefix}:${eventName}`, handler)
70
79
  }
71
80
 
72
- addError (error) {
73
- const span = this.activeSpan
81
+ addTraceBind (eventName, transform) {
82
+ const prefix = this.constructor.prefix || `apm:${this.component}:${this.operation}`
83
+ this.addBind(`${prefix}:${eventName}`, transform)
84
+ }
74
85
 
86
+ addError (error, span = this.activeSpan) {
75
87
  if (!span._spanContext._tags['error']) {
88
+ // Errors may be wrapped in a context.
89
+ error = (error && error.error) || error
76
90
  span.setTag('error', error || 1)
77
91
  }
78
92
  }
79
93
 
80
- startSpan (name, { childOf, kind, meta, metrics, service, resource, type } = {}) {
94
+ startSpan (name, { childOf, kind, meta, metrics, service, resource, type } = {}, enter = true) {
81
95
  const store = storage.getStore()
82
96
 
83
97
  if (store && childOf === undefined) {
@@ -100,7 +114,10 @@ class TracingPlugin extends Plugin {
100
114
 
101
115
  analyticsSampler.sample(span, this.config.measured)
102
116
 
103
- storage.enterWith({ ...store, span })
117
+ // TODO: Remove this after migration to TracingChannel is done.
118
+ if (enter) {
119
+ storage.enterWith({ ...store, span })
120
+ }
104
121
 
105
122
  return span
106
123
  }
@@ -77,7 +77,7 @@ function filterSensitiveInfoFromRepository (repositoryUrl) {
77
77
 
78
78
  return `${protocol}//${hostname}${pathname}`
79
79
  } catch (e) {
80
- return repositoryUrl
80
+ return ''
81
81
  }
82
82
  }
83
83
 
@@ -399,6 +399,7 @@ module.exports = {
399
399
  BITBUCKET_BRANCH,
400
400
  BITBUCKET_COMMIT,
401
401
  BITBUCKET_GIT_SSH_ORIGIN,
402
+ BITBUCKET_GIT_HTTP_ORIGIN,
402
403
  BITBUCKET_TAG,
403
404
  BITBUCKET_PIPELINE_UUID,
404
405
  BITBUCKET_CLONE_DIR
@@ -416,7 +417,7 @@ module.exports = {
416
417
  [CI_PIPELINE_URL]: url,
417
418
  [GIT_BRANCH]: BITBUCKET_BRANCH,
418
419
  [GIT_TAG]: BITBUCKET_TAG,
419
- [GIT_REPOSITORY_URL]: BITBUCKET_GIT_SSH_ORIGIN,
420
+ [GIT_REPOSITORY_URL]: BITBUCKET_GIT_SSH_ORIGIN || BITBUCKET_GIT_HTTP_ORIGIN,
420
421
  [CI_WORKSPACE_PATH]: BITBUCKET_CLONE_DIR,
421
422
  [CI_PIPELINE_ID]: BITBUCKET_PIPELINE_UUID && BITBUCKET_PIPELINE_UUID.replace(/{|}/gm, '')
422
423
  }