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.
- package/index.d.ts +30 -21
- package/package.json +2 -2
- package/packages/datadog-instrumentations/src/jest.js +7 -4
- package/packages/datadog-instrumentations/src/mocha/main.js +1 -0
- package/packages/datadog-instrumentations/src/nyc.js +1 -0
- package/packages/datadog-instrumentations/src/vitest.js +2 -0
- package/packages/dd-trace/src/appsec/iast/index.js +0 -1
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +2 -4
- package/packages/dd-trace/src/appsec/reporter.js +3 -8
- package/packages/dd-trace/src/appsec/sdk/track_event.js +2 -4
- package/packages/dd-trace/src/appsec/telemetry/common.js +24 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +126 -0
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +35 -0
- package/packages/dd-trace/src/appsec/telemetry/user.js +24 -0
- package/packages/dd-trace/src/appsec/telemetry/waf.js +92 -0
- package/packages/dd-trace/src/appsec/user_tracking.js +2 -4
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +16 -4
- package/packages/dd-trace/src/config.js +23 -6
- package/packages/dd-trace/src/constants.js +1 -1
- package/packages/dd-trace/src/dogstatsd.js +16 -4
- package/packages/dd-trace/src/exporters/agent/index.js +2 -2
- package/packages/dd-trace/src/noop/dogstatsd.js +6 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +2 -2
- package/packages/dd-trace/src/priority_sampler.js +5 -3
- package/packages/dd-trace/src/proxy.js +41 -13
- package/packages/dd-trace/src/remote_config/index.js +1 -0
- package/packages/dd-trace/src/span_processor.js +7 -4
- package/packages/dd-trace/src/span_stats.js +1 -2
- package/packages/dd-trace/src/standalone/index.js +70 -0
- package/packages/dd-trace/src/standalone/product.js +24 -0
- package/packages/dd-trace/src/standalone/tracesource.js +22 -0
- package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +47 -0
- package/packages/dd-trace/src/tracer.js +3 -2
- package/packages/dd-trace/src/appsec/standalone.js +0 -130
- 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
|
|
817
|
-
* @param
|
|
818
|
-
* @param
|
|
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?:
|
|
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
|
|
825
|
-
* @param
|
|
826
|
-
* @param
|
|
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?:
|
|
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
|
|
833
|
-
* @param
|
|
834
|
-
* @param
|
|
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?:
|
|
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
|
|
841
|
-
* @param
|
|
842
|
-
* @param
|
|
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?:
|
|
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
|
|
849
|
-
* @param
|
|
850
|
-
* @param
|
|
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?:
|
|
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
|
|
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.
|
|
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
|
|
150
|
+
const hasKnownTests = !!knownTests?.jest
|
|
151
151
|
earlyFlakeDetectionNumRetries = this.testEnvironmentOptions._ddEarlyFlakeDetectionNumRetries
|
|
152
152
|
this.knownTestsForThisSuite = hasKnownTests
|
|
153
|
-
? (knownTests
|
|
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
|
|
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
|
|
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)
|
|
@@ -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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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 (
|
|
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:
|
|
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
|
-
|
|
145
|
+
let dynamicInstrumentation
|
|
146
|
+
|
|
147
|
+
module.exports = (config) => {
|
|
148
|
+
if (dynamicInstrumentation) {
|
|
149
|
+
return dynamicInstrumentation
|
|
150
|
+
}
|
|
151
|
+
dynamicInstrumentation = new TestVisDynamicInstrumentation(config)
|
|
152
|
+
return dynamicInstrumentation
|
|
153
|
+
}
|