dd-trace 3.43.0 → 3.45.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 (52) hide show
  1. package/package.json +6 -6
  2. package/packages/datadog-instrumentations/src/child-process.js +4 -5
  3. package/packages/datadog-instrumentations/src/couchbase.js +5 -4
  4. package/packages/datadog-instrumentations/src/crypto.js +2 -1
  5. package/packages/datadog-instrumentations/src/dns.js +2 -1
  6. package/packages/datadog-instrumentations/src/helpers/hooks.js +7 -2
  7. package/packages/datadog-instrumentations/src/helpers/instrument.js +8 -3
  8. package/packages/datadog-instrumentations/src/helpers/register.js +18 -2
  9. package/packages/datadog-instrumentations/src/http/client.js +2 -2
  10. package/packages/datadog-instrumentations/src/http/server.js +7 -4
  11. package/packages/datadog-instrumentations/src/http2/client.js +3 -1
  12. package/packages/datadog-instrumentations/src/http2/server.js +3 -1
  13. package/packages/datadog-instrumentations/src/jest.js +3 -1
  14. package/packages/datadog-instrumentations/src/net.js +10 -2
  15. package/packages/datadog-plugin-cucumber/src/index.js +34 -2
  16. package/packages/datadog-plugin-cypress/src/plugin.js +60 -8
  17. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -0
  18. package/packages/datadog-plugin-jest/src/index.js +60 -6
  19. package/packages/datadog-plugin-jest/src/util.js +38 -16
  20. package/packages/datadog-plugin-mocha/src/index.js +32 -1
  21. package/packages/datadog-plugin-playwright/src/index.js +17 -1
  22. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +5 -1
  23. package/packages/dd-trace/src/appsec/remote_config/index.js +4 -0
  24. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
  25. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
  26. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +36 -4
  27. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +18 -1
  28. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +26 -1
  29. package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
  30. package/packages/dd-trace/src/config.js +100 -59
  31. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +14 -1
  32. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
  33. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
  34. package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
  35. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  36. package/packages/dd-trace/src/plugins/ci_plugin.js +44 -8
  37. package/packages/dd-trace/src/plugins/index.js +5 -0
  38. package/packages/dd-trace/src/plugins/util/exec.js +23 -2
  39. package/packages/dd-trace/src/plugins/util/git.js +94 -19
  40. package/packages/dd-trace/src/priority_sampler.js +30 -38
  41. package/packages/dd-trace/src/profiling/config.js +17 -2
  42. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -0
  43. package/packages/dd-trace/src/profiling/exporters/file.js +2 -1
  44. package/packages/dd-trace/src/profiling/profiler.js +18 -14
  45. package/packages/dd-trace/src/profiling/profilers/events.js +11 -5
  46. package/packages/dd-trace/src/profiling/profilers/shared.js +7 -1
  47. package/packages/dd-trace/src/profiling/profilers/space.js +17 -2
  48. package/packages/dd-trace/src/profiling/profilers/wall.js +34 -21
  49. package/packages/dd-trace/src/sampling_rule.js +130 -0
  50. package/packages/dd-trace/src/span_sampler.js +6 -64
  51. package/packages/dd-trace/src/telemetry/index.js +43 -5
  52. package/packages/dd-trace/src/telemetry/send-data.js +35 -16
