dd-trace 5.39.0 → 5.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 (35) hide show
  1. package/index.d.ts +30 -21
  2. package/package.json +2 -2
  3. package/packages/datadog-instrumentations/src/jest.js +7 -4
  4. package/packages/datadog-instrumentations/src/mocha/main.js +1 -0
  5. package/packages/datadog-instrumentations/src/nyc.js +1 -0
  6. package/packages/datadog-instrumentations/src/vitest.js +2 -0
  7. package/packages/dd-trace/src/appsec/iast/index.js +0 -1
  8. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -4
  9. package/packages/dd-trace/src/appsec/reporter.js +3 -8
  10. package/packages/dd-trace/src/appsec/sdk/track_event.js +2 -4
  11. package/packages/dd-trace/src/appsec/telemetry/common.js +24 -0
  12. package/packages/dd-trace/src/appsec/telemetry/index.js +126 -0
  13. package/packages/dd-trace/src/appsec/telemetry/rasp.js +35 -0
  14. package/packages/dd-trace/src/appsec/telemetry/user.js +24 -0
  15. package/packages/dd-trace/src/appsec/telemetry/waf.js +92 -0
  16. package/packages/dd-trace/src/appsec/user_tracking.js +2 -4
  17. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +16 -4
  18. package/packages/dd-trace/src/config.js +23 -6
  19. package/packages/dd-trace/src/constants.js +1 -1
  20. package/packages/dd-trace/src/dogstatsd.js +16 -4
  21. package/packages/dd-trace/src/exporters/agent/index.js +2 -2
  22. package/packages/dd-trace/src/noop/dogstatsd.js +6 -0
  23. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -2
  24. package/packages/dd-trace/src/priority_sampler.js +5 -3
  25. package/packages/dd-trace/src/proxy.js +41 -13
  26. package/packages/dd-trace/src/remote_config/index.js +1 -0
  27. package/packages/dd-trace/src/span_processor.js +7 -4
  28. package/packages/dd-trace/src/span_stats.js +1 -2
  29. package/packages/dd-trace/src/standalone/index.js +70 -0
  30. package/packages/dd-trace/src/standalone/product.js +24 -0
  31. package/packages/dd-trace/src/standalone/tracesource.js +22 -0
  32. package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +47 -0
  33. package/packages/dd-trace/src/tracer.js +3 -2
  34. package/packages/dd-trace/src/appsec/standalone.js +0 -130
  35. package/packages/dd-trace/src/appsec/telemetry.js +0 -218
