dd-trace 4.42.0 → 4.44.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 (75) hide show
  1. package/LICENSE-3rdparty.csv +0 -2
  2. package/ext/formats.d.ts +1 -0
  3. package/ext/formats.js +2 -1
  4. package/index.d.ts +61 -39
  5. package/init.js +3 -15
  6. package/package.json +9 -12
  7. package/packages/datadog-instrumentations/src/child_process.js +2 -2
  8. package/packages/datadog-instrumentations/src/fs.js +1 -1
  9. package/packages/datadog-instrumentations/src/hapi.js +1 -1
  10. package/packages/datadog-instrumentations/src/helpers/register.js +13 -11
  11. package/packages/datadog-instrumentations/src/http/client.js +8 -2
  12. package/packages/datadog-instrumentations/src/http/server.js +50 -13
  13. package/packages/datadog-instrumentations/src/jest.js +17 -2
  14. package/packages/datadog-instrumentations/src/kafkajs.js +1 -1
  15. package/packages/datadog-instrumentations/src/ldapjs.js +2 -2
  16. package/packages/datadog-instrumentations/src/mocha/main.js +21 -8
  17. package/packages/datadog-instrumentations/src/mquery.js +2 -2
  18. package/packages/datadog-instrumentations/src/next.js +1 -1
  19. package/packages/datadog-instrumentations/src/pg.js +2 -2
  20. package/packages/datadog-instrumentations/src/playwright.js +46 -32
  21. package/packages/datadog-instrumentations/src/process.js +29 -0
  22. package/packages/datadog-instrumentations/src/restify.js +1 -1
  23. package/packages/datadog-instrumentations/src/vitest.js +98 -28
  24. package/packages/datadog-plugin-aws-sdk/src/base.js +16 -2
  25. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -1
  26. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  27. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -1
  28. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +3 -3
  29. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
  30. package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +6 -4
  31. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +114 -48
  32. package/packages/datadog-plugin-cypress/src/plugin.js +4 -3
  33. package/packages/datadog-plugin-fs/src/index.js +1 -1
  34. package/packages/datadog-plugin-jest/src/index.js +7 -1
  35. package/packages/datadog-plugin-kafkajs/src/producer.js +1 -1
  36. package/packages/datadog-plugin-mongodb-core/src/index.js +1 -1
  37. package/packages/datadog-plugin-openai/src/index.js +5 -5
  38. package/packages/datadog-plugin-playwright/src/index.js +4 -1
  39. package/packages/datadog-plugin-sharedb/src/index.js +1 -1
  40. package/packages/datadog-plugin-vitest/src/index.js +19 -7
  41. package/packages/dd-trace/src/analytics_sampler.js +1 -1
  42. package/packages/dd-trace/src/appsec/blocking.js +10 -1
  43. package/packages/dd-trace/src/appsec/channels.js +4 -1
  44. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  45. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +16 -0
  46. package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +1 -1
  47. package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +2 -0
  48. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +2 -1
  49. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +2 -2
  50. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +2 -2
  51. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +11 -0
  52. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/code-injection-sensitive-analyzer.js +25 -0
  53. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -0
  54. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +2 -2
  55. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +3 -1
  56. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  57. package/packages/dd-trace/src/appsec/index.js +15 -10
  58. package/packages/dd-trace/src/appsec/passport.js +1 -1
  59. package/packages/dd-trace/src/appsec/rasp.js +121 -7
  60. package/packages/dd-trace/src/appsec/recommended.json +220 -2
  61. package/packages/dd-trace/src/appsec/reporter.js +0 -4
  62. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +1 -1
  63. package/packages/dd-trace/src/config.js +68 -66
  64. package/packages/dd-trace/src/data_streams.js +44 -0
  65. package/packages/dd-trace/src/datastreams/pathway.js +4 -2
  66. package/packages/dd-trace/src/datastreams/processor.js +1 -1
  67. package/packages/dd-trace/src/log/index.js +32 -0
  68. package/packages/dd-trace/src/opentelemetry/span.js +1 -1
  69. package/packages/dd-trace/src/opentelemetry/tracer.js +6 -0
  70. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +43 -0
  71. package/packages/dd-trace/src/opentracing/tracer.js +10 -6
  72. package/packages/dd-trace/src/plugins/ci_plugin.js +9 -2
  73. package/packages/dd-trace/src/plugins/plugin.js +12 -1
  74. package/packages/dd-trace/src/proxy.js +1 -0
  75. package/packages/dd-trace/src/tracer.js +2 -0