@@ -0,0 +1,130 @@
1
+ const telemetryMetrics = require('../telemetry/metrics')
2
+
3
+ const ciVisibilityMetrics = telemetryMetrics.manager.namespace('civisibility')
4
+
5
+ const formattedTags = {
6
+ testLevel: 'event_type',
7
+ testFramework: 'test_framework',
8
+ errorType: 'error_type',
9
+ exitCode: 'exit_code',
10
+ isCodeCoverageEnabled: 'coverage_enabled',
11
+ isSuitesSkippingEnabled: 'itrskip_enabled',
12
+ hasCodeOwners: 'has_code_owners',
13
+ isUnsupportedCIProvider: 'is_unsupported_ci'
14
+ }
15
+
16
+ // Transform tags dictionary to array of strings.
17
+ // If tag value is true, then only tag key is added to the array.
18
+ function formatMetricTags (tagsDictionary) {
19
+ return Object.keys(tagsDictionary).reduce((acc, tagKey) => {
20
+ const formattedTagKey = formattedTags[tagKey] || tagKey
21
+ if (tagsDictionary[tagKey] === true) {
22
+ acc.push(formattedTagKey)
23
+ } else if (tagsDictionary[tagKey] !== undefined && tagsDictionary[tagKey] !== null) {
24
+ acc.push(`${formattedTagKey}:${tagsDictionary[tagKey]}`)
25
+ }
26
+ return acc
27
+ }, [])
28
+ }
29
+
30
+ function incrementCountMetric (name, tags = {}, value = 1) {
31
+ ciVisibilityMetrics.count(name, formatMetricTags(tags)).inc(value)
32
+ }
33
+
34
+ function distributionMetric (name, tags, measure) {
35
+ ciVisibilityMetrics.distribution(name, formatMetricTags(tags)).track(measure)
36
+ }
37
+
38
+ // CI Visibility telemetry events
39
+ const TELEMETRY_EVENT_CREATED = 'event_created'
40
+ const TELEMETRY_EVENT_FINISHED = 'event_finished'
41
+ const TELEMETRY_CODE_COVERAGE_STARTED = 'code_coverage_started'
42
+ const TELEMETRY_CODE_COVERAGE_FINISHED = 'code_coverage_finished'
43
+ const TELEMETRY_ITR_SKIPPED = 'itr_skipped'
44
+ const TELEMETRY_ITR_UNSKIPPABLE = 'itr_unskippable'
45
+ const TELEMETRY_ITR_FORCED_TO_RUN = 'itr_forced_run'
46
+ const TELEMETRY_CODE_COVERAGE_EMPTY = 'code_coverage.is_empty'
47
+ const TELEMETRY_CODE_COVERAGE_NUM_FILES = 'code_coverage.files'
48
+ const TELEMETRY_EVENTS_ENQUEUED_FOR_SERIALIZATION = 'events_enqueued_for_serialization'
49
+ const TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS = 'endpoint_payload.events_serialization_ms'
50
+ const TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS = 'endpoint_payload.requests'
51
+ const TELEMETRY_ENDPOINT_PAYLOAD_BYTES = 'endpoint_payload.bytes'
52
+ const TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT = 'endpoint_payload.events_count'
53
+ const TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_MS = 'endpoint_payload.requests_ms'
54
+ const TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS = 'endpoint_payload.requests_errors'
55
+ const TELEMETRY_ENDPOINT_PAYLOAD_DROPPED = 'endpoint_payload.dropped'
56
+ const TELEMETRY_GIT_COMMAND = 'git.command'
57
+ const TELEMETRY_GIT_COMMAND_MS = 'git.command_ms'
58
+ const TELEMETRY_GIT_COMMAND_ERRORS = 'git.command_errors'
59
+ const TELEMETRY_GIT_REQUESTS_SEARCH_COMMITS = 'git_requests.search_commits'
60
+ const TELEMETRY_GIT_REQUESTS_SEARCH_COMMITS_MS = 'git_requests.search_commits_ms'
61
+ const TELEMETRY_GIT_REQUESTS_SEARCH_COMMITS_ERRORS = 'git_requests.search_commits_errors'
62
+ const TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES = 'git_requests.objects_pack'
63
+ const TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES_MS = 'git_requests.objects_pack_ms'
64
+ const TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES_ERRORS = 'git_requests.objects_pack_errors'
65
+ const TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES_NUM = 'git_requests.objects_pack_files'
66
+ const TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES_BYTES = 'git_requests.objects_pack_bytes'
67
+ const TELEMETRY_GIT_REQUESTS_SETTINGS = 'git_requests.settings'
68
+ const TELEMETRY_GIT_REQUESTS_SETTINGS_MS = 'git_requests.settings_ms'
69
+ const TELEMETRY_GIT_REQUESTS_SETTINGS_ERRORS = 'git_requests.settings_errors'
70
+ const TELEMETRY_GIT_REQUESTS_SETTINGS_RESPONSE = 'git_requests.settings_response'
71
+ const TELEMETRY_ITR_SKIPPABLE_TESTS = 'itr_skippable_tests.request'
72
+ const TELEMETRY_ITR_SKIPPABLE_TESTS_MS = 'itr_skippable_tests.request_ms'
73
+ const TELEMETRY_ITR_SKIPPABLE_TESTS_ERRORS = 'itr_skippable_tests.request_errors'
74
+ const TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_SUITES = 'itr_skippable_tests.response_suites'
75
+ const TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_TESTS = 'itr_skippable_tests.response_tests'
76
+ const TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_BYTES = 'itr_skippable_tests.response_bytes'
77
+
78
+ function getErrorTypeFromStatusCode (statusCode) {
79
+ if (statusCode >= 400 && statusCode < 500) {
80
+ return 'status_code_4xx_response'
81
+ }
82
+ if (statusCode >= 500) {
83
+ return 'status_code_5xx_response'
84
+ }
85
+ return 'network'
86
+ }
87
+
88
+ module.exports = {
89
+ incrementCountMetric,
90
+ distributionMetric,
91
+ TELEMETRY_EVENT_CREATED,
92
+ TELEMETRY_EVENT_FINISHED,
93
+ TELEMETRY_CODE_COVERAGE_STARTED,
94
+ TELEMETRY_CODE_COVERAGE_FINISHED,
95
+ TELEMETRY_ITR_SKIPPED,
96
+ TELEMETRY_ITR_UNSKIPPABLE,
97
+ TELEMETRY_ITR_FORCED_TO_RUN,
98
+ TELEMETRY_CODE_COVERAGE_EMPTY,
99
+ TELEMETRY_CODE_COVERAGE_NUM_FILES,
100
+ TELEMETRY_EVENTS_ENQUEUED_FOR_SERIALIZATION,
101
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
102
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS,
103
+ TELEMETRY_ENDPOINT_PAYLOAD_BYTES,
104
+ TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT,
105
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_MS,
106
+ TELEMETRY_ENDPOINT_PAYLOAD_REQUESTS_ERRORS,
107
+ TELEMETRY_ENDPOINT_PAYLOAD_DROPPED,
108
+ TELEMETRY_GIT_COMMAND,
109
+ TELEMETRY_GIT_COMMAND_MS,
110
+ TELEMETRY_GIT_COMMAND_ERRORS,
111
+ TELEMETRY_GIT_REQUESTS_SEARCH_COMMITS,
112
+ TELEMETRY_GIT_REQUESTS_SEARCH_COMMITS_MS,
113
+ TELEMETRY_GIT_REQUESTS_SEARCH_COMMITS_ERRORS,
114
+ TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES_NUM,
115
+ TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES_BYTES,
116
+ TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES,
117
+ TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES_MS,
118
+ TELEMETRY_GIT_REQUESTS_OBJECT_PACKFILES_ERRORS,
119
+ TELEMETRY_GIT_REQUESTS_SETTINGS,
120
+ TELEMETRY_GIT_REQUESTS_SETTINGS_MS,
121
+ TELEMETRY_GIT_REQUESTS_SETTINGS_ERRORS,
122
+ TELEMETRY_GIT_REQUESTS_SETTINGS_RESPONSE,
123
+ TELEMETRY_ITR_SKIPPABLE_TESTS,
124
+ TELEMETRY_ITR_SKIPPABLE_TESTS_MS,
125
+ TELEMETRY_ITR_SKIPPABLE_TESTS_ERRORS,
126
+ TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_SUITES,
127
+ TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_TESTS,
128
+ TELEMETRY_ITR_SKIPPABLE_TESTS_RESPONSE_BYTES,
129
+ getErrorTypeFromStatusCode
130
+ }
@@ -109,13 +109,6 @@ class Config {
109
109
  log.use(this.logger)
110
110
  log.toggle(this.debug, this.logLevel, this)
111
111
 
112
- this.tags = {}
113
-
114
- tagger.add(this.tags, process.env.DD_TAGS)
115
- tagger.add(this.tags, process.env.DD_TRACE_TAGS)
116
- tagger.add(this.tags, process.env.DD_TRACE_GLOBAL_TAGS)
117
- tagger.add(this.tags, options.tags)
118
-
119
112
  const DD_TRACING_ENABLED = coalesce(
120
113
  process.env.DD_TRACING_ENABLED,
121
114
  true
@@ -184,33 +177,12 @@ class Config {
184
177
  false
185
178
  )
186
179
 
187
- const DD_SERVICE = options.service ||
188
- process.env.DD_SERVICE ||
189
- process.env.DD_SERVICE_NAME ||
190
- this.tags.service ||
191
- process.env.AWS_LAMBDA_FUNCTION_NAME ||
192
- process.env.FUNCTION_NAME || // Google Cloud Function Name set by deprecated runtimes
193
- process.env.K_SERVICE || // Google Cloud Function Name set by newer runtimes
194
- process.env.WEBSITE_SITE_NAME || // set by Azure Functions
195
- pkg.name ||
196
- 'node'
197
180
  const DD_SERVICE_MAPPING = coalesce(
198
181
  options.serviceMapping,
199
182
  process.env.DD_SERVICE_MAPPING ? fromEntries(
200
183
  process.env.DD_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
201
184
  ) : {}
202
185
  )
203
- const DD_ENV = coalesce(
204
- options.env,
205
- process.env.DD_ENV,
206
- this.tags.env
207
- )
208
- const DD_VERSION = coalesce(
209
- options.version,
210
- process.env.DD_VERSION,
211
- this.tags.version,
212
- pkg.version
213
- )
214
186
  const DD_TRACE_STARTUP_LOGS = coalesce(
215
187
  options.startupLogs,
216
188
  process.env.DD_TRACE_STARTUP_LOGS,
@@ -550,6 +522,19 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
550
522
  0
551
523
  )
552
524
 
525
+ const DD_INSTRUMENTATION_INSTALL_ID = coalesce(
526
+ process.env.DD_INSTRUMENTATION_INSTALL_ID,
527
+ null
528
+ )
529
+ const DD_INSTRUMENTATION_INSTALL_TIME = coalesce(
530
+ process.env.DD_INSTRUMENTATION_INSTALL_TIME,
531
+ null
532
+ )
533
+ const DD_INSTRUMENTATION_INSTALL_TYPE = coalesce(
534
+ process.env.DD_INSTRUMENTATION_INSTALL_TYPE,
535
+ null
536
+ )
537
+
553
538
  const ingestion = options.ingestion || {}
554
539
  const dogstatsd = coalesce(options.dogstatsd, {})
555
540
  const sampler = {
@@ -583,7 +568,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
583
568
  this.dsmEnabled = isTrue(DD_DATA_STREAMS_ENABLED)
584
569
  this.openAiLogsEnabled = DD_OPENAI_LOGS_ENABLED
585
570
  this.apiKey = DD_API_KEY
586
- this.env = DD_ENV
587
571
  this.url = DD_CIVISIBILITY_AGENTLESS_URL ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
588
572
  : getAgentUrl(DD_TRACE_AGENT_URL, options)
589
573
  this.site = coalesce(options.site, process.env.DD_SITE, 'datadoghq.com')
@@ -595,9 +579,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
595
579
  this.clientIpEnabled = DD_TRACE_CLIENT_IP_ENABLED
596
580
  this.clientIpHeader = DD_TRACE_CLIENT_IP_HEADER
597
581
  this.plugins = !!coalesce(options.plugins, true)
598
- this.service = DD_SERVICE
599
582
  this.serviceMapping = DD_SERVICE_MAPPING
600
- this.version = DD_VERSION
601
583
  this.dogstatsd = {
602
584
  hostname: coalesce(dogstatsd.hostname, process.env.DD_DOGSTATSD_HOSTNAME, this.hostname),
603
585
  port: String(coalesce(dogstatsd.port, process.env.DD_DOGSTATSD_PORT, 8125))
@@ -629,7 +611,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
629
611
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
630
612
  // Disabled for CI Visibility's agentless
631
613
  this.telemetry = {
632
- enabled: DD_TRACE_EXPORTER !== 'datadog' && isTrue(DD_INSTRUMENTATION_TELEMETRY_ENABLED),
614
+ enabled: isTrue(DD_INSTRUMENTATION_TELEMETRY_ENABLED),
633
615
  heartbeatInterval: DD_TELEMETRY_HEARTBEAT_INTERVAL,
634
616
  debug: isTrue(DD_TELEMETRY_DEBUG),
635
617
  logCollection: isTrue(DD_TELEMETRY_LOG_COLLECTION_ENABLED),
@@ -690,6 +672,37 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
690
672
  // Requires an accompanying DD_APM_OBFUSCATION_MEMCACHED_KEEP_COMMAND=true in the agent
691
673
  this.memcachedCommandEnabled = isTrue(DD_TRACE_MEMCACHED_COMMAND_ENABLED)
692
674
 
675
+ this.stats = {
676
+ enabled: isTrue(DD_TRACE_STATS_COMPUTATION_ENABLED)
677
+ }
678
+
679
+ this.traceId128BitGenerationEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED)
680
+ this.traceId128BitLoggingEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
681
+
682
+ this.isGCPFunction = isGCPFunction
683
+ this.isAzureFunctionConsumptionPlan = isAzureFunctionConsumptionPlan
684
+
685
+ this.spanLeakDebug = Number(DD_TRACE_SPAN_LEAK_DEBUG)
686
+
687
+ this.installSignature = {
688
+ id: DD_INSTRUMENTATION_INSTALL_ID,
689
+ time: DD_INSTRUMENTATION_INSTALL_TIME,
690
+ type: DD_INSTRUMENTATION_INSTALL_TYPE
691
+ }
692
+
693
+ this._applyDefaults()
694
+ this._applyEnvironment()
695
+ this._applyOptions(options)
696
+ this._applyRemote({})
697
+ this._merge()
698
+
699
+ tagger.add(this.tags, {
700
+ service: this.service,
701
+ env: this.env,
702
+ version: this.version,
703
+ 'runtime-id': uuid()
704
+ })
705
+
693
706
  if (this.gitMetadataEnabled) {
694
707
  this.repositoryUrl = removeUserSensitiveInfo(
695
708
  coalesce(
@@ -722,31 +735,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
722
735
  }
723
736
  }
724
737
  }
725
-
726
- this.stats = {
727
- enabled: isTrue(DD_TRACE_STATS_COMPUTATION_ENABLED)
728
- }
729
-
730
- this.traceId128BitGenerationEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED)
731
- this.traceId128BitLoggingEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
732
-
733
- this.isGCPFunction = isGCPFunction
734
- this.isAzureFunctionConsumptionPlan = isAzureFunctionConsumptionPlan
735
-
736
- this.spanLeakDebug = Number(DD_TRACE_SPAN_LEAK_DEBUG)
737
-
738
- tagger.add(this.tags, {
739
- service: this.service,
740
- env: this.env,
741
- version: this.version,
742
- 'runtime-id': uuid()
743
- })
744
-
745
- this._applyDefaults()
746
- this._applyEnvironment()
747
- this._applyOptions(options)
748
- this._applyRemote({})
749
- this._merge()
750
738
  }
751
739
 
752
740
  // Supports only a subset of options for now.
@@ -761,48 +749,93 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
761
749
  }
762
750
 
763
751
  _applyDefaults () {
752
+ const {
753
+ AWS_LAMBDA_FUNCTION_NAME,
754
+ FUNCTION_NAME,
755
+ K_SERVICE,
756
+ WEBSITE_SITE_NAME
757
+ } = process.env
758
+
759
+ const service = AWS_LAMBDA_FUNCTION_NAME ||
760
+ FUNCTION_NAME || // Google Cloud Function Name set by deprecated runtimes
761
+ K_SERVICE || // Google Cloud Function Name set by newer runtimes
762
+ WEBSITE_SITE_NAME || // set by Azure Functions
763
+ pkg.name ||
764
+ 'node'
765
+
764
766
  const defaults = this._defaults = {}
765
767
 
768
+ this._setValue(defaults, 'service', service)
769
+ this._setValue(defaults, 'env', undefined)
770
+ this._setValue(defaults, 'version', pkg.version)
766
771
  this._setUnit(defaults, 'sampleRate', undefined)
767
772
  this._setBoolean(defaults, 'logInjection', false)
768
773
  this._setArray(defaults, 'headerTags', [])
774
+ this._setValue(defaults, 'tags', {})
769
775
  }
770
776
 
771
777
  _applyEnvironment () {
772
778
  const {
773
- DD_TRACE_SAMPLE_RATE,
779
+ DD_ENV,
774
780
  DD_LOGS_INJECTION,
775
- DD_TRACE_HEADER_TAGS
781
+ DD_SERVICE,
782
+ DD_SERVICE_NAME,
783
+ DD_TAGS,
784
+ DD_TRACE_GLOBAL_TAGS,
785
+ DD_TRACE_HEADER_TAGS,
786
+ DD_TRACE_SAMPLE_RATE,
787
+ DD_TRACE_TAGS,
788
+ DD_VERSION
776
789
  } = process.env
777
790
 
791
+ const tags = {}
778
792
  const env = this._env = {}
779
793
 
794
+ tagger.add(tags, DD_TAGS)
795
+ tagger.add(tags, DD_TRACE_TAGS)
796
+ tagger.add(tags, DD_TRACE_GLOBAL_TAGS)
797
+
798
+ this._setValue(env, 'service', DD_SERVICE || DD_SERVICE_NAME || tags.service)
799
+ this._setValue(env, 'env', DD_ENV || tags.env)
800
+ this._setValue(env, 'version', DD_VERSION || tags.version)
780
801
  this._setUnit(env, 'sampleRate', DD_TRACE_SAMPLE_RATE)
781
802
  this._setBoolean(env, 'logInjection', DD_LOGS_INJECTION)
782
803
  this._setArray(env, 'headerTags', DD_TRACE_HEADER_TAGS)
804
+ this._setTags(env, 'tags', tags)
783
805
  }
784
806
 
785
807
  _applyOptions (options) {
786
808
  const opts = this._options = this._options || {}
809
+ const tags = {}
787
810
 
788
811
  options = Object.assign({ ingestion: {} }, options, opts)
789
812
 
813
+ tagger.add(tags, options.tags)
814
+
815
+ this._setValue(opts, 'service', options.service || tags.service)
816
+ this._setValue(opts, 'env', options.env || tags.env)
817
+ this._setValue(opts, 'version', options.version || tags.version)
790
818
  this._setUnit(opts, 'sampleRate', coalesce(options.sampleRate, options.ingestion.sampleRate))
791
819
  this._setBoolean(opts, 'logInjection', options.logInjection)
792
820
  this._setArray(opts, 'headerTags', options.headerTags)
821
+ this._setTags(opts, 'tags', tags)
793
822
  }
794
823
 
795
824
  _applyRemote (options) {
796
825
  const opts = this._remote = this._remote || {}
826
+ const tags = {}
797
827
  const headerTags = options.tracing_header_tags
798
828
  ? options.tracing_header_tags.map(tag => {
799
829
  return tag.tag_name ? `${tag.header}:${tag.tag_name}` : tag.header
800
830
  })
801
831
  : undefined
802
832
 
833
+ tagger.add(tags, options.tracing_tags)
834
+
803
835
  this._setUnit(opts, 'sampleRate', options.tracing_sampling_rate)
804
836
  this._setBoolean(opts, 'logInjection', options.log_injection_enabled)
805
837
  this._setArray(opts, 'headerTags', headerTags)
838
+ this._setTags(opts, 'tags', tags)
806
839
  }
807
840
 
808
841
  _setBoolean (obj, name, value) {
@@ -842,6 +875,14 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
842
875
  }
843
876
  }