package/index.d.ts CHANGED
@@ -345,6 +345,12 @@ declare namespace tracer {
345
345
  * List of options available to the tracer.
346
346
  */
347
347
  export interface TracerOptions {
348
+ /**
349
+ * Used to disable APM Tracing when using standalone products
350
+ * @default true
351
+ */
352
+ apmTracingEnabled?: boolean
353
+
348
354
  /**
349
355
  * Whether to enable trace ID injection in log records to be able to correlate
350
356
  * traces with logs.
@@ -528,6 +534,9 @@ declare namespace tracer {
528
534
  appsec?: {
529
535
  /**
530
536
  * Configuration of Standalone ASM mode
537
+ * Deprecated in favor of `apmTracingEnabled`.
538
+ *
539
+ * @deprecated
531
540
  */
532
541
  standalone?: {
533
542
  /**
@@ -813,43 +822,43 @@ declare namespace tracer {
813
822
  export interface DogStatsD {
814
823
  /**
815
824
  * Increments a metric by the specified value, optionally specifying tags.
816
- * @param {string} stat The dot-separated metric name.
817
- * @param {number} value The amount to increment the stat by.
818
- * @param {[tag:string]:string|number} tags Tags to pass along, such as `{ foo: 'bar' }`. Values are combined with config.tags.
825
+ * @param stat The dot-separated metric name.
826
+ * @param value The amount to increment the stat by.
827
+ * @param tags Tags to pass along, such as `{ foo: 'bar' }`. Values are combined with config.tags.
819
828
  */
820
- increment(stat: string, value?: number, tags?: { [tag: string]: string|number }): void
829
+ increment(stat: string, value?: number, tags?: Record<string, string|number>): void
821
830
 
822
831
  /**
823
832
  * Decrements a metric by the specified value, optionally specifying tags.
824
- * @param {string} stat The dot-separated metric name.
825
- * @param {number} value The amount to decrement the stat by.
826
- * @param {[tag:string]:string|number} tags Tags to pass along, such as `{ foo: 'bar' }`. Values are combined with config.tags.
833
+ * @param stat The dot-separated metric name.
834
+ * @param value The amount to decrement the stat by.
835
+ * @param tags Tags to pass along, such as `{ foo: 'bar' }`. Values are combined with config.tags.
827
836
  */
828
- decrement(stat: string, value?: number, tags?: { [tag: string]: string|number }): void
837
+ decrement(stat: string, value?: number, tags?: Record<string, string|number>): void
829
838
 
830
839
  /**
831
840
  * Sets a distribution value, optionally specifying tags.
832
- * @param {string} stat The dot-separated metric name.
833
- * @param {number} value The amount to increment the stat by.
834
- * @param {[tag:string]:string|number} tags Tags to pass along, such as `{ foo: 'bar' }`. Values are combined with config.tags.
841
+ * @param stat The dot-separated metric name.
842
+ * @param value The amount to increment the stat by.
843
+ * @param tags Tags to pass along, such as `{ foo: 'bar' }`. Values are combined with config.tags.
835
844
  */
836
- distribution(stat: string, value?: number, tags?: { [tag: string]: string|number }): void
845
+ distribution(stat: string, value?: number, tags?: Record<string, string|number>): void
837
846
 
838
847
  /**
839
848
  * Sets a gauge value, optionally specifying tags.
840
- * @param {string} stat The dot-separated metric name.
841
- * @param {number} value The amount to increment the stat by.
842
- * @param {[tag:string]:string|number} tags Tags to pass along, such as `{ foo: 'bar' }`. Values are combined with config.tags.
849
+ * @param stat The dot-separated metric name.
850
+ * @param value The amount to increment the stat by.
851
+ * @param tags Tags to pass along, such as `{ foo: 'bar' }`. Values are combined with config.tags.
843
852
  */
844
- gauge(stat: string, value?: number, tags?: { [tag: string]: string|number }): void
853
+ gauge(stat: string, value?: number, tags?: Record<string, string|number>): void
845
854
 
846
855
  /**
847
856
  * Sets a histogram value, optionally specifying tags.
848
- * @param {string} stat The dot-separated metric name.
849
- * @param {number} value The amount to increment the stat by.
850
- * @param {[tag:string]:string|number} tags Tags to pass along, such as `{ foo: 'bar' }`. Values are combined with config.tags.
857
+ * @param stat The dot-separated metric name.
858
+ * @param value The amount to increment the stat by.
859
+ * @param tags Tags to pass along, such as `{ foo: 'bar' }`. Values are combined with config.tags.
851
860
  */
852
- histogram(stat: string, value?: number, tags?: { [tag: string]: string|number }): void
861
+ histogram(stat: string, value?: number, tags?: Record<string, string|number>): void
853
862
 
854
863
  /**
855
864
  * Forces any unsent metrics to be sent
@@ -871,7 +880,7 @@ declare namespace tracer {
871
880
 
872
881
  /**
873
882
  * Links a failed login event to the current trace.
874
- * @param {string} userId The user id of the attemped login.
883
+ * @param {string} userId The user id of the attempted login.
875
884
  * @param {boolean} exists If the user id exists.
876
885
  * @param {[key: string]: string} metadata Custom fields to link to the login failure event.
877
886
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "5.39.0",
3
+ "version": "5.40.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -24,7 +24,7 @@
24
24
  "test:appsec:plugins:ci": "yarn services && nyc --no-clean --include \"packages/dd-trace/src/appsec/**/*.js\" -- npm run test:appsec:plugins",
25
25
  "test:debugger": "mocha -r 'packages/dd-trace/test/setup/mocha.js' 'packages/dd-trace/test/debugger/**/*.spec.js'",
26
26
  "test:debugger:ci": "nyc --no-clean --include 'packages/dd-trace/src/debugger/**/*.js' -- npm run test:debugger",
27
- "test:trace:core": "tap packages/dd-trace/test/*.spec.js \"packages/dd-trace/test/{ci-visibility,datastreams,encode,exporters,opentelemetry,opentracing,plugins,service-naming,telemetry}/**/*.spec.js\"",
27
+ "test:trace:core": "tap packages/dd-trace/test/*.spec.js \"packages/dd-trace/test/{ci-visibility,datastreams,encode,exporters,opentelemetry,opentracing,plugins,service-naming,standalone,telemetry}/**/*.spec.js\"",
28
28
  "test:trace:core:ci": "npm run test:trace:core -- --coverage --nyc-arg=--include=\"packages/dd-trace/src/**/*.js\"",
29
29
  "test:instrumentations": "mocha -r 'packages/dd-trace/test/setup/mocha.js' 'packages/datadog-instrumentations/test/**/*.spec.js'",
30
30
  "test:instrumentations:ci": "nyc --no-clean --include 'packages/datadog-instrumentations/src/**/*.js' -- npm run test:instrumentations",
@@ -147,10 +147,10 @@ function getWrappedEnvironment (BaseEnvironment, jestVersion) {
147
147
 
148
148
  if (this.isKnownTestsEnabled) {
149
149
  try {
150
- const hasKnownTests = !!knownTests.jest
150
+ const hasKnownTests = !!knownTests?.jest
151
151
  earlyFlakeDetectionNumRetries = this.testEnvironmentOptions._ddEarlyFlakeDetectionNumRetries
152
152
  this.knownTestsForThisSuite = hasKnownTests
153
- ? (knownTests.jest[this.testSuite] || [])
153
+ ? (knownTests?.jest[this.testSuite] || [])
154
154
  : this.getKnownTestsForSuite(this.testEnvironmentOptions._ddKnownTests)
155
155
  } catch (e) {
156
156
  // If there has been an error parsing the tests, we'll disable Early Flake Deteciton
@@ -442,6 +442,7 @@ addHook({
442
442
  }, getTestEnvironment)
443
443
 
444
444
  function getWrappedScheduleTests (scheduleTests, frameworkVersion) {
445
+ // `scheduleTests` is an async function
445
446
  return function (tests) {
446
447
  if (!isSuitesSkippingEnabled || hasFilteredSkippableSuites) {
447
448
  return scheduleTests.apply(this, arguments)
@@ -744,6 +745,7 @@ function coverageReporterWrapper (coverageReporter) {
744
745
  * This calculation adds no value, so we'll skip it, as long as the user has not manually opted in to code coverage,
745
746
  * in which case we'll leave it.
746
747
  */
748
+ // `_addUntestedFiles` is an async function
747
749
  shimmer.wrap(CoverageReporter.prototype, '_addUntestedFiles', addUntestedFiles => function () {
748
750
  // If the user has added coverage manually, they're willing to pay the price of this execution, so
749
751
  // we will not skip it.
@@ -901,6 +903,7 @@ addHook({
901
903
  }, transformPackage => {
902
904
  const originalCreateScriptTransformer = transformPackage.createScriptTransformer
903
905
 
906
+ // `createScriptTransformer` is an async function
904
907
  transformPackage.createScriptTransformer = function (config) {
905
908
  const { testEnvironmentOptions, ...restOfConfig } = config
906
909
  const {
@@ -951,7 +954,7 @@ addHook({
951
954
  if (isKnownTestsEnabled) {
952
955
  const projectSuites = testPaths.tests.map(test => getTestSuitePath(test.path, test.context.config.rootDir))
953
956
  const isFaulty =
954
- getIsFaultyEarlyFlakeDetection(projectSuites, knownTests.jest || {}, earlyFlakeDetectionFaultyThreshold)
957
+ getIsFaultyEarlyFlakeDetection(projectSuites, knownTests?.jest || {}, earlyFlakeDetectionFaultyThreshold)
955
958
  if (isFaulty) {
956
959
  log.error('Early flake detection is disabled because the number of new suites is too high.')
957
960
  isEarlyFlakeDetectionEnabled = false
@@ -1063,7 +1066,7 @@ addHook({
1063
1066
  }
1064
1067
  const [{ globalConfig, config, path: testSuiteAbsolutePath }] = args
1065
1068
  const testSuite = getTestSuitePath(testSuiteAbsolutePath, globalConfig.rootDir || process.cwd())
1066
- const suiteKnownTests = knownTests.jest?.[testSuite] || []
1069
+ const suiteKnownTests = knownTests?.jest?.[testSuite] || []
1067
1070
 
1068
1071
  const suiteQuarantinedTests = quarantinedTests.jest?.suites?.[testSuite]?.tests || {}
1069
1072
 
@@ -349,6 +349,7 @@ addHook({
349
349
  versions: ['>=5.2.0'],
350
350
  file: 'lib/cli/run-helpers.js'
351
351
  }, (run) => {
352
+ // `runMocha` is an async function
352
353
  shimmer.wrap(run, 'runMocha', runMocha => function () {
353
354
  if (!testStartCh.hasSubscribers) {
354
355
  return runMocha.apply(this, arguments)
@@ -7,6 +7,7 @@ addHook({
7
7
  name: 'nyc',
8
8
  versions: ['>=17']
9
9
  }, (nycPackage) => {
10
+ // `wrap` is an async function
10
11
  shimmer.wrap(nycPackage.prototype, 'wrap', wrap => function () {
11
12
  // Only relevant if the config `all` is set to true
12
13
  try {
@@ -329,6 +329,7 @@ addHook({
329
329
  const { VitestTestRunner } = vitestPackage
330
330
 
331
331
  // `onBeforeRunTask` is run before any repetition or attempt is run
332
+ // `onBeforeRunTask` is an async function
332
333
  shimmer.wrap(VitestTestRunner.prototype, 'onBeforeRunTask', onBeforeRunTask => function (task) {
333
334
  const testName = getTestName(task)
334
335
 
@@ -361,6 +362,7 @@ addHook({
361
362
  })
362
363
 
363
364
  // `onAfterRunTask` is run after all repetitions or attempts are run
365
+ // `onAfterRunTask` is an async function
364
366
  shimmer.wrap(VitestTestRunner.prototype, 'onAfterRunTask', onAfterRunTask => function (task) {
365
367
  const { isEarlyFlakeDetectionEnabled, isQuarantinedTestsEnabled } = getProvidedContext()
366
368
 
@@ -22,7 +22,6 @@ const securityControls = require('./security-controls')
22
22
  const requestStart = dc.channel('dd-trace:incomingHttpRequestStart')
23
23
  const requestClose = dc.channel('dd-trace:incomingHttpRequestEnd')
24
24
  const iastResponseEnd = dc.channel('datadog:iast:response-end')
25
-
26
25
  let isEnabled = false
27
26
 
28
27
  function enable (config, _tracer) {
@@ -3,11 +3,10 @@
3
3
  const LRU = require('lru-cache')
4
4
  const vulnerabilitiesFormatter = require('./vulnerabilities-formatter')
5
5
  const { IAST_ENABLED_TAG_KEY, IAST_JSON_TAG_KEY } = require('./tags')
6
- const standalone = require('../standalone')
7
- const { SAMPLING_MECHANISM_APPSEC } = require('../../constants')
8
6
  const { keepTrace } = require('../../priority_sampler')
9
7
  const { reportStackTrace, getCallsiteFrames, canReportStackTrace, STACK_TRACE_NAMESPACES } = require('../stack_trace')
10
8
  const { getOriginalPathAndLineFromSourceMap } = require('./taint-tracking/rewriter')
9
+ const { ASM } = require('../../standalone/product')
11
10
 
12
11
  const VULNERABILITIES_KEY = 'vulnerabilities'
13
12
  const VULNERABILITY_HASHES_MAX_SIZE = 1000
@@ -51,8 +50,7 @@ function addVulnerability (iastContext, vulnerability, callSiteFrames) {
51
50
 
52
51
  if (!span) return
53
52
 
54
- keepTrace(span, SAMPLING_MECHANISM_APPSEC)
55
- standalone.sample(span)
53
+ keepTrace(span, ASM)
56
54
 
57
55
  if (stackTraceEnabled && canReportStackTrace(span, maxStackTraces, STACK_TRACE_NAMESPACES.IAST)) {
58
56
  const originalCallSiteList = callSiteFrames.map(callsite => replaceCallSiteFromSourceMap(callsite))
@@ -13,9 +13,8 @@ const {
13
13
  getRequestMetrics
14
14
  } = require('./telemetry')
15
15
  const zlib = require('zlib')
16
- const standalone = require('./standalone')
17
- const { SAMPLING_MECHANISM_APPSEC } = require('../constants')
18
16
  const { keepTrace } = require('../priority_sampler')
17
+ const { ASM } = require('../standalone/product')
19
18
 
20
19
  // default limiter, configurable with setRateLimit()
21
20
  let limiter = new Limiter(100)
@@ -129,9 +128,7 @@ function reportAttack (attackData) {
129
128
  }
130
129
 
131
130
  if (limiter.isAllowed()) {
132
- keepTrace(rootSpan, SAMPLING_MECHANISM_APPSEC)
133
-
134
- standalone.sample(rootSpan)
131
+ keepTrace(rootSpan, ASM)
135
132
  }
136
133
 
137
134
  // TODO: maybe add this to format.js later (to take decision as late as possible)
@@ -186,9 +183,7 @@ function finishRequest (req, res) {
186
183
  if (metricsQueue.size) {
187
184
  rootSpan.addTags(Object.fromEntries(metricsQueue))
188
185
 
189
- keepTrace(rootSpan, SAMPLING_MECHANISM_APPSEC)
190
-
191
- standalone.sample(rootSpan)
186
+ keepTrace(rootSpan, ASM)
192
187
 
193
188
  metricsQueue.clear()
194
189
  }
@@ -3,11 +3,10 @@
3
3
  const log = require('../../log')
4
4
  const { getRootSpan } = require('./utils')
5
5
  const { setUserTags } = require('./set_user')
6
- const standalone = require('../standalone')
7
6
  const waf = require('../waf')
8
- const { SAMPLING_MECHANISM_APPSEC } = require('../../constants')
9
7
  const { keepTrace } = require('../../priority_sampler')
10
8
  const addresses = require('../addresses')
9
+ const { ASM } = require('../../standalone/product')
11
10
 
12
11
  function trackUserLoginSuccessEvent (tracer, user, metadata) {
13
12
  // TODO: better user check here and in _setUser() ?
@@ -79,8 +78,7 @@ function trackEvent (eventName, fields, sdkMethodName, rootSpan) {
79
78
 
80
79
  rootSpan.addTags(tags)
81
80
 
82
- keepTrace(rootSpan, SAMPLING_MECHANISM_APPSEC)
83
- standalone.sample(rootSpan)
81
+ keepTrace(rootSpan, ASM)
84
82
  }
85
83
 
86
84
  function runWaf (eventName, user) {
@@ -0,0 +1,24 @@
1
+ 'use strinct'
2
+
3
+ const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics')
4
+
5
+ const tags = {
6
+ REQUEST_BLOCKED: 'request_blocked',
7
+ RULE_TRIGGERED: 'rule_triggered',
8
+ WAF_TIMEOUT: 'waf_timeout',
9
+ WAF_VERSION: 'waf_version',
10
+ EVENT_RULES_VERSION: 'event_rules_version'
11
+ }
12
+
13
+ function getVersionsTags (wafVersion, rulesVersion) {
14
+ return {
15
+ [tags.WAF_VERSION]: wafVersion,
16
+ [tags.EVENT_RULES_VERSION]: rulesVersion
17
+ }
18
+ }
19
+
20
+ module.exports = {
21
+ tags,
22
+ getVersionsTags,
23
+ DD_TELEMETRY_REQUEST_METRICS
24
+ }
@@ -0,0 +1,126 @@
1
+ 'use strict'
2
+
3
+ const { DD_TELEMETRY_REQUEST_METRICS } = require('./common')
4
+ const { addRaspRequestMetrics, trackRaspMetrics } = require('./rasp')
5
+ const { incrementMissingUserId, incrementMissingUserLogin } = require('./user')
6
+ const {
7
+ addWafRequestMetrics,
8
+ trackWafMetrics,
9
+ incrementWafInit,
10
+ incrementWafUpdates,
11
+ incrementWafRequests
12
+ } = require('./waf')
13
+
14
+ const metricsStoreMap = new WeakMap()
15
+
16
+ let enabled = false
17
+
18
+ function enable (telemetryConfig) {
19
+ enabled = telemetryConfig?.enabled && telemetryConfig.metrics
20
+ }
21
+
22
+ function disable () {
23
+ enabled = false
24
+ }
25
+
26
+ function newStore () {
27
+ return {
28
+ [DD_TELEMETRY_REQUEST_METRICS]: {
29
+ duration: 0,
30
+ durationExt: 0,
31
+ raspDuration: 0,
32
+ raspDurationExt: 0,
33
+ raspEvalCount: 0
34
+ }
35
+ }
36
+ }
37
+
38
+ function getStore (req) {
39
+ let store = metricsStoreMap.get(req)
40
+ if (!store) {
41
+ store = newStore()
42
+ metricsStoreMap.set(req, store)
43
+ }
44
+ return store
45
+ }
46
+
47
+ function updateRaspRequestsMetricTags (metrics, req, raspRule) {
48
+ if (!req) return
49
+
50
+ const store = getStore(req)
51
+
52
+ // it does not depend on whether telemetry is enabled or not
53
+ addRaspRequestMetrics(store, metrics)
54
+
55
+ if (!enabled) return
56
+
57
+ trackRaspMetrics(metrics, raspRule)
58
+ }
59
+
60
+ function updateWafRequestsMetricTags (metrics, req) {
61
+ if (!req) return
62
+
63
+ const store = getStore(req)
64
+
65
+ // it does not depend on whether telemetry is enabled or not
66
+ addWafRequestMetrics(store, metrics)
67
+
68
+ if (!enabled) return
69
+
70
+ return trackWafMetrics(store, metrics)
71
+ }
72
+
73
+ function incrementWafInitMetric (wafVersion, rulesVersion) {
74
+ if (!enabled) return
75
+
76
+ incrementWafInit(wafVersion, rulesVersion)
77
+ }
78
+
79
+ function incrementWafUpdatesMetric (wafVersion, rulesVersion) {
80
+ if (!enabled) return
81
+
82
+ incrementWafUpdates(wafVersion, rulesVersion)
83
+ }
84
+
85
+ function incrementWafRequestsMetric (req) {
86
+ if (!req || !enabled) return
87
+
88
+ const store = getStore(req)
89
+ incrementWafRequests(store)
90
+
91
+ metricsStoreMap.delete(req)
92
+ }
93
+
94
+ function incrementMissingUserLoginMetric (framework, eventType) {
95
+ if (!enabled) return
96
+
97
+ incrementMissingUserLogin(framework, eventType)
98
+ }
99
+
100
+ function incrementMissingUserIdMetric (framework, eventType) {
101
+ if (!enabled) return
102
+
103
+ incrementMissingUserId(framework, eventType)
104
+ }
105
+
106
+ function getRequestMetrics (req) {
107
+ if (req) {
108
+ const store = getStore(req)
109
+ return store?.[DD_TELEMETRY_REQUEST_METRICS]
110
+ }
111
+ }
112
+
113
+ module.exports = {
114
+ enable,
115
+ disable,
116
+
117
+ updateWafRequestsMetricTags,
118
+ updateRaspRequestsMetricTags,
119
+ incrementWafInitMetric,
120
+ incrementWafUpdatesMetric,
121
+ incrementWafRequestsMetric,
122
+ incrementMissingUserLoginMetric,
123
+ incrementMissingUserIdMetric,
124
+
125
+ getRequestMetrics
126
+ }
@@ -0,0 +1,35 @@
1
+ 'use strict'
2
+
3
+ const telemetryMetrics = require('../../telemetry/metrics')
4
+ const { DD_TELEMETRY_REQUEST_METRICS } = require('./common')
5
+
6
+ const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
7
+
8
+ function addRaspRequestMetrics (store, { duration, durationExt }) {
9
+ store[DD_TELEMETRY_REQUEST_METRICS].raspDuration += duration || 0
10
+ store[DD_TELEMETRY_REQUEST_METRICS].raspDurationExt += durationExt || 0
11
+ store[DD_TELEMETRY_REQUEST_METRICS].raspEvalCount++
12
+ }
13
+
14
+ function trackRaspMetrics (metrics, raspRule) {
15
+ const tags = { rule_type: raspRule.type, waf_version: metrics.wafVersion }
16
+
17
+ if (raspRule.variant) {
18
+ tags.rule_variant = raspRule.variant
19
+ }
20
+
21
+ appsecMetrics.count('rasp.rule.eval', tags).inc(1)
22
+
23
+ if (metrics.wafTimeout) {
24
+ appsecMetrics.count('rasp.timeout', tags).inc(1)
25
+ }
26
+
27
+ if (metrics.ruleTriggered) {
28
+ appsecMetrics.count('rasp.rule.match', tags).inc(1)
29
+ }
30
+ }
31
+
32
+ module.exports = {
33
+ addRaspRequestMetrics,
34
+ trackRaspMetrics
35
+ }
@@ -0,0 +1,24 @@
1
+ 'use strict'
2
+
3
+ const telemetryMetrics = require('../../telemetry/metrics')
4
+
5
+ const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
6
+
7
+ function incrementMissingUserLogin (framework, eventType) {
8
+ appsecMetrics.count('instrum.user_auth.missing_user_login', {
9
+ framework,
10
+ event_type: eventType
11
+ }).inc()
12
+ }
13
+
14
+ function incrementMissingUserId (framework, eventType) {
15
+ appsecMetrics.count('instrum.user_auth.missing_user_id', {
16
+ framework,
17
+ event_type: eventType
18
+ }).inc()
19
+ }
20
+
21
+ module.exports = {
22
+ incrementMissingUserLogin,
23
+ incrementMissingUserId
24
+ }
@@ -0,0 +1,92 @@
1
+ 'use strict'
2
+
3
+ const telemetryMetrics = require('../../telemetry/metrics')
4
+ const { tags, getVersionsTags, DD_TELEMETRY_REQUEST_METRICS } = require('./common')
5
+
6
+ const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
7
+
8
+ const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags')
9
+
10
+ function addWafRequestMetrics (store, { duration, durationExt }) {
11
+ store[DD_TELEMETRY_REQUEST_METRICS].duration += duration || 0
12
+ store[DD_TELEMETRY_REQUEST_METRICS].durationExt += durationExt || 0
13
+ }
14
+
15
+ function trackWafDurations ({ duration, durationExt }, versionsTags) {
16
+ if (duration) {
17
+ appsecMetrics.distribution('waf.duration', versionsTags).track(duration)
18
+ }
19
+
20
+ if (durationExt) {
21
+ appsecMetrics.distribution('waf.duration_ext', versionsTags).track(durationExt)
22
+ }
23
+ }
24
+
25
+ function trackWafMetrics (store, metrics) {
26
+ const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion)
27
+
28
+ trackWafDurations(metrics, versionsTags)
29
+
30
+ const metricTags = getOrCreateMetricTags(store, versionsTags)
31
+
32
+ const { blockTriggered, ruleTriggered, wafTimeout } = metrics
33
+
34
+ if (blockTriggered) {
35
+ metricTags[tags.REQUEST_BLOCKED] = true
36
+ }
37
+
38
+ if (ruleTriggered) {
39
+ metricTags[tags.RULE_TRIGGERED] = true
40
+ }
41
+
42
+ if (wafTimeout) {
43
+ metricTags[tags.WAF_TIMEOUT] = true
44
+ }
45
+
46
+ return metricTags
47
+ }
48
+
49
+ function getOrCreateMetricTags (store, versionsTags) {
50
+ let metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS]
51
+
52
+ if (!metricTags) {
53
+ metricTags = {
54
+ [tags.REQUEST_BLOCKED]: false,
55
+ [tags.RULE_TRIGGERED]: false,
56
+ [tags.WAF_TIMEOUT]: false,
57
+
58
+ ...versionsTags
59
+ }
60
+ store[DD_TELEMETRY_WAF_RESULT_TAGS] = metricTags
61
+ }
62
+
63
+ return metricTags
64
+ }
65
+
66
+ function incrementWafInit (wafVersion, rulesVersion) {
67
+ const versionsTags = getVersionsTags(wafVersion, rulesVersion)
68
+
69
+ appsecMetrics.count('waf.init', versionsTags).inc()
70
+ }
71
+
72
+ function incrementWafUpdates (wafVersion, rulesVersion) {
73
+ const versionsTags = getVersionsTags(wafVersion, rulesVersion)
74
+
75
+ appsecMetrics.count('waf.updates', versionsTags).inc()
76
+ }
77
+
78
+ function incrementWafRequests (store) {
79
+ const metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS]
80
+
81
+ if (metricTags) {
82
+ appsecMetrics.count('waf.requests', metricTags).inc()
83
+ }
84
+ }
85
+
86
+ module.exports = {
87
+ addWafRequestMetrics,
88
+ trackWafMetrics,
89
+ incrementWafInit,
90
+ incrementWafUpdates,
91
+ incrementWafRequests
92
+ }
@@ -5,9 +5,8 @@ const log = require('../log')
5
5
  const telemetry = require('./telemetry')
6
6
  const addresses = require('./addresses')
7
7
  const { keepTrace } = require('../priority_sampler')
8
- const { SAMPLING_MECHANISM_APPSEC } = require('../constants')
9
- const standalone = require('./standalone')
10
8
  const waf = require('./waf')
9
+ const { ASM } = require('../standalone/product')
11
10
 
12
11
  // the RFC doesn't include '_id', but it's common in MongoDB
13
12
  const USER_ID_FIELDS = ['id', '_id', 'email', 'username', 'login', 'user']
@@ -151,8 +150,7 @@ function trackLogin (framework, login, user, success, rootSpan) {
151
150
  persistent[addresses.LOGIN_FAILURE] = null
152
151
  }
153
152
 
154
- keepTrace(rootSpan, SAMPLING_MECHANISM_APPSEC)
155
- standalone.sample(rootSpan)
153
+ keepTrace(rootSpan, ASM)
156
154
 
157
155
  rootSpan.addTags(newTags)
158
156
 
@@ -9,7 +9,8 @@ const probeIdToResolveBreakpointSet = new Map()
9
9
  const probeIdToResolveBreakpointRemove = new Map()
10
10
 
11
11
  class TestVisDynamicInstrumentation {
12
- constructor () {
12
+ constructor (config) {
13
+ this._config = config
13
14
  this.worker = null
14
15
  this._readyPromise = new Promise(resolve => {
15
16
  this._onReady = resolve
@@ -32,6 +33,9 @@ class TestVisDynamicInstrumentation {
32
33
  // 1. Probe ID
33
34
  // 2. Promise that's resolved when the breakpoint is set
34
35
  addLineProbe ({ file, line }, onHitBreakpoint) {
36
+ if (!this.worker) { // not init yet
37
+ this.start()
38
+ }
35
39
  const probeId = randomUUID()
36
40
 
37
41
  this.breakpointSetChannel.port2.postMessage(
@@ -52,7 +56,7 @@ class TestVisDynamicInstrumentation {
52
56
  return this._readyPromise
53
57
  }
54
58
 
55
- start (config) {
59
+ start () {
56
60
  if (this.worker) return
57
61
 
58
62
  log.debug('Starting Test Visibility - Dynamic Instrumentation client...')
@@ -77,7 +81,7 @@ class TestVisDynamicInstrumentation {
77
81
  DD_TRACE_TELEMETRY_ENABLED: 0
78
82
  },
79
83
  workerData: {
80
- config: config.serialize(),
84
+ config: this._config.serialize(),
81
85
  parentThreadId,
82
86
  rcPort: rcChannel.port1,
83
87
  configPort: configChannel.port1,
@@ -138,4 +142,12 @@ class TestVisDynamicInstrumentation {
138
142
  }
139
143
  }
140
144
 
141
- module.exports = new TestVisDynamicInstrumentation()
145
+ let dynamicInstrumentation
146
+
147
+ module.exports = (config) => {
148
+ if (dynamicInstrumentation) {
149
+ return dynamicInstrumentation
150
+ }
151
+ dynamicInstrumentation = new TestVisDynamicInstrumentation(config)
152
+ return dynamicInstrumentation
153
+ }