From 7515899c667a46a24a81b21a0d70cdc2abfb1eb9 Mon Sep 17 00:00:00 2001 From: ishabi Date: Tue, 18 Feb 2025 22:22:53 +0100 Subject: [PATCH 1/7] bump native appsec --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 8fc24a40358..4a129d4b129 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ }, "dependencies": { "@datadog/libdatadog": "^0.4.0", - "@datadog/native-appsec": "8.4.0", + "@datadog/native-appsec": "8.5.0", "@datadog/native-iast-rewriter": "2.8.0", "@datadog/native-iast-taint-tracking": "3.3.0", "@datadog/native-metrics": "^3.1.0", diff --git a/yarn.lock b/yarn.lock index 8504417827d..d5c135df304 100644 --- a/yarn.lock +++ b/yarn.lock @@ -406,10 +406,10 @@ resolved "https://registry.yarnpkg.com/@datadog/libdatadog/-/libdatadog-0.4.0.tgz#aeeea02973f663b555ad9ac30c4015a31d561598" integrity sha512-kGZfFVmQInzt6J4FFGrqMbrDvOxqwk3WqhAreS6n9b/De+iMVy/NMu3V7uKsY5zAvz+uQw0liDJm3ZDVH/MVVw== -"@datadog/native-appsec@8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-8.4.0.tgz#5c44d949ff8f40a94c334554db79c1c470653bae" - integrity sha512-LC47AnpVLpQFEUOP/nIIs+i0wLb8XYO+et3ACaJlHa2YJM3asR4KZTqQjDQNy08PTAUbVvYWKwfSR1qVsU/BeA== +"@datadog/native-appsec@8.5.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@datadog/native-appsec/-/native-appsec-8.5.0.tgz#cf4eea74a07085a0dc9f3e98c130736b38cd61c9" + integrity sha512-95y+fm7jd+3iknzuu57pWEPw9fcK9uSBCPiB4kSPHszHu3bESlZM553tc4ANsz+X3gMkYGVg2pgSydG77nSDJw== dependencies: node-gyp-build "^3.9.0" From c4fb931e5e7544b21ea771dfcd325bdef519a54b Mon Sep 17 00:00:00 2001 From: ishabi Date: Tue, 18 Feb 2025 22:28:00 +0100 Subject: [PATCH 2/7] add waf and rasp span tags and telemetry metrics --- packages/dd-trace/src/appsec/blocking.js | 52 +++++-- packages/dd-trace/src/appsec/reporter.js | 41 ++++- packages/dd-trace/src/appsec/telemetry.js | 141 ++++++++++++++++-- .../src/appsec/waf/waf_context_wrapper.js | 92 ++++++++---- .../dd-trace/src/appsec/waf/waf_manager.js | 15 +- .../dd-trace/test/appsec/blocking.spec.js | 36 +++++ .../dd-trace/test/appsec/telemetry.spec.js | 10 +- 7 files changed, 324 insertions(+), 63 deletions(-) diff --git a/packages/dd-trace/src/appsec/blocking.js b/packages/dd-trace/src/appsec/blocking.js index 733b982a811..df06fde3d09 100644 --- a/packages/dd-trace/src/appsec/blocking.js +++ b/packages/dd-trace/src/appsec/blocking.js @@ -4,6 +4,7 @@ const log = require('../log') const blockedTemplates = require('./blocked_templates') const detectedSpecificEndpoints = {} +const MAX_ERROR_MESSAGE_LENGTH = 512 let templateHtml = blockedTemplates.html let templateJson = blockedTemplates.json @@ -105,24 +106,51 @@ function block (req, res, rootSpan, abortController, actionParameters = defaultB return } - const { body, headers, statusCode } = getBlockingData(req, null, actionParameters) + try { + const { body, headers, statusCode } = getBlockingData(req, null, actionParameters) - rootSpan.addTags({ - 'appsec.blocked': 'true' - }) + for (const headerName of res.getHeaderNames()) { + res.removeHeader(headerName) + } - for (const headerName of res.getHeaderNames()) { - res.removeHeader(headerName) - } + res.writeHead(statusCode, headers) + + // this is needed to call the original end method, since express-session replaces it + res.constructor.prototype.end.call(res, body) - res.writeHead(statusCode, headers) + responseBlockedSet.add(res) - // this is needed to call the original end method, since express-session replaces it - res.constructor.prototype.end.call(res, body) + abortController?.abort() + + rootSpan.addTags({ + 'appsec.blocked': true + }) + } catch (error) { + rootSpan.addTags({ + '_dd.appsec.block.failed': 1 + }) + + if (error.name) { + rootSpan.addTags({ + '_dd.appsec.error.type': error.name // check telemetry logs section + }) + } - responseBlockedSet.add(res) + if (error.message) { + rootSpan.addTags({ + '_dd.appsec.error.message': truncateMessage(error.message) + }) + } + } +} + +function truncateMessage (msg) { + const buf = Buffer.from(msg, 'utf8') + if (buf.length <= MAX_ERROR_MESSAGE_LENGTH) { + return msg + } - abortController?.abort() + return buf.subarray(0, MAX_ERROR_MESSAGE_LENGTH).toString('utf8') } function getBlockingAction (actions) { diff --git a/packages/dd-trace/src/appsec/reporter.js b/packages/dd-trace/src/appsec/reporter.js index 8f16a1a513a..f70cce0f3fc 100644 --- a/packages/dd-trace/src/appsec/reporter.js +++ b/packages/dd-trace/src/appsec/reporter.js @@ -89,16 +89,17 @@ function formatHeaderName (name) { .toLowerCase() } -function reportWafInit (wafVersion, rulesVersion, diagnosticsRules = {}) { +function reportWafInit (wafVersion, rulesVersion, diagnosticsRules, success) { metricsQueue.set('_dd.appsec.waf.version', wafVersion) + // TODO: these should be removed after per-configuration error reporting through remote configuration initiative metricsQueue.set('_dd.appsec.event_rules.loaded', diagnosticsRules.loaded?.length || 0) metricsQueue.set('_dd.appsec.event_rules.error_count', diagnosticsRules.failed?.length || 0) if (diagnosticsRules.failed?.length) { metricsQueue.set('_dd.appsec.event_rules.errors', JSON.stringify(diagnosticsRules.errors)) } - incrementWafInitMetric(wafVersion, rulesVersion) + incrementWafInitMetric(wafVersion, rulesVersion, success) } function reportMetrics (metrics, raspRule) { @@ -109,11 +110,28 @@ function reportMetrics (metrics, raspRule) { if (metrics.rulesVersion) { rootSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion) } + if (raspRule) { updateRaspRequestsMetricTags(metrics, store.req, raspRule) } else { updateWafRequestsMetricTags(metrics, store.req) } + + reportTruncationMetrics(rootSpan, metrics) +} + +function reportTruncationMetrics (rootSpan, metrics) { + if (metrics.maxTruncatedString) { + rootSpan.setTag('_dd.appsec.truncated.string_length', metrics.maxTruncatedString) + } + + if (metrics.maxTruncatedContainerSize) { + rootSpan.setTag('_dd.appsec.truncated.container_size', metrics.maxTruncatedContainerSize) + } + + if (metrics.maxTruncatedContainerDepth) { + rootSpan.setTag('_dd.appsec.truncated.container_depth', metrics.maxTruncatedContainerDepth) + } } function reportAttack (attackData) { @@ -194,6 +212,8 @@ function finishRequest (req, res) { } const metrics = getRequestMetrics(req) + + // WAF metrics if (metrics?.duration) { rootSpan.setTag('_dd.appsec.waf.duration', metrics.duration) } @@ -202,6 +222,15 @@ function finishRequest (req, res) { rootSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt) } + if (metrics?.wafTimeouts) { + rootSpan.setTag('_dd.appsec.waf.timeouts', metrics.wafTimeouts) + } + + if (metrics?.wafErrorCode) { + rootSpan.setTag('_dd.appsec.waf.error', metrics.wafErrorCode) + } + + // RASP metrics if (metrics?.raspDuration) { rootSpan.setTag('_dd.appsec.rasp.duration', metrics.raspDuration) } @@ -210,10 +239,18 @@ function finishRequest (req, res) { rootSpan.setTag('_dd.appsec.rasp.duration_ext', metrics.raspDurationExt) } + if (metrics?.raspTimeouts) { + rootSpan.setTag('_dd.appsec.rasp.timeout', metrics.raspTimeouts) + } + if (metrics?.raspEvalCount) { rootSpan.setTag('_dd.appsec.rasp.rule.eval', metrics.raspEvalCount) } + if (metrics?.raspErrorCode) { + rootSpan.setTag('_dd.appsec.rasp.error', metrics.raspErrorCode) + } + incrementWafRequestsMetric(req) // collect some headers even when no attack is detected diff --git a/packages/dd-trace/src/appsec/telemetry.js b/packages/dd-trace/src/appsec/telemetry.js index d9b94638917..c3024912016 100644 --- a/packages/dd-trace/src/appsec/telemetry.js +++ b/packages/dd-trace/src/appsec/telemetry.js @@ -8,11 +8,14 @@ const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tag const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') const tags = { + BLOCK_FAILURE: 'block_failure', + EVENT_RULES_VERSION: 'event_rules_version', + INPUT_TRUNCATED: 'input_truncated', REQUEST_BLOCKED: 'request_blocked', RULE_TRIGGERED: 'rule_triggered', + WAF_ERROR: 'waf_error', WAF_TIMEOUT: 'waf_timeout', - WAF_VERSION: 'waf_version', - EVENT_RULES_VERSION: 'event_rules_version' + WAF_VERSION: 'waf_version' } const metricsStoreMap = new WeakMap() @@ -34,7 +37,11 @@ function newStore () { durationExt: 0, raspDuration: 0, raspDurationExt: 0, - raspEvalCount: 0 + raspEvalCount: 0, + raspErrorCode: null, + raspTimeouts: 0, + wafErrorCode: null, + wafTimeouts: 0 } } } @@ -59,18 +66,46 @@ function trackWafDurations (metrics, versionsTags) { if (metrics.duration) { appsecMetrics.distribution('waf.duration', versionsTags).track(metrics.duration) } + if (metrics.durationExt) { appsecMetrics.distribution('waf.duration_ext', versionsTags).track(metrics.durationExt) } + + if (metrics.wafTimeouts) { + appsecMetrics.distribution('waf.timeouts', versionsTags).track(metrics.wafTimeouts) + } +} + +function trackRaspDurations (metrics, tags) { + const versionsTags = { + waf_version: tags.waf_version, + event_rules_version: tags.event_rules_version + } + + if (metrics.raspDuration) { + // Incorrect + appsecMetrics.distribution('rasp.rule.duration', tags).track(metrics.raspDuration) + } + + if (metrics.raspDuration) { + appsecMetrics.distribution('rasp.duration', versionsTags).track(metrics.raspDuration) + } + + if (metrics.raspDurationExt) { + appsecMetrics.distribution('rasp.duration_ext', versionsTags).track(metrics.raspDurationExt) + } } function getOrCreateMetricTags (store, versionsTags) { let metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS] if (!metricTags) { metricTags = { + [tags.BLOCK_FAILURE]: false, [tags.REQUEST_BLOCKED]: false, + [tags.INPUT_TRUNCATED]: false, [tags.RULE_TRIGGERED]: false, [tags.WAF_TIMEOUT]: false, + [tags.WAF_ERROR]: false, ...versionsTags } @@ -89,12 +124,16 @@ function updateRaspRequestsMetricTags (metrics, req, raspRule) { if (!enabled) return - const tags = { rule_type: raspRule.type, waf_version: metrics.wafVersion } + const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion) + + const tags = { ...versionsTags, rule_type: raspRule.type } if (raspRule.variant) { tags.rule_variant = raspRule.variant } + trackRaspDurations(metrics, tags) + appsecMetrics.count('rasp.rule.eval', tags).inc(1) if (metrics.wafTimeout) { @@ -104,6 +143,12 @@ function updateRaspRequestsMetricTags (metrics, req, raspRule) { if (metrics.ruleTriggered) { appsecMetrics.count('rasp.rule.match', tags).inc(1) } + + if (metrics.errorCode) { + const errorTags = { ...versionsTags, ...tags, waf_error: metrics.errorCode } + + appsecMetrics.count('rasp.error', errorTags).inc(1) + } } function updateWafRequestsMetricTags (metrics, req) { @@ -127,30 +172,41 @@ function updateWafRequestsMetricTags (metrics, req) { if (blockTriggered) { metricTags[tags.REQUEST_BLOCKED] = blockTriggered } + if (ruleTriggered) { metricTags[tags.RULE_TRIGGERED] = ruleTriggered } + if (wafTimeout) { metricTags[tags.WAF_TIMEOUT] = wafTimeout } - return metricTags + if (metrics.errorCode) { + const errorTags = { ...versionsTags, waf_error: metrics.errorCode } + + appsecMetrics.count('waf.error', errorTags).inc(1) + metricTags[tags.WAF_ERROR] = true + } + + incrementTruncatedMetrics(metrics) } -function incrementWafInitMetric (wafVersion, rulesVersion) { +function incrementWafInitMetric (wafVersion, rulesVersion, success) { if (!enabled) return const versionsTags = getVersionsTags(wafVersion, rulesVersion) + const initTags = { ...versionsTags, success } - appsecMetrics.count('waf.init', versionsTags).inc() + appsecMetrics.count('waf.init', initTags).inc() } -function incrementWafUpdatesMetric (wafVersion, rulesVersion) { +function incrementWafUpdatesMetric (wafVersion, rulesVersion, success) { if (!enabled) return const versionsTags = getVersionsTags(wafVersion, rulesVersion) + const updateTags = { ...versionsTags, success } - appsecMetrics.count('waf.updates', versionsTags).inc() + appsecMetrics.count('waf.updates', updateTags).inc() } function incrementWafRequestsMetric (req) { @@ -159,6 +215,7 @@ function incrementWafRequestsMetric (req) { const store = getStore(req) const metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS] + if (metricTags) { appsecMetrics.count('waf.requests', metricTags).inc() } @@ -166,15 +223,67 @@ function incrementWafRequestsMetric (req) { metricsStoreMap.delete(req) } -function addRequestMetrics (store, { duration, durationExt }) { +function incrementTruncatedMetrics (metrics) { + const truncationReason = getTruncationReason(metrics) + + if (truncationReason > 0) { + const truncationTags = { truncation_reason: 1 } + appsecMetrics.count('appsec.waf.input_truncated', truncationTags).inc(1) + } + + if (metrics?.maxTruncatedString) { + appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 1 }) + .track(metrics.maxTruncatedString) + } + + if (metrics?.maxTruncatedContainerSize) { + appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 2 }) + .track(metrics.maxTruncatedContainerSize) + } + + if (metrics?.maxTruncatedContainerDepth) { + appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 4 }) + .track(metrics.maxTruncatedContainerDepth) + } +} + +function addRequestMetrics (store, metrics) { + const { duration, durationExt, wafTimeout, errorCode } = metrics + store[DD_TELEMETRY_REQUEST_METRICS].duration += duration || 0 store[DD_TELEMETRY_REQUEST_METRICS].durationExt += durationExt || 0 + + if (wafTimeout) { + store[DD_TELEMETRY_REQUEST_METRICS].wafTimeout++ + } + + if (errorCode != null) { + store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode = Math.max( + errorCode, + store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode ?? errorCode + ) + } + + if (getTruncationReason(metrics) > 0) { + store[DD_TELEMETRY_REQUEST_METRICS].input_truncated = true + } } -function addRaspRequestMetrics (store, { duration, durationExt }) { +function addRaspRequestMetrics (store, { duration, durationExt, wafTimeout, errorCode }) { store[DD_TELEMETRY_REQUEST_METRICS].raspDuration += duration || 0 store[DD_TELEMETRY_REQUEST_METRICS].raspDurationExt += durationExt || 0 store[DD_TELEMETRY_REQUEST_METRICS].raspEvalCount++ + + if (wafTimeout) { + store[DD_TELEMETRY_REQUEST_METRICS].raspTimeouts++ + } + + if (errorCode != null) { + store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode = Math.max( + errorCode, + store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode ?? errorCode + ) + } } function incrementMissingUserLoginMetric (framework, eventType) { @@ -202,6 +311,16 @@ function getRequestMetrics (req) { } } +function getTruncationReason ({ maxTruncatedString, maxTruncatedContainerSize, maxTruncatedContainerDepth }) { + let reason = 0 + + if (maxTruncatedString) reason |= 1 // string too long + if (maxTruncatedContainerSize) reason |= 2 // list/map too large + if (maxTruncatedContainerDepth) reason |= 4 // object too deep + + return reason +} + module.exports = { enable, disable, diff --git a/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js b/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js index 1561bd1d0d0..5c116887ae7 100644 --- a/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +++ b/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js @@ -17,8 +17,8 @@ class WAFContextWrapper { this.wafTimeout = wafTimeout this.wafVersion = wafVersion this.rulesVersion = rulesVersion - this.addressesToSkip = new Set() this.knownAddresses = knownAddresses + this.addressesToSkip = new Set() this.cachedUserIdActions = new Map() } @@ -77,48 +77,80 @@ class WAFContextWrapper { if (!payloadHasData) return - try { - const start = process.hrtime.bigint() + const start = process.hrtime.bigint() - const result = this.ddwafContext.run(payload, this.wafTimeout) - - const end = process.hrtime.bigint() + const metrics = { + rulesVersion: this.rulesVersion, + wafVersion: this.wafVersion + } - this.addressesToSkip = newAddressesToSkip + const result = this.runWaf(payload) - const ruleTriggered = !!result.events?.length + if (!result) { + // Binding or other waf unexpected errors + metrics.errorCode = -127 + } else { + if (typeof result.errorCode === 'number' && result.errorCode < 0) { + metrics.errorCode = result.errorCode + } - const blockTriggered = !!getBlockingAction(result.actions) + if (result.metrics?.maxTruncatedString) { + metrics.maxTruncatedString = result.metrics.maxTruncatedString + } - // SPECIAL CASE FOR USER_ID - // TODO: make this universal - if (userId && ruleTriggered && blockTriggered) { - this.setUserIdCache(userId, result) + if (result.metrics?.maxTruncatedContainerSize) { + metrics.maxTruncatedContainerSize = result.metrics.maxTruncatedContainerSize } - Reporter.reportMetrics({ - duration: result.totalRuntime / 1e3, - durationExt: parseInt(end - start) / 1e3, - rulesVersion: this.rulesVersion, - ruleTriggered, - blockTriggered, - wafVersion: this.wafVersion, - wafTimeout: result.timeout - }, raspRule) - - if (ruleTriggered) { - Reporter.reportAttack(JSON.stringify(result.events)) + if (result.metrics?.maxTruncatedContainerDepth) { + metrics.maxTruncatedContainerDepth = result.metrics.maxTruncatedContainerDepth } + } - Reporter.reportDerivatives(result.derivatives) + const end = process.hrtime.bigint() + this.addressesToSkip = newAddressesToSkip - if (wafRunFinished.hasSubscribers) { - wafRunFinished.publish({ payload }) - } + const ruleTriggered = !!result.events?.length + + const blockTriggered = !!getBlockingAction(result.actions) + + // SPECIAL CASE FOR USER_ID + // TODO: make this universal + if (userId && ruleTriggered && blockTriggered) { + this.setUserIdCache(userId, result) + } + + Reporter.reportMetrics({ + ...metrics, + duration: result.totalRuntime / 1e3, + durationExt: parseInt(end - start) / 1e3, + ruleTriggered, + blockTriggered, + wafTimeout: result.timeout + }, raspRule) + + if (ruleTriggered) { + Reporter.reportAttack(JSON.stringify(result.events)) + } + + Reporter.reportDerivatives(result.derivatives) + + if (wafRunFinished.hasSubscribers) { + wafRunFinished.publish({ payload }) + } - return result.actions + return result.actions + } + + runWaf (payload) { + try { + const result = this.ddwafContext.run(payload, this.wafTimeout) + + return result } catch (err) { log.error('[ASM] Error while running the AppSec WAF', err) + + return null } } diff --git a/packages/dd-trace/src/appsec/waf/waf_manager.js b/packages/dd-trace/src/appsec/waf/waf_manager.js index 520438d8a20..419e3b8a82a 100644 --- a/packages/dd-trace/src/appsec/waf/waf_manager.js +++ b/packages/dd-trace/src/appsec/waf/waf_manager.js @@ -9,12 +9,15 @@ const contexts = new WeakMap() class WAFManager { constructor (rules, config) { this.config = config + this.loadStatus = true this.wafTimeout = config.wafTimeout this.ddwaf = this._loadDDWAF(rules) this.ddwafVersion = this.ddwaf.constructor.version() this.rulesVersion = this.ddwaf.diagnostics.ruleset_version - Reporter.reportWafInit(this.ddwafVersion, this.rulesVersion, this.ddwaf.diagnostics.rules) + const diagnosticsRules = this.ddwaf.diagnostics.rules || {} + + Reporter.reportWafInit(this.ddwafVersion, this.rulesVersion, diagnosticsRules, this.loadStatus) } _loadDDWAF (rules) { @@ -27,6 +30,7 @@ class WAFManager { } catch (err) { log.error('[ASM] AppSec could not load native package. In-app WAF features will not be available.') + this.loadStatus = false throw err } } @@ -49,13 +53,18 @@ class WAFManager { } update (newRules) { - this.ddwaf.update(newRules) + let status = true + try { + this.ddwaf.update(newRules) + } catch { + status = false + } if (this.ddwaf.diagnostics.ruleset_version) { this.rulesVersion = this.ddwaf.diagnostics.ruleset_version } - Reporter.reportWafUpdate(this.ddwafVersion, this.rulesVersion) + Reporter.reportWafUpdate(this.ddwafVersion, this.rulesVersion, status) } destroy () { diff --git a/packages/dd-trace/test/appsec/blocking.spec.js b/packages/dd-trace/test/appsec/blocking.spec.js index 1a809410694..b43f6354096 100644 --- a/packages/dd-trace/test/appsec/blocking.spec.js +++ b/packages/dd-trace/test/appsec/blocking.spec.js @@ -266,6 +266,42 @@ describe('blocking', () => { expect(res.constructor.prototype.end).to.have.been.calledOnce }) }) + + describe('block error handling', () => { + beforeEach(() => { + setTemplates(config) + }) + + it('should add appropriate error tags when blocking fails', () => { + res.writeHead.throws(new TypeError('Failed to write headers')) + + block(req, res, rootSpan) + + expect(rootSpan.addTags.getCall(1)).to.have.been.calledWithExactly({ + 'appsec.blocked': 'false', + '_dd.appsec.block.failed': 1 + }) + + expect(rootSpan.addTags.getCall(2)).to.have.been.calledWithExactly({ + '_dd.appsec.error.type': 'TypeError' + }) + + expect(rootSpan.addTags.getCall(3)).to.have.been.calledWithExactly({ + '_dd.appsec.error.message': 'Failed to write headers' + }) + }) + + it('should truncate long error messages to 512 bytes', () => { + const longMessage = 'a'.repeat(1000) + res.writeHead.throws(new Error(longMessage)) + + block(req, res, rootSpan) + + const tags = rootSpan.addTags.getCall(3).args[0] + expect(tags['_dd.appsec.error.message'].length).to.be.at.most(512) + expect(Buffer.from(tags['_dd.appsec.error.message'], 'utf8').length).to.be.at.most(512) + }) + }) }) describe('waf actions', () => { diff --git a/packages/dd-trace/test/appsec/telemetry.spec.js b/packages/dd-trace/test/appsec/telemetry.spec.js index 91ea8660d3a..d1029512e82 100644 --- a/packages/dd-trace/test/appsec/telemetry.spec.js +++ b/packages/dd-trace/test/appsec/telemetry.spec.js @@ -166,7 +166,7 @@ describe('Appsec Telemetry metrics', () => { appsecTelemetry.updateRaspRequestsMetricTags({ duration: 42, durationExt: 52 - }, req, 'rule-type') + }, req, { type: 'rule-type' }) expect(count).to.have.been.calledWith('rasp.rule.eval') expect(count).to.not.have.been.calledWith('rasp.timeout') @@ -179,7 +179,7 @@ describe('Appsec Telemetry metrics', () => { duration: 42, durationExt: 52, wafTimeout: true - }, req, 'rule-type') + }, req, { type: 'rule-type' }) expect(count).to.have.been.calledWith('rasp.rule.eval') expect(count).to.have.been.calledWith('rasp.timeout') @@ -192,7 +192,7 @@ describe('Appsec Telemetry metrics', () => { duration: 42, durationExt: 52, ruleTriggered: true - }, req, 'rule-type') + }, req, { type: 'rule-type' }) expect(count).to.have.been.calledWith('rasp.rule.match') expect(count).to.have.been.calledWith('rasp.rule.eval') @@ -204,12 +204,12 @@ describe('Appsec Telemetry metrics', () => { appsecTelemetry.updateRaspRequestsMetricTags({ duration: 42, durationExt: 52 - }, req, 'rule-type') + }, req, { type: 'rule-type' }) appsecTelemetry.updateRaspRequestsMetricTags({ duration: 24, durationExt: 25 - }, req, 'rule-type') + }, req, { type: 'rule-type' }) const { duration, From a44b0ee45406a5d55de9309b0f2f300bc11ab372 Mon Sep 17 00:00:00 2001 From: ishabi Date: Wed, 19 Feb 2025 09:23:19 +0100 Subject: [PATCH 3/7] add rasp durations metrics --- packages/dd-trace/src/appsec/telemetry.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/dd-trace/src/appsec/telemetry.js b/packages/dd-trace/src/appsec/telemetry.js index c3024912016..542a6e2103f 100644 --- a/packages/dd-trace/src/appsec/telemetry.js +++ b/packages/dd-trace/src/appsec/telemetry.js @@ -76,23 +76,20 @@ function trackWafDurations (metrics, versionsTags) { } } -function trackRaspDurations (metrics, tags) { +function trackRaspCumulativeDurations (store, metrics, tags) { const versionsTags = { waf_version: tags.waf_version, event_rules_version: tags.event_rules_version } - if (metrics.raspDuration) { - // Incorrect - appsecMetrics.distribution('rasp.rule.duration', tags).track(metrics.raspDuration) - } - - if (metrics.raspDuration) { - appsecMetrics.distribution('rasp.duration', versionsTags).track(metrics.raspDuration) + if (metrics.duration) { + const raspDuration = store[DD_TELEMETRY_REQUEST_METRICS].raspDuration + appsecMetrics.distribution('rasp.duration', versionsTags).track(raspDuration) } - if (metrics.raspDurationExt) { - appsecMetrics.distribution('rasp.duration_ext', versionsTags).track(metrics.raspDurationExt) + if (metrics.durationExt) { + const raspDurationExt = store[DD_TELEMETRY_REQUEST_METRICS].raspDurationExt + appsecMetrics.distribution('rasp.duration_ext', versionsTags).track(raspDurationExt) } } @@ -132,7 +129,7 @@ function updateRaspRequestsMetricTags (metrics, req, raspRule) { tags.rule_variant = raspRule.variant } - trackRaspDurations(metrics, tags) + trackRaspCumulativeDurations(store, metrics, tags) appsecMetrics.count('rasp.rule.eval', tags).inc(1) @@ -144,6 +141,10 @@ function updateRaspRequestsMetricTags (metrics, req, raspRule) { appsecMetrics.count('rasp.rule.match', tags).inc(1) } + if (metrics.duration) { + appsecMetrics.distribution('rasp.rule.duration', tags).track(metrics.duration) + } + if (metrics.errorCode) { const errorTags = { ...versionsTags, ...tags, waf_error: metrics.errorCode } From 7b793aa6d46b707fa3e629033b7b910c3cd9bf55 Mon Sep 17 00:00:00 2001 From: ishabi Date: Wed, 19 Feb 2025 10:29:51 +0100 Subject: [PATCH 4/7] split telemetry rasp, waf and user files --- packages/dd-trace/src/appsec/telemetry.js | 338 ------------------ .../dd-trace/src/appsec/telemetry/index.js | 203 +++++++++++ .../dd-trace/src/appsec/telemetry/rasp.js | 70 ++++ .../dd-trace/src/appsec/telemetry/user.js | 24 ++ packages/dd-trace/src/appsec/telemetry/waf.js | 138 +++++++ 5 files changed, 435 insertions(+), 338 deletions(-) delete mode 100644 packages/dd-trace/src/appsec/telemetry.js create mode 100644 packages/dd-trace/src/appsec/telemetry/index.js create mode 100644 packages/dd-trace/src/appsec/telemetry/rasp.js create mode 100644 packages/dd-trace/src/appsec/telemetry/user.js create mode 100644 packages/dd-trace/src/appsec/telemetry/waf.js diff --git a/packages/dd-trace/src/appsec/telemetry.js b/packages/dd-trace/src/appsec/telemetry.js deleted file mode 100644 index 542a6e2103f..00000000000 --- a/packages/dd-trace/src/appsec/telemetry.js +++ /dev/null @@ -1,338 +0,0 @@ -'use strict' - -const telemetryMetrics = require('../telemetry/metrics') - -const appsecMetrics = telemetryMetrics.manager.namespace('appsec') - -const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags') -const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') - -const tags = { - BLOCK_FAILURE: 'block_failure', - EVENT_RULES_VERSION: 'event_rules_version', - INPUT_TRUNCATED: 'input_truncated', - REQUEST_BLOCKED: 'request_blocked', - RULE_TRIGGERED: 'rule_triggered', - WAF_ERROR: 'waf_error', - WAF_TIMEOUT: 'waf_timeout', - WAF_VERSION: 'waf_version' -} - -const metricsStoreMap = new WeakMap() - -let enabled = false - -function enable (telemetryConfig) { - enabled = telemetryConfig?.enabled && telemetryConfig.metrics -} - -function disable () { - enabled = false -} - -function newStore () { - return { - [DD_TELEMETRY_REQUEST_METRICS]: { - duration: 0, - durationExt: 0, - raspDuration: 0, - raspDurationExt: 0, - raspEvalCount: 0, - raspErrorCode: null, - raspTimeouts: 0, - wafErrorCode: null, - wafTimeouts: 0 - } - } -} - -function getStore (req) { - let store = metricsStoreMap.get(req) - if (!store) { - store = newStore() - metricsStoreMap.set(req, store) - } - return store -} - -function getVersionsTags (wafVersion, rulesVersion) { - return { - [tags.WAF_VERSION]: wafVersion, - [tags.EVENT_RULES_VERSION]: rulesVersion - } -} - -function trackWafDurations (metrics, versionsTags) { - if (metrics.duration) { - appsecMetrics.distribution('waf.duration', versionsTags).track(metrics.duration) - } - - if (metrics.durationExt) { - appsecMetrics.distribution('waf.duration_ext', versionsTags).track(metrics.durationExt) - } - - if (metrics.wafTimeouts) { - appsecMetrics.distribution('waf.timeouts', versionsTags).track(metrics.wafTimeouts) - } -} - -function trackRaspCumulativeDurations (store, metrics, tags) { - const versionsTags = { - waf_version: tags.waf_version, - event_rules_version: tags.event_rules_version - } - - if (metrics.duration) { - const raspDuration = store[DD_TELEMETRY_REQUEST_METRICS].raspDuration - appsecMetrics.distribution('rasp.duration', versionsTags).track(raspDuration) - } - - if (metrics.durationExt) { - const raspDurationExt = store[DD_TELEMETRY_REQUEST_METRICS].raspDurationExt - appsecMetrics.distribution('rasp.duration_ext', versionsTags).track(raspDurationExt) - } -} - -function getOrCreateMetricTags (store, versionsTags) { - let metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS] - if (!metricTags) { - metricTags = { - [tags.BLOCK_FAILURE]: false, - [tags.REQUEST_BLOCKED]: false, - [tags.INPUT_TRUNCATED]: false, - [tags.RULE_TRIGGERED]: false, - [tags.WAF_TIMEOUT]: false, - [tags.WAF_ERROR]: false, - - ...versionsTags - } - store[DD_TELEMETRY_WAF_RESULT_TAGS] = metricTags - } - return metricTags -} - -function updateRaspRequestsMetricTags (metrics, req, raspRule) { - if (!req) return - - const store = getStore(req) - - // it does not depend on whether telemetry is enabled or not - addRaspRequestMetrics(store, metrics) - - if (!enabled) return - - const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion) - - const tags = { ...versionsTags, rule_type: raspRule.type } - - if (raspRule.variant) { - tags.rule_variant = raspRule.variant - } - - trackRaspCumulativeDurations(store, metrics, tags) - - appsecMetrics.count('rasp.rule.eval', tags).inc(1) - - if (metrics.wafTimeout) { - appsecMetrics.count('rasp.timeout', tags).inc(1) - } - - if (metrics.ruleTriggered) { - appsecMetrics.count('rasp.rule.match', tags).inc(1) - } - - if (metrics.duration) { - appsecMetrics.distribution('rasp.rule.duration', tags).track(metrics.duration) - } - - if (metrics.errorCode) { - const errorTags = { ...versionsTags, ...tags, waf_error: metrics.errorCode } - - appsecMetrics.count('rasp.error', errorTags).inc(1) - } -} - -function updateWafRequestsMetricTags (metrics, req) { - if (!req) return - - const store = getStore(req) - - // it does not depend on whether telemetry is enabled or not - addRequestMetrics(store, metrics) - - if (!enabled) return - - const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion) - - trackWafDurations(metrics, versionsTags) - - const metricTags = getOrCreateMetricTags(store, versionsTags) - - const { blockTriggered, ruleTriggered, wafTimeout } = metrics - - if (blockTriggered) { - metricTags[tags.REQUEST_BLOCKED] = blockTriggered - } - - if (ruleTriggered) { - metricTags[tags.RULE_TRIGGERED] = ruleTriggered - } - - if (wafTimeout) { - metricTags[tags.WAF_TIMEOUT] = wafTimeout - } - - if (metrics.errorCode) { - const errorTags = { ...versionsTags, waf_error: metrics.errorCode } - - appsecMetrics.count('waf.error', errorTags).inc(1) - metricTags[tags.WAF_ERROR] = true - } - - incrementTruncatedMetrics(metrics) -} - -function incrementWafInitMetric (wafVersion, rulesVersion, success) { - if (!enabled) return - - const versionsTags = getVersionsTags(wafVersion, rulesVersion) - const initTags = { ...versionsTags, success } - - appsecMetrics.count('waf.init', initTags).inc() -} - -function incrementWafUpdatesMetric (wafVersion, rulesVersion, success) { - if (!enabled) return - - const versionsTags = getVersionsTags(wafVersion, rulesVersion) - const updateTags = { ...versionsTags, success } - - appsecMetrics.count('waf.updates', updateTags).inc() -} - -function incrementWafRequestsMetric (req) { - if (!req || !enabled) return - - const store = getStore(req) - - const metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS] - - if (metricTags) { - appsecMetrics.count('waf.requests', metricTags).inc() - } - - metricsStoreMap.delete(req) -} - -function incrementTruncatedMetrics (metrics) { - const truncationReason = getTruncationReason(metrics) - - if (truncationReason > 0) { - const truncationTags = { truncation_reason: 1 } - appsecMetrics.count('appsec.waf.input_truncated', truncationTags).inc(1) - } - - if (metrics?.maxTruncatedString) { - appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 1 }) - .track(metrics.maxTruncatedString) - } - - if (metrics?.maxTruncatedContainerSize) { - appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 2 }) - .track(metrics.maxTruncatedContainerSize) - } - - if (metrics?.maxTruncatedContainerDepth) { - appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 4 }) - .track(metrics.maxTruncatedContainerDepth) - } -} - -function addRequestMetrics (store, metrics) { - const { duration, durationExt, wafTimeout, errorCode } = metrics - - store[DD_TELEMETRY_REQUEST_METRICS].duration += duration || 0 - store[DD_TELEMETRY_REQUEST_METRICS].durationExt += durationExt || 0 - - if (wafTimeout) { - store[DD_TELEMETRY_REQUEST_METRICS].wafTimeout++ - } - - if (errorCode != null) { - store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode = Math.max( - errorCode, - store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode ?? errorCode - ) - } - - if (getTruncationReason(metrics) > 0) { - store[DD_TELEMETRY_REQUEST_METRICS].input_truncated = true - } -} - -function addRaspRequestMetrics (store, { duration, durationExt, wafTimeout, errorCode }) { - store[DD_TELEMETRY_REQUEST_METRICS].raspDuration += duration || 0 - store[DD_TELEMETRY_REQUEST_METRICS].raspDurationExt += durationExt || 0 - store[DD_TELEMETRY_REQUEST_METRICS].raspEvalCount++ - - if (wafTimeout) { - store[DD_TELEMETRY_REQUEST_METRICS].raspTimeouts++ - } - - if (errorCode != null) { - store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode = Math.max( - errorCode, - store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode ?? errorCode - ) - } -} - -function incrementMissingUserLoginMetric (framework, eventType) { - if (!enabled) return - - appsecMetrics.count('instrum.user_auth.missing_user_login', { - framework, - event_type: eventType - }).inc() -} - -function incrementMissingUserIdMetric (framework, eventType) { - if (!enabled) return - - appsecMetrics.count('instrum.user_auth.missing_user_id', { - framework, - event_type: eventType - }).inc() -} - -function getRequestMetrics (req) { - if (req) { - const store = getStore(req) - return store?.[DD_TELEMETRY_REQUEST_METRICS] - } -} - -function getTruncationReason ({ maxTruncatedString, maxTruncatedContainerSize, maxTruncatedContainerDepth }) { - let reason = 0 - - if (maxTruncatedString) reason |= 1 // string too long - if (maxTruncatedContainerSize) reason |= 2 // list/map too large - if (maxTruncatedContainerDepth) reason |= 4 // object too deep - - return reason -} - -module.exports = { - enable, - disable, - - updateWafRequestsMetricTags, - updateRaspRequestsMetricTags, - incrementWafInitMetric, - incrementWafUpdatesMetric, - incrementWafRequestsMetric, - incrementMissingUserLoginMetric, - incrementMissingUserIdMetric, - - getRequestMetrics -} diff --git a/packages/dd-trace/src/appsec/telemetry/index.js b/packages/dd-trace/src/appsec/telemetry/index.js new file mode 100644 index 00000000000..8f41f57065f --- /dev/null +++ b/packages/dd-trace/src/appsec/telemetry/index.js @@ -0,0 +1,203 @@ +'use strict' + +const telemetryMetrics = require('../../telemetry/metrics') + +const { addRaspRequestMetrics, trackRaspMetrics } = require('./rasp') +const { incrementMissingUserId, incrementMissingUserLogin } = require('./user') +const { + addWafRequestMetrics, + trackWafMetrics, + incrementWafInit, + incrementWafUpdates, + incrementWafRequests +} = require('./waf') + +const appsecMetrics = telemetryMetrics.manager.namespace('appsec') + +const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') + +const tags = { + BLOCK_FAILURE: 'block_failure', + EVENT_RULES_VERSION: 'event_rules_version', + INPUT_TRUNCATED: 'input_truncated', + REQUEST_BLOCKED: 'request_blocked', + RULE_TRIGGERED: 'rule_triggered', + WAF_ERROR: 'waf_error', + WAF_TIMEOUT: 'waf_timeout', + WAF_VERSION: 'waf_version' +} + +const metricsStoreMap = new WeakMap() + +let enabled = false + +function enable (telemetryConfig) { + enabled = telemetryConfig?.enabled && telemetryConfig.metrics +} + +function disable () { + enabled = false +} + +function newStore () { + return { + [DD_TELEMETRY_REQUEST_METRICS]: { + duration: 0, + durationExt: 0, + raspDuration: 0, + raspDurationExt: 0, + raspEvalCount: 0, + raspErrorCode: null, + raspTimeouts: 0, + wafErrorCode: null, + wafTimeouts: 0 + } + } +} + +function getStore (req) { + let store = metricsStoreMap.get(req) + if (!store) { + store = newStore() + metricsStoreMap.set(req, store) + } + return store +} + +function getVersionsTags (wafVersion, rulesVersion) { + return { + [tags.WAF_VERSION]: wafVersion, + [tags.EVENT_RULES_VERSION]: rulesVersion + } +} + +function updateRaspRequestsMetricTags (metrics, req, raspRule) { + if (!req) return + + const store = getStore(req) + + // it does not depend on whether telemetry is enabled or not + addRaspRequestMetrics(store, metrics) + + if (!enabled) return + + const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion) + + const tags = { ...versionsTags, rule_type: raspRule.type } + + if (raspRule.variant) { + tags.rule_variant = raspRule.variant + } + + trackRaspMetrics(store, metrics, tags) + + incrementTruncatedMetrics(metrics) +} + +function updateWafRequestsMetricTags (metrics, req) { + if (!req) return + + const store = getStore(req) + + // it does not depend on whether telemetry is enabled or not + addWafRequestMetrics(store, metrics) + + if (!enabled) return + + const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion) + + trackWafMetrics(store, metrics, versionsTags) + + incrementTruncatedMetrics(metrics) +} + +function incrementWafInitMetric (wafVersion, rulesVersion, success) { + if (!enabled) return + + const versionsTags = getVersionsTags(wafVersion, rulesVersion) + incrementWafInit(versionsTags, success) +} + +function incrementWafUpdatesMetric (wafVersion, rulesVersion, success) { + if (!enabled) return + + const versionsTags = getVersionsTags(wafVersion, rulesVersion) + incrementWafUpdates(versionsTags, success) +} + +function incrementWafRequestsMetric (req) { + if (!req || !enabled) return + + const store = getStore(req) + incrementWafRequests(store) + + metricsStoreMap.delete(req) +} + +function incrementTruncatedMetrics (metrics) { + const truncationReason = getTruncationReason(metrics) + + if (truncationReason > 0) { + const truncationTags = { truncation_reason: 1 } + appsecMetrics.count('appsec.waf.input_truncated', truncationTags).inc(1) + } + + if (metrics?.maxTruncatedString) { + appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 1 }) + .track(metrics.maxTruncatedString) + } + + if (metrics?.maxTruncatedContainerSize) { + appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 2 }) + .track(metrics.maxTruncatedContainerSize) + } + + if (metrics?.maxTruncatedContainerDepth) { + appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 4 }) + .track(metrics.maxTruncatedContainerDepth) + } +} + +function incrementMissingUserLoginMetric (framework, eventType) { + if (!enabled) return + + incrementMissingUserLogin(framework, eventType) +} + +function incrementMissingUserIdMetric (framework, eventType) { + if (!enabled) return + + incrementMissingUserId(framework, eventType) +} + +function getRequestMetrics (req) { + if (req) { + const store = getStore(req) + return store?.[DD_TELEMETRY_REQUEST_METRICS] + } +} + +function getTruncationReason ({ maxTruncatedString, maxTruncatedContainerSize, maxTruncatedContainerDepth }) { + let reason = 0 + + if (maxTruncatedString) reason |= 1 // string too long + if (maxTruncatedContainerSize) reason |= 2 // list/map too large + if (maxTruncatedContainerDepth) reason |= 4 // object too deep + + return reason +} + +module.exports = { + enable, + disable, + + updateWafRequestsMetricTags, + updateRaspRequestsMetricTags, + incrementWafInitMetric, + incrementWafUpdatesMetric, + incrementWafRequestsMetric, + incrementMissingUserLoginMetric, + incrementMissingUserIdMetric, + + getRequestMetrics +} diff --git a/packages/dd-trace/src/appsec/telemetry/rasp.js b/packages/dd-trace/src/appsec/telemetry/rasp.js new file mode 100644 index 00000000000..2a9c3a2feba --- /dev/null +++ b/packages/dd-trace/src/appsec/telemetry/rasp.js @@ -0,0 +1,70 @@ +'use strict' + +const telemetryMetrics = require('../../telemetry/metrics') + +const appsecMetrics = telemetryMetrics.manager.namespace('appsec') + +const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') + +function addRaspRequestMetrics (store, { duration, durationExt, wafTimeout, errorCode }) { + store[DD_TELEMETRY_REQUEST_METRICS].raspDuration += duration || 0 + store[DD_TELEMETRY_REQUEST_METRICS].raspDurationExt += durationExt || 0 + store[DD_TELEMETRY_REQUEST_METRICS].raspEvalCount++ + + if (wafTimeout) { + store[DD_TELEMETRY_REQUEST_METRICS].raspTimeouts++ + } + + if (errorCode != null) { + store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode = Math.max( + errorCode, + store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode ?? errorCode + ) + } +} + +function trackRaspCumulativeDurations (store, metrics, tags) { + const versionsTags = { + waf_version: tags.waf_version, + event_rules_version: tags.event_rules_version + } + + if (metrics.duration) { + const raspDuration = store[DD_TELEMETRY_REQUEST_METRICS].raspDuration + appsecMetrics.distribution('rasp.duration', versionsTags).track(raspDuration) + } + + if (metrics.durationExt) { + const raspDurationExt = store[DD_TELEMETRY_REQUEST_METRICS].raspDurationExt + appsecMetrics.distribution('rasp.duration_ext', versionsTags).track(raspDurationExt) + } +} + +function trackRaspMetrics (store, metrics, tags) { + trackRaspCumulativeDurations(store, metrics, tags) + + appsecMetrics.count('rasp.rule.eval', tags).inc(1) + + if (metrics.wafTimeout) { + appsecMetrics.count('rasp.timeout', tags).inc(1) + } + + if (metrics.ruleTriggered) { + appsecMetrics.count('rasp.rule.match', tags).inc(1) + } + + if (metrics.duration) { + appsecMetrics.distribution('rasp.rule.duration', tags).track(metrics.duration) + } + + if (metrics.errorCode) { + const errorTags = { ...tags, waf_error: metrics.errorCode } + + appsecMetrics.count('rasp.error', errorTags).inc(1) + } +} + +module.exports = { + addRaspRequestMetrics, + trackRaspMetrics +} diff --git a/packages/dd-trace/src/appsec/telemetry/user.js b/packages/dd-trace/src/appsec/telemetry/user.js new file mode 100644 index 00000000000..9f082ae12ec --- /dev/null +++ b/packages/dd-trace/src/appsec/telemetry/user.js @@ -0,0 +1,24 @@ +'use strict' + +const telemetryMetrics = require('../../telemetry/metrics') + +const appsecMetrics = telemetryMetrics.manager.namespace('appsec') + +function incrementMissingUserLogin (framework, eventType) { + appsecMetrics.count('instrum.user_auth.missing_user_login', { + framework, + event_type: eventType + }).inc() +} + +function incrementMissingUserId (framework, eventType) { + appsecMetrics.count('instrum.user_auth.missing_user_id', { + framework, + event_type: eventType + }).inc() +} + +module.exports = { + incrementMissingUserLogin, + incrementMissingUserId +} diff --git a/packages/dd-trace/src/appsec/telemetry/waf.js b/packages/dd-trace/src/appsec/telemetry/waf.js new file mode 100644 index 00000000000..fe4c9566fb9 --- /dev/null +++ b/packages/dd-trace/src/appsec/telemetry/waf.js @@ -0,0 +1,138 @@ +'use strict' + +const telemetryMetrics = require('../../telemetry/metrics') + +const appsecMetrics = telemetryMetrics.manager.namespace('appsec') + +const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags') +const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') + +const tags = { + BLOCK_FAILURE: 'block_failure', + EVENT_RULES_VERSION: 'event_rules_version', + INPUT_TRUNCATED: 'input_truncated', + REQUEST_BLOCKED: 'request_blocked', + RULE_TRIGGERED: 'rule_triggered', + WAF_ERROR: 'waf_error', + WAF_TIMEOUT: 'waf_timeout', + WAF_VERSION: 'waf_version' +} + +function addWafRequestMetrics (store, metrics) { + const { duration, durationExt, wafTimeout, errorCode } = metrics + + store[DD_TELEMETRY_REQUEST_METRICS].duration += duration || 0 + store[DD_TELEMETRY_REQUEST_METRICS].durationExt += durationExt || 0 + + if (wafTimeout) { + store[DD_TELEMETRY_REQUEST_METRICS].wafTimeout++ + } + + if (errorCode != null) { + store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode = Math.max( + errorCode, + store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode ?? errorCode + ) + } + + if (getTruncationReason(metrics) > 0) { + store[DD_TELEMETRY_REQUEST_METRICS].input_truncated = true + } +} + +function getTruncationReason ({ maxTruncatedString, maxTruncatedContainerSize, maxTruncatedContainerDepth }) { + let reason = 0 + + if (maxTruncatedString) reason |= 1 // string too long + if (maxTruncatedContainerSize) reason |= 2 // list/map too large + if (maxTruncatedContainerDepth) reason |= 4 // object too deep + + return reason +} + +function trackWafDurations (metrics, versionsTags) { + if (metrics.duration) { + appsecMetrics.distribution('waf.duration', versionsTags).track(metrics.duration) + } + + if (metrics.durationExt) { + appsecMetrics.distribution('waf.duration_ext', versionsTags).track(metrics.durationExt) + } + + if (metrics.wafTimeouts) { + appsecMetrics.distribution('waf.timeouts', versionsTags).track(metrics.wafTimeouts) + } +} + +function trackWafMetrics (store, metrics, versionsTags) { + trackWafDurations(metrics, versionsTags) + + const metricTags = getOrCreateMetricTags(store, versionsTags) + + const { blockTriggered, ruleTriggered, wafTimeout } = metrics + + if (blockTriggered) { + metricTags[tags.REQUEST_BLOCKED] = blockTriggered + } + + if (ruleTriggered) { + metricTags[tags.RULE_TRIGGERED] = ruleTriggered + } + + if (wafTimeout) { + metricTags[tags.WAF_TIMEOUT] = wafTimeout + } + + if (metrics.errorCode) { + const errorTags = { ...versionsTags, waf_error: metrics.errorCode } + + appsecMetrics.count('waf.error', errorTags).inc(1) + metricTags[tags.WAF_ERROR] = true + } +} + +function getOrCreateMetricTags (store, versionsTags) { + let metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS] + if (!metricTags) { + metricTags = { + [tags.BLOCK_FAILURE]: false, + [tags.REQUEST_BLOCKED]: false, + [tags.INPUT_TRUNCATED]: false, + [tags.RULE_TRIGGERED]: false, + [tags.WAF_TIMEOUT]: false, + [tags.WAF_ERROR]: false, + + ...versionsTags + } + store[DD_TELEMETRY_WAF_RESULT_TAGS] = metricTags + } + return metricTags +} + +function incrementWafInit (versionsTags, success) { + const initTags = { ...versionsTags, success } + + appsecMetrics.count('waf.init', initTags).inc() +} + +function incrementWafUpdates (versionsTags, success) { + const updateTags = { ...versionsTags, success } + + appsecMetrics.count('waf.updates', updateTags).inc() +} + +function incrementWafRequests (store) { + const metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS] + + if (metricTags) { + appsecMetrics.count('waf.requests', metricTags).inc() + } +} + +module.exports = { + addWafRequestMetrics, + trackWafMetrics, + incrementWafInit, + incrementWafUpdates, + incrementWafRequests +} From 4c788b857733b56a07e7add80257f450443b26c2 Mon Sep 17 00:00:00 2001 From: ishabi Date: Wed, 19 Feb 2025 11:29:56 +0100 Subject: [PATCH 5/7] Add a common file for utils --- .../dd-trace/src/appsec/telemetry/common.js | 24 +++++++++++++ .../dd-trace/src/appsec/telemetry/index.js | 36 ++++--------------- .../dd-trace/src/appsec/telemetry/rasp.js | 12 +++++-- packages/dd-trace/src/appsec/telemetry/waf.js | 24 +++++-------- 4 files changed, 49 insertions(+), 47 deletions(-) create mode 100644 packages/dd-trace/src/appsec/telemetry/common.js diff --git a/packages/dd-trace/src/appsec/telemetry/common.js b/packages/dd-trace/src/appsec/telemetry/common.js new file mode 100644 index 00000000000..7e9df56e11d --- /dev/null +++ b/packages/dd-trace/src/appsec/telemetry/common.js @@ -0,0 +1,24 @@ +'use strinct' + +const tags = { + BLOCK_FAILURE: 'block_failure', + EVENT_RULES_VERSION: 'event_rules_version', + INPUT_TRUNCATED: 'input_truncated', + REQUEST_BLOCKED: 'request_blocked', + RULE_TRIGGERED: 'rule_triggered', + WAF_ERROR: 'waf_error', + WAF_TIMEOUT: 'waf_timeout', + WAF_VERSION: 'waf_version' +} + +function getVersionsTags (wafVersion, rulesVersion) { + return { + [tags.WAF_VERSION]: wafVersion, + [tags.EVENT_RULES_VERSION]: rulesVersion + } +} + +module.exports = { + tags, + getVersionsTags +} diff --git a/packages/dd-trace/src/appsec/telemetry/index.js b/packages/dd-trace/src/appsec/telemetry/index.js index 8f41f57065f..90f2e42a6a0 100644 --- a/packages/dd-trace/src/appsec/telemetry/index.js +++ b/packages/dd-trace/src/appsec/telemetry/index.js @@ -16,17 +16,6 @@ const appsecMetrics = telemetryMetrics.manager.namespace('appsec') const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') -const tags = { - BLOCK_FAILURE: 'block_failure', - EVENT_RULES_VERSION: 'event_rules_version', - INPUT_TRUNCATED: 'input_truncated', - REQUEST_BLOCKED: 'request_blocked', - RULE_TRIGGERED: 'rule_triggered', - WAF_ERROR: 'waf_error', - WAF_TIMEOUT: 'waf_timeout', - WAF_VERSION: 'waf_version' -} - const metricsStoreMap = new WeakMap() let enabled = false @@ -64,13 +53,6 @@ function getStore (req) { return store } -function getVersionsTags (wafVersion, rulesVersion) { - return { - [tags.WAF_VERSION]: wafVersion, - [tags.EVENT_RULES_VERSION]: rulesVersion - } -} - function updateRaspRequestsMetricTags (metrics, req, raspRule) { if (!req) return @@ -81,15 +63,13 @@ function updateRaspRequestsMetricTags (metrics, req, raspRule) { if (!enabled) return - const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion) - - const tags = { ...versionsTags, rule_type: raspRule.type } + const ruleTags = { rule_type: raspRule.type } if (raspRule.variant) { - tags.rule_variant = raspRule.variant + ruleTags.rule_variant = raspRule.variant } - trackRaspMetrics(store, metrics, tags) + trackRaspMetrics(store, metrics, ruleTags) incrementTruncatedMetrics(metrics) } @@ -104,9 +84,7 @@ function updateWafRequestsMetricTags (metrics, req) { if (!enabled) return - const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion) - - trackWafMetrics(store, metrics, versionsTags) + trackWafMetrics(store, metrics) incrementTruncatedMetrics(metrics) } @@ -114,15 +92,13 @@ function updateWafRequestsMetricTags (metrics, req) { function incrementWafInitMetric (wafVersion, rulesVersion, success) { if (!enabled) return - const versionsTags = getVersionsTags(wafVersion, rulesVersion) - incrementWafInit(versionsTags, success) + incrementWafInit(wafVersion, rulesVersion, success) } function incrementWafUpdatesMetric (wafVersion, rulesVersion, success) { if (!enabled) return - const versionsTags = getVersionsTags(wafVersion, rulesVersion) - incrementWafUpdates(versionsTags, success) + incrementWafUpdates(wafVersion, rulesVersion, success) } function incrementWafRequestsMetric (req) { diff --git a/packages/dd-trace/src/appsec/telemetry/rasp.js b/packages/dd-trace/src/appsec/telemetry/rasp.js index 2a9c3a2feba..a362d9a34ab 100644 --- a/packages/dd-trace/src/appsec/telemetry/rasp.js +++ b/packages/dd-trace/src/appsec/telemetry/rasp.js @@ -1,6 +1,7 @@ 'use strict' const telemetryMetrics = require('../../telemetry/metrics') +const { getVersionsTags } = require('./common') const appsecMetrics = telemetryMetrics.manager.namespace('appsec') @@ -15,7 +16,7 @@ function addRaspRequestMetrics (store, { duration, durationExt, wafTimeout, erro store[DD_TELEMETRY_REQUEST_METRICS].raspTimeouts++ } - if (errorCode != null) { + if (errorCode) { store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode = Math.max( errorCode, store[DD_TELEMETRY_REQUEST_METRICS].raspErrorCode ?? errorCode @@ -40,7 +41,14 @@ function trackRaspCumulativeDurations (store, metrics, tags) { } } -function trackRaspMetrics (store, metrics, tags) { +function trackRaspMetrics (store, metrics, ruleTags) { + const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion) + + const tags = { + ...versionsTags, + ...ruleTags + } + trackRaspCumulativeDurations(store, metrics, tags) appsecMetrics.count('rasp.rule.eval', tags).inc(1) diff --git a/packages/dd-trace/src/appsec/telemetry/waf.js b/packages/dd-trace/src/appsec/telemetry/waf.js index fe4c9566fb9..c588fc7425c 100644 --- a/packages/dd-trace/src/appsec/telemetry/waf.js +++ b/packages/dd-trace/src/appsec/telemetry/waf.js @@ -1,23 +1,13 @@ 'use strict' const telemetryMetrics = require('../../telemetry/metrics') +const { tags, getVersionsTags } = require('./common') const appsecMetrics = telemetryMetrics.manager.namespace('appsec') const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags') const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') -const tags = { - BLOCK_FAILURE: 'block_failure', - EVENT_RULES_VERSION: 'event_rules_version', - INPUT_TRUNCATED: 'input_truncated', - REQUEST_BLOCKED: 'request_blocked', - RULE_TRIGGERED: 'rule_triggered', - WAF_ERROR: 'waf_error', - WAF_TIMEOUT: 'waf_timeout', - WAF_VERSION: 'waf_version' -} - function addWafRequestMetrics (store, metrics) { const { duration, durationExt, wafTimeout, errorCode } = metrics @@ -28,7 +18,7 @@ function addWafRequestMetrics (store, metrics) { store[DD_TELEMETRY_REQUEST_METRICS].wafTimeout++ } - if (errorCode != null) { + if (errorCode) { store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode = Math.max( errorCode, store[DD_TELEMETRY_REQUEST_METRICS].wafErrorCode ?? errorCode @@ -64,7 +54,9 @@ function trackWafDurations (metrics, versionsTags) { } } -function trackWafMetrics (store, metrics, versionsTags) { +function trackWafMetrics (store, metrics) { + const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion) + trackWafDurations(metrics, versionsTags) const metricTags = getOrCreateMetricTags(store, versionsTags) @@ -109,13 +101,15 @@ function getOrCreateMetricTags (store, versionsTags) { return metricTags } -function incrementWafInit (versionsTags, success) { +function incrementWafInit (wafVersion, rulesVersion, success) { + const versionsTags = getVersionsTags(wafVersion, rulesVersion) const initTags = { ...versionsTags, success } appsecMetrics.count('waf.init', initTags).inc() } -function incrementWafUpdates (versionsTags, success) { +function incrementWafUpdates (wafVersion, rulesVersion, success) { + const versionsTags = getVersionsTags(wafVersion, rulesVersion) const updateTags = { ...versionsTags, success } appsecMetrics.count('waf.updates', updateTags).inc() From bc8bb99552275e302e3918564edb2ec035ba9b78 Mon Sep 17 00:00:00 2001 From: ishabi Date: Wed, 19 Feb 2025 16:02:20 +0100 Subject: [PATCH 6/7] report truncation on waf only --- .../dd-trace/src/appsec/telemetry/index.js | 42 ------------ packages/dd-trace/src/appsec/telemetry/waf.js | 67 ++++++++++++++----- 2 files changed, 49 insertions(+), 60 deletions(-) diff --git a/packages/dd-trace/src/appsec/telemetry/index.js b/packages/dd-trace/src/appsec/telemetry/index.js index 90f2e42a6a0..aad79dd2028 100644 --- a/packages/dd-trace/src/appsec/telemetry/index.js +++ b/packages/dd-trace/src/appsec/telemetry/index.js @@ -1,7 +1,5 @@ 'use strict' -const telemetryMetrics = require('../../telemetry/metrics') - const { addRaspRequestMetrics, trackRaspMetrics } = require('./rasp') const { incrementMissingUserId, incrementMissingUserLogin } = require('./user') const { @@ -12,8 +10,6 @@ const { incrementWafRequests } = require('./waf') -const appsecMetrics = telemetryMetrics.manager.namespace('appsec') - const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') const metricsStoreMap = new WeakMap() @@ -70,8 +66,6 @@ function updateRaspRequestsMetricTags (metrics, req, raspRule) { } trackRaspMetrics(store, metrics, ruleTags) - - incrementTruncatedMetrics(metrics) } function updateWafRequestsMetricTags (metrics, req) { @@ -85,8 +79,6 @@ function updateWafRequestsMetricTags (metrics, req) { if (!enabled) return trackWafMetrics(store, metrics) - - incrementTruncatedMetrics(metrics) } function incrementWafInitMetric (wafVersion, rulesVersion, success) { @@ -110,30 +102,6 @@ function incrementWafRequestsMetric (req) { metricsStoreMap.delete(req) } -function incrementTruncatedMetrics (metrics) { - const truncationReason = getTruncationReason(metrics) - - if (truncationReason > 0) { - const truncationTags = { truncation_reason: 1 } - appsecMetrics.count('appsec.waf.input_truncated', truncationTags).inc(1) - } - - if (metrics?.maxTruncatedString) { - appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 1 }) - .track(metrics.maxTruncatedString) - } - - if (metrics?.maxTruncatedContainerSize) { - appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 2 }) - .track(metrics.maxTruncatedContainerSize) - } - - if (metrics?.maxTruncatedContainerDepth) { - appsecMetrics.distribution('appsec.waf.truncated_value_size', { truncation_reason: 4 }) - .track(metrics.maxTruncatedContainerDepth) - } -} - function incrementMissingUserLoginMetric (framework, eventType) { if (!enabled) return @@ -153,16 +121,6 @@ function getRequestMetrics (req) { } } -function getTruncationReason ({ maxTruncatedString, maxTruncatedContainerSize, maxTruncatedContainerDepth }) { - let reason = 0 - - if (maxTruncatedString) reason |= 1 // string too long - if (maxTruncatedContainerSize) reason |= 2 // list/map too large - if (maxTruncatedContainerDepth) reason |= 4 // object too deep - - return reason -} - module.exports = { enable, disable, diff --git a/packages/dd-trace/src/appsec/telemetry/waf.js b/packages/dd-trace/src/appsec/telemetry/waf.js index c588fc7425c..316f024ea80 100644 --- a/packages/dd-trace/src/appsec/telemetry/waf.js +++ b/packages/dd-trace/src/appsec/telemetry/waf.js @@ -8,6 +8,12 @@ const appsecMetrics = telemetryMetrics.manager.namespace('appsec') const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags') const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') +const TRUNCATION_FLAGS = { + LONG_STRING: 1, + LARGE_CONTAINER: 2, + DEEP_CONTAINER: 4 +} + function addWafRequestMetrics (store, metrics) { const { duration, durationExt, wafTimeout, errorCode } = metrics @@ -15,7 +21,7 @@ function addWafRequestMetrics (store, metrics) { store[DD_TELEMETRY_REQUEST_METRICS].durationExt += durationExt || 0 if (wafTimeout) { - store[DD_TELEMETRY_REQUEST_METRICS].wafTimeout++ + store[DD_TELEMETRY_REQUEST_METRICS].wafTimeouts++ } if (errorCode) { @@ -30,16 +36,6 @@ function addWafRequestMetrics (store, metrics) { } } -function getTruncationReason ({ maxTruncatedString, maxTruncatedContainerSize, maxTruncatedContainerDepth }) { - let reason = 0 - - if (maxTruncatedString) reason |= 1 // string too long - if (maxTruncatedContainerSize) reason |= 2 // list/map too large - if (maxTruncatedContainerDepth) reason |= 4 // object too deep - - return reason -} - function trackWafDurations (metrics, versionsTags) { if (metrics.duration) { appsecMetrics.distribution('waf.duration', versionsTags).track(metrics.duration) @@ -48,10 +44,6 @@ function trackWafDurations (metrics, versionsTags) { if (metrics.durationExt) { appsecMetrics.distribution('waf.duration_ext', versionsTags).track(metrics.durationExt) } - - if (metrics.wafTimeouts) { - appsecMetrics.distribution('waf.timeouts', versionsTags).track(metrics.wafTimeouts) - } } function trackWafMetrics (store, metrics) { @@ -64,15 +56,15 @@ function trackWafMetrics (store, metrics) { const { blockTriggered, ruleTriggered, wafTimeout } = metrics if (blockTriggered) { - metricTags[tags.REQUEST_BLOCKED] = blockTriggered + metricTags[tags.REQUEST_BLOCKED] = true } if (ruleTriggered) { - metricTags[tags.RULE_TRIGGERED] = ruleTriggered + metricTags[tags.RULE_TRIGGERED] = true } if (wafTimeout) { - metricTags[tags.WAF_TIMEOUT] = wafTimeout + metricTags[tags.WAF_TIMEOUT] = true } if (metrics.errorCode) { @@ -81,6 +73,45 @@ function trackWafMetrics (store, metrics) { appsecMetrics.count('waf.error', errorTags).inc(1) metricTags[tags.WAF_ERROR] = true } + + incrementTruncatedMetrics(metrics) +} + +function incrementTruncatedMetrics (metrics) { + const truncationReason = getTruncationReason(metrics) + + if (truncationReason > 0) { + const truncationTags = { truncation_reason: truncationReason } + appsecMetrics.count('appsec.waf.input_truncated', truncationTags).inc(1) + } + + if (metrics?.maxTruncatedString) { + appsecMetrics.distribution('appsec.waf.truncated_value_size', + { truncation_reason: TRUNCATION_FLAGS.LONG_STRING }) + .track(metrics.maxTruncatedString) + } + + if (metrics?.maxTruncatedContainerSize) { + appsecMetrics.distribution('appsec.waf.truncated_value_size', + { truncation_reason: TRUNCATION_FLAGS.LARGE_CONTAINER }) + .track(metrics.maxTruncatedContainerSize) + } + + if (metrics?.maxTruncatedContainerDepth) { + appsecMetrics.distribution('appsec.waf.truncated_value_size', + { truncation_reason: TRUNCATION_FLAGS.DEEP_CONTAINER }) + .track(metrics.maxTruncatedContainerDepth) + } +} + +function getTruncationReason ({ maxTruncatedString, maxTruncatedContainerSize, maxTruncatedContainerDepth }) { + let reason = 0 + + if (maxTruncatedString) reason |= TRUNCATION_FLAGS.LONG_STRING + if (maxTruncatedContainerSize) reason |= TRUNCATION_FLAGS.LARGE_CONTAINER + if (maxTruncatedContainerDepth) reason |= TRUNCATION_FLAGS.DEEP_CONTAINER + + return reason } function getOrCreateMetricTags (store, versionsTags) { From 28ca64d38abd9c2b9123d3a5b16f893fbf38a2f5 Mon Sep 17 00:00:00 2001 From: ishabi Date: Wed, 19 Feb 2025 17:04:48 +0100 Subject: [PATCH 7/7] share telemetry request metric symbol --- packages/dd-trace/src/appsec/telemetry/common.js | 5 ++++- packages/dd-trace/src/appsec/telemetry/index.js | 3 +-- packages/dd-trace/src/appsec/telemetry/rasp.js | 4 +--- packages/dd-trace/src/appsec/telemetry/waf.js | 3 +-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/dd-trace/src/appsec/telemetry/common.js b/packages/dd-trace/src/appsec/telemetry/common.js index 7e9df56e11d..b3c0ce0c7d3 100644 --- a/packages/dd-trace/src/appsec/telemetry/common.js +++ b/packages/dd-trace/src/appsec/telemetry/common.js @@ -1,5 +1,7 @@ 'use strinct' +const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') + const tags = { BLOCK_FAILURE: 'block_failure', EVENT_RULES_VERSION: 'event_rules_version', @@ -20,5 +22,6 @@ function getVersionsTags (wafVersion, rulesVersion) { module.exports = { tags, - getVersionsTags + getVersionsTags, + DD_TELEMETRY_REQUEST_METRICS } diff --git a/packages/dd-trace/src/appsec/telemetry/index.js b/packages/dd-trace/src/appsec/telemetry/index.js index aad79dd2028..a70b360d886 100644 --- a/packages/dd-trace/src/appsec/telemetry/index.js +++ b/packages/dd-trace/src/appsec/telemetry/index.js @@ -1,5 +1,6 @@ 'use strict' +const { DD_TELEMETRY_REQUEST_METRICS } = require('./common') const { addRaspRequestMetrics, trackRaspMetrics } = require('./rasp') const { incrementMissingUserId, incrementMissingUserLogin } = require('./user') const { @@ -10,8 +11,6 @@ const { incrementWafRequests } = require('./waf') -const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') - const metricsStoreMap = new WeakMap() let enabled = false diff --git a/packages/dd-trace/src/appsec/telemetry/rasp.js b/packages/dd-trace/src/appsec/telemetry/rasp.js index a362d9a34ab..bb3a5e5dbe2 100644 --- a/packages/dd-trace/src/appsec/telemetry/rasp.js +++ b/packages/dd-trace/src/appsec/telemetry/rasp.js @@ -1,12 +1,10 @@ 'use strict' const telemetryMetrics = require('../../telemetry/metrics') -const { getVersionsTags } = require('./common') +const { DD_TELEMETRY_REQUEST_METRICS, getVersionsTags } = require('./common') const appsecMetrics = telemetryMetrics.manager.namespace('appsec') -const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') - function addRaspRequestMetrics (store, { duration, durationExt, wafTimeout, errorCode }) { store[DD_TELEMETRY_REQUEST_METRICS].raspDuration += duration || 0 store[DD_TELEMETRY_REQUEST_METRICS].raspDurationExt += durationExt || 0 diff --git a/packages/dd-trace/src/appsec/telemetry/waf.js b/packages/dd-trace/src/appsec/telemetry/waf.js index 316f024ea80..36c641c4213 100644 --- a/packages/dd-trace/src/appsec/telemetry/waf.js +++ b/packages/dd-trace/src/appsec/telemetry/waf.js @@ -1,12 +1,11 @@ 'use strict' const telemetryMetrics = require('../../telemetry/metrics') -const { tags, getVersionsTags } = require('./common') +const { tags, getVersionsTags, DD_TELEMETRY_REQUEST_METRICS } = require('./common') const appsecMetrics = telemetryMetrics.manager.namespace('appsec') const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags') -const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics') const TRUNCATION_FLAGS = { LONG_STRING: 1,