844
877
 
878
+ _setTags (obj, name, value) {
879
+ if (!value || Object.keys(value).length === 0) {
880
+ return this._setValue(obj, name, null)
881
+ }
882
+
883
+ this._setValue(obj, name, value)
884
+ }
885
+
845
886
  _setValue (obj, name, value) {
846
887
  obj[name] = value
847
888
  }
@@ -3,8 +3,13 @@ const { truncateSpan, normalizeSpan } = require('./tags-processors')
3
3
  const { AgentEncoder } = require('./0.4')
4
4
  const { version: ddTraceVersion } = require('../../../../package.json')
5
5
  const id = require('../../../dd-trace/src/id')
6
- const ENCODING_VERSION = 1
6
+ const {
7
+ distributionMetric,
8
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
9
+ TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT
10
+ } = require('../ci-visibility/telemetry')
7
11
 
12
+ const ENCODING_VERSION = 1
8
13
  const ALLOWED_CONTENT_TYPES = ['test_session_end', 'test_module_end', 'test_suite_end', 'test']
9
14
 
10
15
  const TEST_SUITE_KEYS_LENGTH = 12
@@ -247,6 +252,8 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
247
252
  }
248
253
 
249
254
  _encode (bytes, trace) {
255
+ const startTime = Date.now()
256
+
250
257
  const rawEvents = trace.map(formatSpan)
251
258
 
252
259
  const testSessionEvents = rawEvents.filter(
@@ -261,9 +268,15 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
261
268
  for (const event of events) {
262
269
  this._encodeEvent(bytes, event)
263
270
  }
271
+ distributionMetric(
272
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
273
+ { endpoint: 'test_cycle' },
274
+ Date.now() - startTime
275
+ )
264
276
  }
265
277
 
266
278
  makePayload () {
279
+ distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT, { endpoint: 'test_cycle' }, this._eventCount)
267
280
  const bytes = this._traceBytes
268
281
  const eventsOffset = this._eventsOffset
269
282
  const eventsCount = this._eventCount
@@ -2,6 +2,11 @@
2
2
  const { AgentEncoder } = require('./0.4')
3
3
  const Chunk = require('./chunk')
4
4
 
5
+ const {
6
+ distributionMetric,
7
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
8
+ TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT
9
+ } = require('../ci-visibility/telemetry')
5
10
  const FormData = require('../exporters/common/form-data')
6
11
 
7
12
  const COVERAGE_PAYLOAD_VERSION = 2
@@ -21,8 +26,16 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
21
26
  }