@@ -29,14 +29,14 @@ const telemetryCounters = {
29
29
  function getCounter (event, ddVar, otelVar) {
30
30
  const counters = telemetryCounters[event]
31
31
  const tags = []
32
- const ddVarPrefix = 'config.datadog:'
33
- const otelVarPrefix = 'config.opentelemetry:'
32
+ const ddVarPrefix = 'config_datadog:'
33
+ const otelVarPrefix = 'config_opentelemetry:'
34
34
  if (ddVar) {
35
- ddVar = ddVarPrefix + ddVar
35
+ ddVar = ddVarPrefix + ddVar.toLowerCase()
36
36
  tags.push(ddVar)
37
37
  }
38
38
  if (otelVar) {
39
- otelVar = otelVarPrefix + otelVar
39
+ otelVar = otelVarPrefix + otelVar.toLowerCase()
40
40
  tags.push(otelVar)
41
41
  }
42
42
 
@@ -134,7 +134,7 @@ const fromEntries = Object.fromEntries || (entries =>
134
134
  // eslint-disable-next-line max-len
135
135
  const qsRegex = '(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:(?:\\s|%20)*(?:=|%3D)[^&]+|(?:"|%22)(?:\\s|%20)*(?::|%3A)(?:\\s|%20)*(?:"|%22)(?:%2[^2]|%[^2]|[^"%])+(?:"|%22))|bearer(?:\\s|%20)+[a-z0-9\\._\\-]+|token(?::|%3A)[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L](?:[\\w=-]|%3D)+\\.ey[I-L](?:[\\w=-]|%3D)+(?:\\.(?:[\\w.+\\/=-]|%3D|%2F|%2B)+)?|[\\-]{5}BEGIN(?:[a-z\\s]|%20)+PRIVATE(?:\\s|%20)KEY[\\-]{5}[^\\-]+[\\-]{5}END(?:[a-z\\s]|%20)+PRIVATE(?:\\s|%20)KEY|ssh-rsa(?:\\s|%20)*(?:[a-z0-9\\/\\.+]|%2F|%5C|%2B){100,}'
136
136
  // eslint-disable-next-line max-len
137
- const defaultWafObfuscatorKeyRegex = '(?i)(?:p(?:ass)?w(?:or)?d|pass(?:[_-]?phrase)?|secret(?:[_-]?key)?|(?:(?:api|private|public|access)[_-]?)key)|(?:(?:auth|access|id|refresh)[_-]?)?token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)|bearer|authorization|jsessionid|phpsessid|asp\\.net[_-]sessionid|sid|jwt'
137
+ const defaultWafObfuscatorKeyRegex = '(?i)pass|pw(?:or)?d|secret|(?:api|private|public|access)[_-]?key|token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)|bearer|authorization|jsessionid|phpsessid|asp\\.net[_-]sessionid|sid|jwt'
138
138
  // eslint-disable-next-line max-len
139
139
  const defaultWafObfuscatorValueRegex = '(?i)(?:p(?:ass)?w(?:or)?d|pass(?:[_-]?phrase)?|secret(?:[_-]?key)?|(?:(?:api|private|public|access)[_-]?)key(?:[_-]?id)?|(?:(?:auth|access|id|refresh)[_-]?)?token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?|jsessionid|phpsessid|asp\\.net(?:[_-]|-)sessionid|sid|jwt)(?:\\s*=[^;]|"\\s*:\\s*"[^"]+")|bearer\\s+[a-z0-9\\._\\-]+|token:[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L][\\w=-]+\\.ey[I-L][\\w=-]+(?:\\.[\\w.+\\/=-]+)?|[\\-]{5}BEGIN[a-z\\s]+PRIVATE\\sKEY[\\-]{5}[^\\-]+[\\-]{5}END[a-z\\s]+PRIVATE\\sKEY|ssh-rsa\\s*[a-z0-9\\/\\.+]{100,}'
140
140
  const runtimeId = uuid()
@@ -185,7 +185,7 @@ function remapify (input, mappings) {
185
185
 
186
186
  function propagationStyle (key, option, defaultValue) {
187
187
  // Extract by key if in object-form value
188
- if (typeof option === 'object' && !Array.isArray(option)) {
188
+ if (option !== null && typeof option === 'object' && !Array.isArray(option)) {
189
189
  option = option[key]
190
190
  }
191
191
 
@@ -193,7 +193,7 @@ function propagationStyle (key, option, defaultValue) {
193
193
  if (Array.isArray(option)) return option.map(v => v.toLowerCase())
194
194
 
195
195
  // If it's not an array but not undefined there's something wrong with the input
196
- if (typeof option !== 'undefined') {
196
+ if (option !== undefined) {
197
197
  log.warn('Unexpected input for config.tracePropagationStyle')
198
198
  }
199
199
 
@@ -201,7 +201,7 @@ function propagationStyle (key, option, defaultValue) {
201
201
  const envKey = `DD_TRACE_PROPAGATION_STYLE_${key.toUpperCase()}`
202
202
 
203
203
  const envVar = coalesce(process.env[envKey], process.env.DD_TRACE_PROPAGATION_STYLE, process.env.OTEL_PROPAGATORS)
204
- if (typeof envVar !== 'undefined') {
204
+ if (envVar !== undefined) {
205
205
  return envVar.split(',')
206
206
  .filter(v => v !== '')
207
207
  .map(v => v.trim().toLowerCase())
@@ -211,33 +211,23 @@ function propagationStyle (key, option, defaultValue) {
211
211
  }
212
212
 
213
213
  class Config {
214
- constructor (options) {
215
- options = options || {}
216
- options = this.options = {
214
+ constructor (options = {}) {
215
+ options = {
217
216
  ...options,
218
217
  appsec: options.appsec != null ? options.appsec : options.experimental?.appsec,
219
- iastOptions: options.experimental?.iast
218
+ iast: options.iast != null ? options.iast : options.experimental?.iast
220
219
  }
221
220
 
222
- checkIfBothOtelAndDdEnvVarSet()
223
-
224
221
  // Configure the logger first so it can be used to warn about other configs
225
- this.debug = isTrue(coalesce(
226
- process.env.DD_TRACE_DEBUG,
227
- process.env.OTEL_LOG_LEVEL && process.env.OTEL_LOG_LEVEL === 'debug',
228
- false
229
- ))
230
- this.logger = options.logger
231
-
232
- this.logLevel = coalesce(
233
- options.logLevel,
234
- process.env.DD_TRACE_LOG_LEVEL,
235
- process.env.OTEL_LOG_LEVEL,
236
- 'debug'
237
- )
222
+ const logConfig = log.getConfig()
223
+ this.debug = logConfig.enabled
224
+ this.logger = coalesce(options.logger, logConfig.logger)
225
+ this.logLevel = coalesce(options.logLevel, logConfig.logLevel)
238
226
 
239
227
  log.use(this.logger)
240
- log.toggle(this.debug, this.logLevel, this)
228
+ log.toggle(this.debug, this.logLevel)
229
+
230
+ checkIfBothOtelAndDdEnvVarSet()
241
231
 
242
232
  const DD_TRACE_MEMCACHED_COMMAND_ENABLED = coalesce(
243
233
  process.env.DD_TRACE_MEMCACHED_COMMAND_ENABLED,
@@ -486,14 +476,14 @@ class Config {
486
476
  pkg.name ||
487
477
  'node'
488
478
 
489
- const defaults = this._defaults = {}
479
+ const defaults = setHiddenProperty(this, '_defaults', {})
490
480
 
491
481
  this._setValue(defaults, 'appsec.blockedTemplateHtml', undefined)
492
482
  this._setValue(defaults, 'appsec.blockedTemplateJson', undefined)
493
483
  this._setValue(defaults, 'appsec.enabled', undefined)
494
484
  this._setValue(defaults, 'appsec.obfuscatorKeyRegex', defaultWafObfuscatorKeyRegex)
495
485
  this._setValue(defaults, 'appsec.obfuscatorValueRegex', defaultWafObfuscatorValueRegex)
496
- this._setValue(defaults, 'appsec.rasp.enabled', false)
486
+ this._setValue(defaults, 'appsec.rasp.enabled', true)
497
487
  this._setValue(defaults, 'appsec.rateLimit', 100)
498
488
  this._setValue(defaults, 'appsec.rules', undefined)
499
489
  this._setValue(defaults, 'appsec.sca.enabled', null)
@@ -671,8 +661,8 @@ class Config {
671
661
  } = process.env
672
662
 
673
663
  const tags = {}
674
- const env = this._env = {}
675
- this._envUnprocessed = {}
664
+ const env = setHiddenProperty(this, '_env', {})
665
+ setHiddenProperty(this, '_envUnprocessed', {})
676
666
 
677
667
  tagger.add(tags, OTEL_RESOURCE_ATTRIBUTES, true)
678
668
  tagger.add(tags, DD_TAGS)
@@ -812,11 +802,11 @@ class Config {
812
802
  }
813
803
 
814
804
  _applyOptions (options) {
815
- const opts = this._options = this._options || {}
805
+ const opts = setHiddenProperty(this, '_options', this._options || {})
816
806
  const tags = {}
817
- this._optsUnprocessed = {}
807
+ setHiddenProperty(this, '_optsUnprocessed', {})
818
808
 
819
- options = this.options = Object.assign({ ingestion: {} }, options, opts)
809
+ options = setHiddenProperty(this, '_optionsArg', Object.assign({ ingestion: {} }, options, opts))
820
810
 
821
811
  tagger.add(tags, options.tags)
822
812
 
@@ -858,23 +848,23 @@ class Config {
858
848
  this._optsUnprocessed.flushMinSpans = options.flushMinSpans
859
849
  this._setArray(opts, 'headerTags', options.headerTags)
860
850
  this._setString(opts, 'hostname', options.hostname)
861
- this._setBoolean(opts, 'iast.deduplicationEnabled', options.iastOptions && options.iastOptions.deduplicationEnabled)
851
+ this._setBoolean(opts, 'iast.deduplicationEnabled', options.iast && options.iast.deduplicationEnabled)
862
852
  this._setBoolean(opts, 'iast.enabled',
863
- options.iastOptions && (options.iastOptions === true || options.iastOptions.enabled === true))
853
+ options.iast && (options.iast === true || options.iast.enabled === true))
864
854
  this._setValue(opts, 'iast.maxConcurrentRequests',
865
- maybeInt(options.iastOptions?.maxConcurrentRequests))
866
- this._optsUnprocessed['iast.maxConcurrentRequests'] = options.iastOptions?.maxConcurrentRequests
867
- this._setValue(opts, 'iast.maxContextOperations', maybeInt(options.iastOptions?.maxContextOperations))
868
- this._optsUnprocessed['iast.maxContextOperations'] = options.iastOptions?.maxContextOperations
869
- this._setBoolean(opts, 'iast.redactionEnabled', options.iastOptions?.redactionEnabled)
870
- this._setString(opts, 'iast.redactionNamePattern', options.iastOptions?.redactionNamePattern)
871
- this._setString(opts, 'iast.redactionValuePattern', options.iastOptions?.redactionValuePattern)
872
- const iastRequestSampling = maybeInt(options.iastOptions?.requestSampling)
855
+ maybeInt(options.iast?.maxConcurrentRequests))
856
+ this._optsUnprocessed['iast.maxConcurrentRequests'] = options.iast?.maxConcurrentRequests
857
+ this._setValue(opts, 'iast.maxContextOperations', maybeInt(options.iast?.maxContextOperations))
858
+ this._optsUnprocessed['iast.maxContextOperations'] = options.iast?.maxContextOperations
859
+ this._setBoolean(opts, 'iast.redactionEnabled', options.iast?.redactionEnabled)
860
+ this._setString(opts, 'iast.redactionNamePattern', options.iast?.redactionNamePattern)
861
+ this._setString(opts, 'iast.redactionValuePattern', options.iast?.redactionValuePattern)
862
+ const iastRequestSampling = maybeInt(options.iast?.requestSampling)
873
863
  if (iastRequestSampling > -1 && iastRequestSampling < 101) {
874
864
  this._setValue(opts, 'iast.requestSampling', iastRequestSampling)
875
- this._optsUnprocessed['iast.requestSampling'] = options.iastOptions?.requestSampling
865
+ this._optsUnprocessed['iast.requestSampling'] = options.iast?.requestSampling
876
866
  }
877
- this._setString(opts, 'iast.telemetryVerbosity', options.iastOptions && options.iastOptions.telemetryVerbosity)
867
+ this._setString(opts, 'iast.telemetryVerbosity', options.iast && options.iast.telemetryVerbosity)
878
868
  this._setBoolean(opts, 'isCiVisibility', options.isCiVisibility)
879
869
  this._setBoolean(opts, 'logInjection', options.logInjection)
880
870
  this._setString(opts, 'lookup', options.lookup)
@@ -904,7 +894,7 @@ class Config {
904
894
  this._setBoolean(opts, 'startupLogs', options.startupLogs)
905
895
  this._setTags(opts, 'tags', tags)
906
896
  const hasTelemetryLogsUsingFeatures =
907
- (options.iastOptions && (options.iastOptions === true || options.iastOptions?.enabled === true)) ||
897
+ (options.iast && (options.iast === true || options.iast?.enabled === true)) ||
908
898
  (options.profiling && options.profiling === true)
909
899
  this._setBoolean(opts, 'telemetry.logCollection', hasTelemetryLogsUsingFeatures)
910
900
  this._setBoolean(opts, 'traceId128BitGenerationEnabled', options.traceId128BitGenerationEnabled)
@@ -914,7 +904,7 @@ class Config {
914
904
 
915
905
  _isCiVisibility () {
916
906
  return coalesce(
917
- this.options.isCiVisibility,
907
+ this._optionsArg.isCiVisibility,
918
908
  this._defaults.isCiVisibility
919
909
  )
920
910
  }
@@ -930,9 +920,9 @@ class Config {
930
920
  const DD_CIVISIBILITY_AGENTLESS_URL = process.env.DD_CIVISIBILITY_AGENTLESS_URL
931
921
  const url = DD_CIVISIBILITY_AGENTLESS_URL
932
922
  ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
933
- : getAgentUrl(this._getTraceAgentUrl(), this.options)
923
+ : getAgentUrl(this._getTraceAgentUrl(), this._optionsArg)
934
924
  const DD_AGENT_HOST = coalesce(
935
- this.options.hostname,
925
+ this._optionsArg.hostname,
936
926
  process.env.DD_AGENT_HOST,
937
927
  process.env.DD_TRACE_AGENT_HOSTNAME,
938
928
  '127.0.0.1'
@@ -943,17 +933,17 @@ class Config {
943
933
  _getSpanComputePeerService () {
944
934
  const DD_TRACE_SPAN_ATTRIBUTE_SCHEMA = validateNamingVersion(
945
935
  coalesce(
946
- this.options.spanAttributeSchema,
936
+ this._optionsArg.spanAttributeSchema,
947
937
  process.env.DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
948
938
  )
949
939
  )
950
940
 
951
941
  const peerServiceSet = (
952
- this.options.hasOwnProperty('spanComputePeerService') ||
942
+ this._optionsArg.hasOwnProperty('spanComputePeerService') ||
953
943
  process.env.hasOwnProperty('DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED')
954
944
  )
955
945
  const peerServiceValue = coalesce(
956
- this.options.spanComputePeerService,
946
+ this._optionsArg.spanComputePeerService,
957
947
  process.env.DD_TRACE_PEER_SERVICE_DEFAULTS_ENABLED
958
948
  )
959
949
 
@@ -984,7 +974,7 @@ class Config {
984
974
 
985
975
  _isTraceStatsComputationEnabled () {
986
976
  return coalesce(
987
- this.options.stats,
977
+ this._optionsArg.stats,
988
978
  process.env.DD_TRACE_STATS_COMPUTATION_ENABLED,
989
979
  getIsGCPFunction() || getIsAzureFunction()
990
980
  )
@@ -992,7 +982,7 @@ class Config {
992
982
 
993
983
  _getTraceAgentUrl () {
994
984
  return coalesce(
995
- this.options.url,
985
+ this._optionsArg.url,
996
986
  process.env.DD_TRACE_AGENT_URL,
997
987
  process.env.DD_TRACE_URL,
998
988
  null
@@ -1001,7 +991,7 @@ class Config {
1001
991
 
1002
992
  // handles values calculated from a mixture of options and env vars
1003
993
  _applyCalculated () {
1004
- const calc = this._calculated = {}
994
+ const calc = setHiddenProperty(this, '_calculated', {})
1005
995
 
1006
996
  const {
1007
997
  DD_CIVISIBILITY_AGENTLESS_URL
@@ -1010,7 +1000,7 @@ class Config {
1010
1000
  if (DD_CIVISIBILITY_AGENTLESS_URL) {
1011
1001
  this._setValue(calc, 'url', new URL(DD_CIVISIBILITY_AGENTLESS_URL))
1012
1002
  } else {
1013
- this._setValue(calc, 'url', getAgentUrl(this._getTraceAgentUrl(), this.options))
1003
+ this._setValue(calc, 'url', getAgentUrl(this._getTraceAgentUrl(), this._optionsArg))
1014
1004
  }
1015
1005
  if (this._isCiVisibility()) {
1016
1006
  this._setBoolean(calc, 'isEarlyFlakeDetectionEnabled',
@@ -1026,8 +1016,8 @@ class Config {
1026
1016
  }
1027
1017
 
1028
1018
  _applyRemote (options) {
1029
- const opts = this._remote = this._remote || {}
1030
- this._remoteUnprocessed = {}
1019
+ const opts = setHiddenProperty(this, '_remote', this._remote || {})
1020
+ setHiddenProperty(this, '_remoteUnprocessed', {})
1031
1021
  const tags = {}
1032
1022
  const headerTags = options.tracing_header_tags
1033
1023
  ? options.tracing_header_tags.map(tag => {
@@ -1043,15 +1033,18 @@ class Config {
1043
1033
  this._setArray(opts, 'headerTags', headerTags)
1044
1034
  this._setTags(opts, 'tags', tags)
1045
1035
  this._setBoolean(opts, 'tracing', options.tracing_enabled)
1046
- // ignore tags for now since rc sampling rule tags format is not supported
1047
- this._setSamplingRule(opts, 'sampler.rules', this._ignoreTags(options.tracing_sampling_rules))
1048
1036
  this._remoteUnprocessed['sampler.rules'] = options.tracing_sampling_rules
1037
+ this._setSamplingRule(opts, 'sampler.rules', this._reformatTags(options.tracing_sampling_rules))
1049
1038
  }
1050
1039
 
1051
- _ignoreTags (samplingRules) {
1052
- if (samplingRules) {
1053
- for (const rule of samplingRules) {
1054
- delete rule.tags
1040
+ _reformatTags (samplingRules) {
1041
+ for (const rule of (samplingRules || [])) {
1042
+ const reformattedTags = {}
1043
+ if (rule.tags) {
1044
+ for (const tag of (rule.tags || {})) {
1045
+ reformattedTags[tag.key] = tag.value_glob
1046
+ }
1047
+ rule.tags = reformattedTags
1055
1048
  }
1056
1049
  }
1057
1050
  return samplingRules
@@ -1193,4 +1186,13 @@ function getAgentUrl (url, options) {
1193
1186
  }
1194
1187
  }
1195
1188
 
1189
+ function setHiddenProperty (obj, name, value) {
1190
+ Object.defineProperty(obj, name, {
1191
+ value,
1192
+ enumerable: false,
1193
+ writable: true
1194
+ })
1195
+ return obj[name]
1196
+ }
1197
+
1196
1198
  module.exports = Config
@@ -0,0 +1,44 @@
1
+ const DataStreamsContext = require('./data_streams_context')
2
+
3
+ class DataStreamsCheckpointer {
4
+ constructor (tracer) {
5
+ this.tracer = tracer
6
+ this.config = tracer._config
7
+ this.dsmProcessor = tracer._dataStreamsProcessor
8
+ }
9
+
10
+ setProduceCheckpoint (type, target, carrier) {
11
+ if (!this.config.dsmEnabled) return
12
+
13
+ const ctx = this.dsmProcessor.setCheckpoint(
14
+ ['type:' + type, 'topic:' + target, 'direction:out', 'manual_checkpoint:true'],
15
+ null,
16
+ DataStreamsContext.getDataStreamsContext(),
17
+ null
18
+ )
19
+ DataStreamsContext.setDataStreamsContext(ctx)
20
+
21
+ this.tracer.inject(ctx, 'text_map_dsm', carrier)
22
+ }
23
+
24
+ setConsumeCheckpoint (type, source, carrier) {
25
+ if (!this.config.dsmEnabled) return
26
+
27
+ const parentCtx = this.tracer.extract('text_map_dsm', carrier)
28
+ DataStreamsContext.setDataStreamsContext(parentCtx)
29
+
30
+ const ctx = this.dsmProcessor.setCheckpoint(
31
+ ['type:' + type, 'topic:' + source, 'direction:in', 'manual_checkpoint:true'],
32
+ null,
33
+ parentCtx,
34
+ null
35
+ )
36
+ DataStreamsContext.setDataStreamsContext(ctx)
37
+
38
+ return ctx
39
+ }
40
+ }
41
+
42
+ module.exports = {
43
+ DataStreamsCheckpointer
44
+ }
@@ -17,11 +17,13 @@ function shaHash (checkpointString) {
17
17
  }
18
18
 
19
19
  function computeHash (service, env, edgeTags, parentHash) {
20
- const key = `${service}${env}` + edgeTags.join('') + parentHash.toString()
20
+ const hashableEdgeTags = edgeTags.filter(item => item !== 'manual_checkpoint:true')
21
+
22
+ const key = `${service}${env}` + hashableEdgeTags.join('') + parentHash.toString()
21
23
  if (cache.get(key)) {
22
24
  return cache.get(key)
23
25
  }
24
- const currentHash = shaHash(`${service}${env}` + edgeTags.join(''))
26
+ const currentHash = shaHash(`${service}${env}` + hashableEdgeTags.join(''))
25
27
  const buf = Buffer.concat([currentHash, parentHash], 16)
26
28
  const val = shaHash(buf.toString())
27
29
  cache.set(key, val)
@@ -132,7 +132,7 @@ function getSizeOrZero (obj) {
132
132
  })
133
133
  return payloadSize
134
134
  }
135
- if (typeof obj === 'object') {
135
+ if (obj !== null && typeof obj === 'object') {
136
136
  try {
137
137
  return getHeadersSize(obj)
138
138
  } catch {
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const coalesce = require('koalas')
4
+ const { isTrue } = require('../util')
3
5
  const { debugChannel, infoChannel, warnChannel, errorChannel } = require('./channels')
4
6
  const logWriter = require('./writer')
5
7
 
@@ -20,13 +22,29 @@ function processMsg (msg) {
20
22
  return typeof msg === 'function' ? msg() : msg
21
23
  }
22
24
 
25
+ const config = {
26
+ enabled: false,
27
+ logger: undefined,
28
+ logLevel: 'debug'
29
+ }
30
+
23
31
  const log = {
32
+ /**
33
+ * @returns Read-only version of logging config. To modify config, call `log.use` and `log.toggle`
34
+ */
35
+ getConfig () {
36
+ return { ...config }
37
+ },
38
+
24
39
  use (logger) {
40
+ config.logger = logger
25
41
  logWriter.use(logger)
26
42
  return this
27
43
  },
28
44
 
29
45
  toggle (enabled, logLevel) {
46
+ config.enabled = enabled
47
+ config.logLevel = logLevel
30
48
  logWriter.toggle(enabled, logLevel)
31
49
  return this
32
50
  },
@@ -76,4 +94,18 @@ const log = {
76
94
 
77
95
  log.reset()
78
96
 
97
+ const enabled = isTrue(coalesce(
98
+ process.env.DD_TRACE_DEBUG,
99
+ process.env.OTEL_LOG_LEVEL === 'debug',
100
+ config.enabled
101
+ ))
102
+
103
+ const logLevel = coalesce(
104
+ process.env.DD_TRACE_LOG_LEVEL,
105
+ process.env.OTEL_LOG_LEVEL,
106
+ config.logLevel
107
+ )
108
+
109
+ log.toggle(enabled, logLevel)
110
+
79
111
  module.exports = log
@@ -283,7 +283,7 @@ class Span {
283
283
  }
284
284
 
285
285
  get ended () {
286
- return typeof this.duration !== 'undefined'
286
+ return this.duration !== undefined
287
287
  }
288
288
  }
289
289
 
@@ -15,6 +15,7 @@ class Tracer {
15
15
  this._tracerProvider = tracerProvider
16
16
  // Is there a reason this is public?
17
17
  this.instrumentationLibrary = library
18
+ this._spanLimits = {}
18
19
  }
19
20
 
20
21
  get resource () {
@@ -118,6 +119,11 @@ class Tracer {
118
119
  getActiveSpanProcessor () {
119
120
  return this._tracerProvider.getActiveSpanProcessor()
120
121
  }
122
+
123
+ // not used in our codebase but needed for compatibility. See issue #1244
124
+ getSpanLimits () {
125
+ return this._spanLimits
126
+ }
121
127
  }
122
128
 
123
129
  module.exports = Tracer
@@ -0,0 +1,43 @@
1
+ const pick = require('../../../../datadog-core/src/utils/src/pick')
2
+ const log = require('../../log')
3
+
4
+ const { DsmPathwayCodec } = require('../../datastreams/pathway')
5
+
6
+ const base64Key = 'dd-pathway-ctx-base64'
7
+ const logKeys = [base64Key]
8
+
9
+ class DSMTextMapPropagator {
10
+ constructor (config) {
11
+ this.config = config
12
+ }
13
+
14
+ inject (ctx, carrier) {
15
+ if (!this.config.dsmEnabled) return
16
+
17
+ this._injectDatadogDSMContext(ctx, carrier)
18
+
19
+ log.debug(() => `Inject into carrier (DSM): ${JSON.stringify(pick(carrier, logKeys))}.`)
20
+ }
21
+
22
+ extract (carrier) {
23
+ if (!this.config.dsmEnabled) return
24
+
25
+ const dsmContext = this._extractDatadogDSMContext(carrier)
26
+
27
+ if (!dsmContext) return dsmContext
28
+
29
+ log.debug(() => `Extract from carrier (DSM): ${JSON.stringify(pick(carrier, logKeys))}.`)
30
+ return dsmContext
31
+ }
32
+
33
+ _injectDatadogDSMContext (ctx, carrier) {
34
+ DsmPathwayCodec.encode(ctx, carrier)
35
+ }
36
+
37
+ _extractDatadogDSMContext (carrier) {
38
+ const ctx = DsmPathwayCodec.decode(carrier)
39
+ return ctx
40
+ }
41
+ }
42
+
43
+ module.exports = DSMTextMapPropagator
@@ -5,6 +5,7 @@ const Span = require('./span')
5
5
  const SpanProcessor = require('../span_processor')
6
6
  const PrioritySampler = require('../priority_sampler')
7
7
  const TextMapPropagator = require('./propagation/text_map')
8
+ const DSMTextMapPropagator = require('./propagation/text_map_dsm')
8
9
  const HttpPropagator = require('./propagation/http')
9
10
  const BinaryPropagator = require('./propagation/binary')
10
11
  const LogPropagator = require('./propagation/log')
@@ -38,7 +39,8 @@ class DatadogTracer {
38
39
  [formats.TEXT_MAP]: new TextMapPropagator(config),
39
40
  [formats.HTTP_HEADERS]: new HttpPropagator(config),
40
41
  [formats.BINARY]: new BinaryPropagator(config),
41
- [formats.LOG]: new LogPropagator(config)
42
+ [formats.LOG]: new LogPropagator(config),
43
+ [formats.TEXT_MAP_DSM]: new DSMTextMapPropagator(config)
42
44
  }
43
45
  if (config.reportHostname) {
44
46
  this._hostname = os.hostname()
@@ -71,14 +73,16 @@ class DatadogTracer {
71
73
  return span
72
74
  }
73
75
 
74
- inject (spanContext, format, carrier) {
75
- if (spanContext instanceof Span) {
76
- spanContext = spanContext.context()
76
+ inject (context, format, carrier) {
77
+ if (context instanceof Span) {
78
+ context = context.context()
77
79
  }
78
80
 
79
81
  try {
80
- this._prioritySampler.sample(spanContext)
81
- this._propagators[format].inject(spanContext, carrier)
82
+ if (format !== 'text_map_dsm') {
83
+ this._prioritySampler.sample(context)
84
+ }
85
+ this._propagators[format].inject(context, carrier)
82
86
  } catch (e) {
83
87
  log.error(e)
84
88
  runtimeMetrics.increment('datadog.tracer.node.inject.errors', true)
@@ -16,7 +16,8 @@ const {
16
16
  getTestSuiteCommonTags,
17
17
  TEST_STATUS,
18
18
  TEST_SKIPPED_BY_ITR,
19
- ITR_CORRELATION_ID
19
+ ITR_CORRELATION_ID,
20
+ TEST_SOURCE_FILE
20
21
  } = require('./util/test')
21
22
  const Plugin = require('./plugin')
22
23
  const { COMPONENT } = require('../constants')
@@ -207,7 +208,13 @@ module.exports = class CiPlugin extends Plugin {
207
208
  ...extraTags
208
209
  }
209
210
 
210
- const codeOwners = getCodeOwnersForFilename(testSuite, this.codeOwnersEntries)
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
+
211
218
  if (codeOwners) {
212
219
  testTags[TEST_CODE_OWNERS] = codeOwners
213
220
  }
@@ -3,6 +3,7 @@
3
3
  // TODO: move anything related to tracing to TracingPlugin instead
4
4
 
5
5
  const dc = require('dc-polyfill')
6
+ const logger = require('../log')
6
7
  const { storage } = require('../../../datadog-core')
7
8
 
8
9
  class Subscription {
@@ -72,7 +73,17 @@ module.exports = class Plugin {
72
73
  }
73
74
 
74
75
  addSub (channelName, handler) {
75
- this._subscriptions.push(new Subscription(channelName, handler))
76
+ const plugin = this
77
+ const wrappedHandler = function () {
78
+ try {
79
+ return handler.apply(this, arguments)
80
+ } catch (e) {
81
+ logger.error('Error in plugin handler:', e)
82
+ logger.info('Disabling plugin:', plugin.id)
83
+ plugin.configure(false)
84
+ }
85
+ }
86
+ this._subscriptions.push(new Subscription(channelName, wrappedHandler))
76
87
  }
77
88
 
78
89
  addBind (channelName, transform) {
@@ -181,6 +181,7 @@ class Tracer extends NoopProxy {
181
181
  if (!this._tracingInitialized) {
182
182
  const prioritySampler = appsecStandalone.configure(config)
183
183
  this._tracer = new DatadogTracer(config, prioritySampler)
184
+ this.dataStreamsCheckpointer = this._tracer.dataStreamsCheckpointer
184
185
  this.appsec = new AppsecSdk(this._tracer, config)
185
186
  this._tracingInitialized = true
186
187
  }
@@ -11,6 +11,7 @@ const { DataStreamsProcessor } = require('./datastreams/processor')
11
11
  const { DsmPathwayCodec } = require('./datastreams/pathway')
12
12
  const { DD_MAJOR } = require('../../../version')
13
13
  const DataStreamsContext = require('./data_streams_context')
14
+ const { DataStreamsCheckpointer } = require('./data_streams')
14
15
  const { flushStartupLogs } = require('../../datadog-instrumentations/src/check_require_cache')
15
16
  const log = require('./log/writer')
16
17
 
@@ -23,6 +24,7 @@ class DatadogTracer extends Tracer {
23
24
  constructor (config, prioritySampler) {
24
25
  super(config, prioritySampler)
25
26
  this._dataStreamsProcessor = new DataStreamsProcessor(config)
27
+ this.dataStreamsCheckpointer = new DataStreamsCheckpointer(this)
26
28
  this._scope = new Scope()
27
29
  setStartupLogConfig(config)
28
30
  flushStartupLogs(log)