22
27
 
23
28
  encode (coverage) {
29
+ const startTime = Date.now()
30
+
24
31
  this._coveragesCount++
25
32
  this.encodeCodeCoverage(this._coverageBytes, coverage)
33
+
34
+ distributionMetric(
35
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
36
+ { endpoint: 'code_coverage' },
37
+ Date.now() - startTime
38
+ )
26
39
  }
27
40
 
28
41
  encodeCodeCoverage (bytes, coverage) {
@@ -73,6 +86,7 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
73
86
  }
74
87
 
75
88
  makePayload () {
89
+ distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT, { endpoint: 'code_coverage' }, this._coveragesCount)
76
90
  const bytes = this._coverageBytes
77
91
 
78
92
  const coveragesOffset = this._coveragesOffset
@@ -1,6 +1,7 @@
1
1
  const { URL, format } = require('url')
2
2
 
3
3
  const request = require('./request')
4
+ const { incrementCountMetric, TELEMETRY_EVENTS_ENQUEUED_FOR_SERIALIZATION } = require('../../ci-visibility/telemetry')
4
5
 
5
6
  function fetchAgentInfo (url, callback) {
6
7
  request('', {
@@ -49,6 +50,9 @@ class AgentInfoExporter {
49
50
  }
50
51
 
51
52
  _export (payload, writer = this._writer, timerKey = '_timer') {
53
+ if (this._config.isCiVisibility) {
54
+ incrementCountMetric(TELEMETRY_EVENTS_ENQUEUED_FOR_SERIALIZATION, {}, payload.length)
55
+ }
52
56
  writer.append(payload)
53
57
 
54
58
  const { flushInterval } = this._config
@@ -21,6 +21,10 @@ class FormData extends Readable {
21
21
  }
22
22
  }
23
23
 
24
+ size () {
25
+ return this._data.reduce((size, chunk) => size + chunk.length, 0)
26
+ }
27
+
24
28
  getHeaders () {
25
29
  return { 'Content-Type': 'multipart/form-data; boundary=' + this._boundary }
26
30
  }
@@ -22,10 +22,10 @@ class DatadogTracer {
22
22
  constructor (config) {
23
23
  const Exporter = getExporter(config.experimental.exporter)
24
24
 
25
+ this._config = config
25
26
  this._service = config.service
26
27
  this._version = config.version
27
28
  this._env = config.env
28
- this._tags = config.tags
29
29
  this._logInjection = config.logInjection
30
30
  this._debug = config.debug
31
31
  this._prioritySampler = new PrioritySampler(config.env, config.sampler)
@@ -64,7 +64,7 @@ class DatadogTracer {
64
64
  integrationName: options.integrationName
65
65
  }, this._debug)
66
66
 
67
- span.addTags(this._tags)
67
+ span.addTags(this._config.tags)
68
68
  span.addTags(options.tags)
69
69
 
70
70
  return span
@@ -20,6 +20,14 @@ const {
20
20
  const Plugin = require('./plugin')
21
21
  const { COMPONENT } = require('../constants')
22
22
  const log = require('../log')
23
+ const {
24
+ incrementCountMetric,
25
+ distributionMetric,
26
+ TELEMETRY_EVENT_CREATED,
27
+ TELEMETRY_ITR_SKIPPED
28
+ } = require('../ci-visibility/telemetry')
29
+ const { CI_PROVIDER_NAME, GIT_REPOSITORY_URL, GIT_COMMIT_SHA, GIT_BRANCH } = require('./util/tags')
30
+ const { OS_VERSION, OS_PLATFORM, OS_ARCHITECTURE, RUNTIME_NAME, RUNTIME_VERSION } = require('./util/env')
23
31
 
24
32
  module.exports = class CiPlugin extends Plugin {
25
33
  constructor (...args) {
@@ -71,6 +79,7 @@ module.exports = class CiPlugin extends Plugin {
71
79
  ...testSessionSpanMetadata
72
80
  }
73
81
  })
82
+ this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'session')
74
83
  this.testModuleSpan = this.tracer.startSpan(`${this.constructor.id}.test_module`, {
75
84
  childOf: this.testSessionSpan,
76
85
  tags: {
@@ -79,6 +88,7 @@ module.exports = class CiPlugin extends Plugin {
79
88
  ...testModuleSpanMetadata
80
89
  }
81
90
  })
91
+ this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'module')
82
92
  })
83
93
 
84
94
  this.addSub(`ci:${this.constructor.id}:itr:skipped-suites`, ({ skippedSuites, frameworkVersion }) => {
@@ -97,25 +107,49 @@ module.exports = class CiPlugin extends Plugin {
97
107
  }
98
108
  }).finish()
99
109
  })
110
+ this.telemetry.count(TELEMETRY_ITR_SKIPPED, { testLevel: 'suite' }, skippedSuites.length)
100
111
  })
101
112
  }
102
113
 
114
+ get telemetry () {
115
+ const testFramework = this.constructor.id
116
+ return {
117
+ ciVisEvent: function (name, testLevel, tags = {}) {
118
+ incrementCountMetric(name, {
119
+ testLevel,
120
+ testFramework,
121
+ isUnsupportedCIProvider: this.isUnsupportedCIProvider,
122
+ ...tags
123
+ })
124
+ },
125
+ count: function (name, tags, value = 1) {
126
+ incrementCountMetric(name, tags, value)
127
+ },
128
+ distribution: function (name, tags, measure) {
129
+ distributionMetric(name, tags, measure)
130
+ }
131
+ }
132
+ }
133
+
103
134
  configure (config) {
104
135
  super.configure(config)
105
136
  this.testEnvironmentMetadata = getTestEnvironmentMetadata(this.constructor.id, this.config)
106
137
  this.codeOwnersEntries = getCodeOwnersFileEntries()
107
138
 
108
139
  const {
109
- 'git.repository_url': repositoryUrl,
110
- 'git.commit.sha': sha,
111
- 'os.version': osVersion,
112
- 'os.platform': osPlatform,
113
- 'os.architecture': osArchitecture,
114
- 'runtime.name': runtimeName,
115
- 'runtime.version': runtimeVersion,
116
- 'git.branch': branch
140
+ [GIT_REPOSITORY_URL]: repositoryUrl,
141
+ [GIT_COMMIT_SHA]: sha,
142
+ [OS_VERSION]: osVersion,
143
+ [OS_PLATFORM]: osPlatform,
144
+ [OS_ARCHITECTURE]: osArchitecture,
145
+ [RUNTIME_NAME]: runtimeName,
146
+ [RUNTIME_VERSION]: runtimeVersion,
147
+ [GIT_BRANCH]: branch,
148
+ [CI_PROVIDER_NAME]: ciProviderName
117
149
  } = this.testEnvironmentMetadata
118
150
 
151
+ this.isUnsupportedCIProvider = !ciProviderName
152
+
119
153
  this.testConfiguration = {
120
154
  repositoryUrl,
121
155
  sha,
@@ -170,6 +204,8 @@ module.exports = class CiPlugin extends Plugin {
170
204
  }
171
205
  }
172
206
 
207
+ this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'test', { hasCodeOwners: !!codeOwners })
208
+
173
209
  const testSpan = this.tracer
174
210
  .startSpan(`${this.constructor.id}.test`, {
175
211
  childOf,
@@ -59,6 +59,11 @@ module.exports = {
59
59
  get 'mysql2' () { return require('../../../datadog-plugin-mysql2/src') },
60
60
  get 'net' () { return require('../../../datadog-plugin-net/src') },
61
61
  get 'next' () { return require('../../../datadog-plugin-next/src') },
62
+ get 'node:dns' () { return require('../../../datadog-plugin-dns/src') },
63
+ get 'node:http' () { return require('../../../datadog-plugin-http/src') },
64
+ get 'node:http2' () { return require('../../../datadog-plugin-http2/src') },
65
+ get 'node:https' () { return require('../../../datadog-plugin-http/src') },
66
+ get 'node:net' () { return require('../../../datadog-plugin-net/src') },
62
67
  get 'oracledb' () { return require('../../../datadog-plugin-oracledb/src') },
63
68
  get 'openai' () { return require('../../../datadog-plugin-openai/src') },
64
69
  get 'paperplane' () { return require('../../../datadog-plugin-paperplane/src') },
@@ -1,10 +1,31 @@
1
1
  const cp = require('child_process')
2
2
  const log = require('../../log')
3
+ const { distributionMetric, incrementCountMetric } = require('../../ci-visibility/telemetry')
3
4
 
4
- const sanitizedExec = (cmd, flags, options = { stdio: 'pipe' }) => {
5
+ const sanitizedExec = (
6
+ cmd,
7
+ flags,
8
+ operationMetric,
9
+ durationMetric,
10
+ errorMetric
11
+ ) => {
12
+ let startTime
13
+ if (operationMetric) {
14
+ incrementCountMetric(operationMetric.name, operationMetric.tags)
15
+ }
16
+ if (durationMetric) {
17
+ startTime = Date.now()
18
+ }
5
19
  try {
6
- return cp.execFileSync(cmd, flags, options).toString().replace(/(\r\n|\n|\r)/gm, '')
20
+ const result = cp.execFileSync(cmd, flags, { stdio: 'pipe' }).toString().replace(/(\r\n|\n|\r)/gm, '')
21
+ if (durationMetric) {
22
+ distributionMetric(durationMetric.name, durationMetric.tags, Date.now() - startTime)
23
+ }
24
+ return result
7
25
  } catch (e) {
26
+ if (errorMetric) {
27
+ incrementCountMetric(errorMetric.name, { ...errorMetric.tags, exitCode: e.status })
28
+ }
8
29
  log.error(e)
9
30
  return ''
10
31
  }