dd-trace 2.17.0 → 2.19.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 +40 -2
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/cucumber.js +0 -2
- package/packages/datadog-instrumentations/src/elasticsearch.js +51 -47
- package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/mariadb.js +43 -69
- package/packages/datadog-instrumentations/src/mocha.js +14 -18
- package/packages/datadog-instrumentations/src/opensearch.js +10 -0
- package/packages/datadog-instrumentations/src/pg.js +2 -1
- package/packages/datadog-instrumentations/src/restify.js +1 -0
- package/packages/datadog-instrumentations/src/rhea.js +20 -17
- package/packages/datadog-plugin-amqp10/src/consumer.js +32 -0
- package/packages/datadog-plugin-amqp10/src/index.js +11 -101
- package/packages/datadog-plugin-amqp10/src/producer.js +34 -0
- package/packages/datadog-plugin-amqp10/src/util.js +15 -0
- package/packages/datadog-plugin-amqplib/src/client.js +38 -0
- package/packages/datadog-plugin-amqplib/src/consumer.js +40 -0
- package/packages/datadog-plugin-amqplib/src/index.js +14 -102
- package/packages/datadog-plugin-amqplib/src/producer.js +37 -0
- package/packages/datadog-plugin-amqplib/src/util.js +14 -0
- package/packages/datadog-plugin-dns/src/index.js +16 -91
- package/packages/datadog-plugin-dns/src/lookup.js +40 -0
- package/packages/datadog-plugin-dns/src/lookup_service.js +24 -0
- package/packages/datadog-plugin-dns/src/resolve.js +24 -0
- package/packages/datadog-plugin-dns/src/reverse.js +21 -0
- package/packages/datadog-plugin-elasticsearch/src/index.js +7 -7
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +25 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +42 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +14 -99
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +34 -0
- package/packages/datadog-plugin-graphql/src/execute.js +73 -0
- package/packages/datadog-plugin-graphql/src/index.js +14 -176
- package/packages/datadog-plugin-graphql/src/parse.js +32 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +70 -76
- package/packages/datadog-plugin-graphql/src/validate.js +28 -0
- package/packages/datadog-plugin-grpc/src/client.js +46 -55
- package/packages/datadog-plugin-grpc/src/index.js +7 -24
- package/packages/datadog-plugin-grpc/src/server.js +50 -52
- package/packages/datadog-plugin-grpc/src/util.js +15 -14
- package/packages/datadog-plugin-http/src/index.js +7 -22
- package/packages/datadog-plugin-http2/src/index.js +8 -26
- package/packages/datadog-plugin-jest/src/index.js +3 -0
- package/packages/datadog-plugin-kafkajs/src/consumer.js +42 -0
- package/packages/datadog-plugin-kafkajs/src/index.js +11 -87
- package/packages/datadog-plugin-kafkajs/src/producer.js +31 -0
- package/packages/datadog-plugin-mocha/src/index.js +2 -2
- package/packages/datadog-plugin-moleculer/src/client.js +22 -36
- package/packages/datadog-plugin-moleculer/src/index.js +8 -26
- package/packages/datadog-plugin-moleculer/src/server.js +18 -30
- package/packages/datadog-plugin-net/src/ipc.js +21 -0
- package/packages/datadog-plugin-net/src/tcp.js +46 -0
- package/packages/datadog-plugin-opensearch/src/index.js +11 -0
- package/packages/datadog-plugin-pg/src/index.js +2 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +55 -0
- package/packages/datadog-plugin-rhea/src/index.js +11 -99
- package/packages/datadog-plugin-rhea/src/producer.js +45 -0
- package/packages/datadog-plugin-sharedb/src/index.js +22 -39
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/index.js +4 -6
- package/packages/dd-trace/src/appsec/iast/path-line.js +3 -0
- package/packages/dd-trace/src/appsec/recommended.json +60 -46
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -5
- package/packages/dd-trace/src/config.js +31 -6
- package/packages/dd-trace/src/constants.js +3 -0
- package/packages/dd-trace/src/dogstatsd.js +42 -10
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +10 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +2 -9
- package/packages/dd-trace/src/exporters/common/request.js +12 -0
- package/packages/dd-trace/src/format.js +13 -0
- package/packages/dd-trace/src/metrics.js +10 -2
- package/packages/dd-trace/src/plugin_manager.js +6 -1
- package/packages/dd-trace/src/plugins/client.js +3 -1
- package/packages/dd-trace/src/plugins/composite.js +26 -0
- package/packages/dd-trace/src/plugins/consumer.js +9 -0
- package/packages/dd-trace/src/plugins/incoming.js +7 -0
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/outgoing.js +1 -1
- package/packages/dd-trace/src/plugins/producer.js +9 -0
- package/packages/dd-trace/src/plugins/server.js +9 -0
- package/packages/dd-trace/src/plugins/storage.js +0 -4
- package/packages/dd-trace/src/plugins/tracing.js +10 -9
- package/packages/dd-trace/src/plugins/util/web.js +49 -3
- package/packages/dd-trace/src/profiling/profiler.js +8 -1
- package/packages/dd-trace/src/span_processor.js +3 -0
- package/packages/dd-trace/src/span_sampler.js +80 -0
- package/packages/dd-trace/src/tracer.js +6 -2
- package/packages/dd-trace/src/util.js +43 -1
|
@@ -1,48 +1,31 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const store = storage.getStore()
|
|
16
|
-
const childOf = store ? store.span : store
|
|
17
|
-
const span = this.tracer.startSpan('sharedb.request', {
|
|
18
|
-
childOf,
|
|
19
|
-
tags: {
|
|
20
|
-
'service.name': this.config.service || this.tracer._service,
|
|
21
|
-
'span.kind': 'server',
|
|
22
|
-
'sharedb.action': actionName,
|
|
23
|
-
'resource.name': getReadableResourceName(actionName, request.c, request.q)
|
|
24
|
-
}
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
if (this.config.hooks && this.config.hooks.receive) {
|
|
28
|
-
this.config.hooks.receive(span, request)
|
|
3
|
+
const ServerPlugin = require('../../dd-trace/src/plugins/server')
|
|
4
|
+
|
|
5
|
+
class SharedbPlugin extends ServerPlugin {
|
|
6
|
+
static get name () { return 'sharedb' }
|
|
7
|
+
|
|
8
|
+
start ({ actionName, request }) {
|
|
9
|
+
const span = this.startSpan('sharedb.request', {
|
|
10
|
+
service: this.config.service,
|
|
11
|
+
resource: getReadableResourceName(actionName, request.c, request.q),
|
|
12
|
+
kind: 'server',
|
|
13
|
+
meta: {
|
|
14
|
+
'sharedb.action': actionName
|
|
29
15
|
}
|
|
30
|
-
|
|
31
|
-
this.enter(span, store)
|
|
32
16
|
})
|
|
33
17
|
|
|
34
|
-
this.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
18
|
+
if (this.config.hooks && this.config.hooks.receive) {
|
|
19
|
+
this.config.hooks.receive(span, request)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
38
22
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
})
|
|
23
|
+
finish ({ request, res }) {
|
|
24
|
+
const span = this.activeSpan
|
|
25
|
+
if (this.config.hooks && this.config.hooks.reply) {
|
|
26
|
+
this.config.hooks.reply(span, request, res)
|
|
27
|
+
}
|
|
28
|
+
span.finish()
|
|
46
29
|
}
|
|
47
30
|
}
|
|
48
31
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const Plugin = require('../../../../src/plugins/plugin')
|
|
4
4
|
const { storage } = require('../../../../../datadog-core')
|
|
5
|
-
const { getFirstNonDDPathAndLine } = require('
|
|
5
|
+
const { getFirstNonDDPathAndLine } = require('../path-line')
|
|
6
6
|
const { createVulnerability, addVulnerability } = require('../vulnerability-reporter')
|
|
7
7
|
const { getIastContext } = require('../iast-context')
|
|
8
8
|
const overheadController = require('../overhead-controller')
|
|
@@ -4,8 +4,7 @@ const web = require('../../plugins/util/web')
|
|
|
4
4
|
const { storage } = require('../../../../datadog-core')
|
|
5
5
|
const overheadController = require('./overhead-controller')
|
|
6
6
|
const dc = require('diagnostics_channel')
|
|
7
|
-
const
|
|
8
|
-
|
|
7
|
+
const iastContextFunctions = require('./iast-context')
|
|
9
8
|
// TODO Change to `apm:http:server:request:[start|close]` when the subscription
|
|
10
9
|
// order of the callbacks can be enforce
|
|
11
10
|
const requestStart = dc.channel('dd-trace:incomingHttpRequestStart')
|
|
@@ -33,7 +32,7 @@ function onIncomingHttpRequestStart (data) {
|
|
|
33
32
|
const rootSpan = topContext.span
|
|
34
33
|
const isRequestAcquired = overheadController.acquireRequest(rootSpan)
|
|
35
34
|
if (isRequestAcquired) {
|
|
36
|
-
const iastContext = saveIastContext(store, topContext, { rootSpan, req: data.req })
|
|
35
|
+
const iastContext = iastContextFunctions.saveIastContext(store, topContext, { rootSpan, req: data.req })
|
|
37
36
|
overheadController.initializeRequestContext(iastContext)
|
|
38
37
|
}
|
|
39
38
|
}
|
|
@@ -44,13 +43,12 @@ function onIncomingHttpRequestStart (data) {
|
|
|
44
43
|
function onIncomingHttpRequestEnd (data) {
|
|
45
44
|
if (data && data.req) {
|
|
46
45
|
const store = storage.getStore()
|
|
47
|
-
const iastContext = getIastContext(storage.getStore())
|
|
46
|
+
const iastContext = iastContextFunctions.getIastContext(storage.getStore())
|
|
48
47
|
if (iastContext && iastContext.rootSpan) {
|
|
49
|
-
overheadController.releaseRequest()
|
|
50
48
|
sendVulnerabilities(iastContext, iastContext.rootSpan)
|
|
51
49
|
}
|
|
52
50
|
// TODO web.getContext(data.req) is required when the request is aborted
|
|
53
|
-
if (cleanIastContext(store, web.getContext(data.req), iastContext)) {
|
|
51
|
+
if (iastContextFunctions.cleanIastContext(store, web.getContext(data.req), iastContext)) {
|
|
54
52
|
overheadController.releaseRequest()
|
|
55
53
|
}
|
|
56
54
|
}
|
|
@@ -51,6 +51,9 @@ function getFirstNonDDPathAndLineFromCallsites (callsites) {
|
|
|
51
51
|
function isExcluded (callsite) {
|
|
52
52
|
if (callsite.isNative()) return true
|
|
53
53
|
const filename = callsite.getFileName()
|
|
54
|
+
if (!filename) {
|
|
55
|
+
return true
|
|
56
|
+
}
|
|
54
57
|
for (let i = 0; i < EXCLUDED_PATHS.length; i++) {
|
|
55
58
|
if (filename.indexOf(EXCLUDED_PATHS[i]) > -1) {
|
|
56
59
|
return true
|
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "2.2",
|
|
3
3
|
"metadata": {
|
|
4
|
-
"rules_version": "1.4.
|
|
4
|
+
"rules_version": "1.4.2"
|
|
5
5
|
},
|
|
6
6
|
"rules": [
|
|
7
|
+
{
|
|
8
|
+
"id": "blk-001-001",
|
|
9
|
+
"name": "Block IP Addresses",
|
|
10
|
+
"tags": {
|
|
11
|
+
"type": "block_ip",
|
|
12
|
+
"category": "security_response"
|
|
13
|
+
},
|
|
14
|
+
"conditions": [
|
|
15
|
+
{
|
|
16
|
+
"parameters": {
|
|
17
|
+
"inputs": [
|
|
18
|
+
{
|
|
19
|
+
"address": "http.client_ip"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"data": "blocked_ips"
|
|
23
|
+
},
|
|
24
|
+
"operator": "ip_match"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"transformers": [],
|
|
28
|
+
"on_match": [
|
|
29
|
+
"block"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
7
32
|
{
|
|
8
33
|
"id": "crs-913-110",
|
|
9
34
|
"name": "Acunetix",
|
|
@@ -2828,51 +2853,6 @@
|
|
|
2828
2853
|
],
|
|
2829
2854
|
"transformers": []
|
|
2830
2855
|
},
|
|
2831
|
-
{
|
|
2832
|
-
"id": "crs-941-100",
|
|
2833
|
-
"name": "XSS Attack Detected via libinjection",
|
|
2834
|
-
"tags": {
|
|
2835
|
-
"type": "xss",
|
|
2836
|
-
"crs_id": "941100",
|
|
2837
|
-
"category": "attack_attempt"
|
|
2838
|
-
},
|
|
2839
|
-
"conditions": [
|
|
2840
|
-
{
|
|
2841
|
-
"parameters": {
|
|
2842
|
-
"inputs": [
|
|
2843
|
-
{
|
|
2844
|
-
"address": "server.request.headers.no_cookies",
|
|
2845
|
-
"key_path": [
|
|
2846
|
-
"user-agent"
|
|
2847
|
-
]
|
|
2848
|
-
},
|
|
2849
|
-
{
|
|
2850
|
-
"address": "server.request.headers.no_cookies",
|
|
2851
|
-
"key_path": [
|
|
2852
|
-
"referer"
|
|
2853
|
-
]
|
|
2854
|
-
},
|
|
2855
|
-
{
|
|
2856
|
-
"address": "server.request.query"
|
|
2857
|
-
},
|
|
2858
|
-
{
|
|
2859
|
-
"address": "server.request.body"
|
|
2860
|
-
},
|
|
2861
|
-
{
|
|
2862
|
-
"address": "server.request.path_params"
|
|
2863
|
-
},
|
|
2864
|
-
{
|
|
2865
|
-
"address": "grpc.server.request.message"
|
|
2866
|
-
}
|
|
2867
|
-
]
|
|
2868
|
-
},
|
|
2869
|
-
"operator": "is_xss"
|
|
2870
|
-
}
|
|
2871
|
-
],
|
|
2872
|
-
"transformers": [
|
|
2873
|
-
"removeNulls"
|
|
2874
|
-
]
|
|
2875
|
-
},
|
|
2876
2856
|
{
|
|
2877
2857
|
"id": "crs-941-110",
|
|
2878
2858
|
"name": "XSS Filter - Category 1: Script Tag Vector",
|
|
@@ -4338,6 +4318,40 @@
|
|
|
4338
4318
|
"keys_only"
|
|
4339
4319
|
]
|
|
4340
4320
|
},
|
|
4321
|
+
{
|
|
4322
|
+
"id": "dog-000-007",
|
|
4323
|
+
"name": "Server side template injection: Velocity & Freemarker",
|
|
4324
|
+
"tags": {
|
|
4325
|
+
"type": "java_code_injection",
|
|
4326
|
+
"category": "attack_attempt"
|
|
4327
|
+
},
|
|
4328
|
+
"conditions": [
|
|
4329
|
+
{
|
|
4330
|
+
"parameters": {
|
|
4331
|
+
"inputs": [
|
|
4332
|
+
{
|
|
4333
|
+
"address": "server.request.query"
|
|
4334
|
+
},
|
|
4335
|
+
{
|
|
4336
|
+
"address": "server.request.body"
|
|
4337
|
+
},
|
|
4338
|
+
{
|
|
4339
|
+
"address": "server.request.path_params"
|
|
4340
|
+
},
|
|
4341
|
+
{
|
|
4342
|
+
"address": "server.request.headers.no_cookies"
|
|
4343
|
+
},
|
|
4344
|
+
{
|
|
4345
|
+
"address": "grpc.server.request.message"
|
|
4346
|
+
}
|
|
4347
|
+
],
|
|
4348
|
+
"regex": "#(?:set|foreach|macro|parse|if)\\(.*\\)|<#assign.*>"
|
|
4349
|
+
},
|
|
4350
|
+
"operator": "match_regex"
|
|
4351
|
+
}
|
|
4352
|
+
],
|
|
4353
|
+
"transformers": []
|
|
4354
|
+
},
|
|
4341
4355
|
{
|
|
4342
4356
|
"id": "nfd-000-001",
|
|
4343
4357
|
"name": "Detect common directory discovery scans",
|
|
@@ -26,13 +26,10 @@ class Writer extends BaseWriter {
|
|
|
26
26
|
'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY,
|
|
27
27
|
...form.getHeaders()
|
|
28
28
|
},
|
|
29
|
-
timeout: 15000
|
|
29
|
+
timeout: 15000,
|
|
30
|
+
url: this._url
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
options.protocol = this._url.protocol
|
|
33
|
-
options.hostname = this._url.hostname
|
|
34
|
-
options.port = this._url.port
|
|
35
|
-
|
|
36
33
|
log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
|
|
37
34
|
|
|
38
35
|
request(form, options, (err, res) => {
|
|
@@ -27,13 +27,10 @@ class Writer extends BaseWriter {
|
|
|
27
27
|
'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY,
|
|
28
28
|
'Content-Type': 'application/msgpack'
|
|
29
29
|
},
|
|
30
|
-
timeout: 15000
|
|
30
|
+
timeout: 15000,
|
|
31
|
+
url: this._url
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
options.protocol = this._url.protocol
|
|
34
|
-
options.hostname = this._url.hostname
|
|
35
|
-
options.port = this._url.port
|
|
36
|
-
|
|
37
34
|
log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
|
|
38
35
|
request(data, options, (err, res) => {
|
|
39
36
|
if (err) {
|
|
@@ -13,6 +13,15 @@ const uuid = require('crypto-randomuuid')
|
|
|
13
13
|
const fromEntries = Object.fromEntries || (entries =>
|
|
14
14
|
entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {}))
|
|
15
15
|
|
|
16
|
+
function maybeFile (filepath) {
|
|
17
|
+
if (!filepath) return
|
|
18
|
+
try {
|
|
19
|
+
return fs.readFileSync(filepath, 'utf8')
|
|
20
|
+
} catch (e) {
|
|
21
|
+
return undefined
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
16
25
|
function safeJsonParse (input) {
|
|
17
26
|
try {
|
|
18
27
|
return JSON.parse(input)
|
|
@@ -133,14 +142,14 @@ class Config {
|
|
|
133
142
|
parseInt(process.env.DD_TRACE_PARTIAL_FLUSH_MIN_SPANS),
|
|
134
143
|
1000
|
|
135
144
|
)
|
|
136
|
-
const DD_TRACE_CLIENT_IP_HEADER_DISABLED = coalesce(
|
|
137
|
-
process.env.DD_TRACE_CLIENT_IP_HEADER_DISABLED,
|
|
138
|
-
false
|
|
139
|
-
)
|
|
140
145
|
const DD_TRACE_CLIENT_IP_HEADER = coalesce(
|
|
141
146
|
process.env.DD_TRACE_CLIENT_IP_HEADER,
|
|
142
147
|
null
|
|
143
148
|
)
|
|
149
|
+
const DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP = coalesce(
|
|
150
|
+
process.env.DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP,
|
|
151
|
+
'.*'
|
|
152
|
+
)
|
|
144
153
|
const DD_TRACE_B3_ENABLED = coalesce(
|
|
145
154
|
options.experimental && options.experimental.b3,
|
|
146
155
|
process.env.DD_TRACE_EXPERIMENTAL_B3_ENABLED,
|
|
@@ -260,10 +269,25 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
260
269
|
ingestion.sampleRate
|
|
261
270
|
),
|
|
262
271
|
rateLimit: coalesce(options.rateLimit, process.env.DD_TRACE_RATE_LIMIT, ingestion.rateLimit),
|
|
263
|
-
rules: coalesce(
|
|
272
|
+
rules: coalesce(
|
|
273
|
+
options.samplingRules,
|
|
274
|
+
safeJsonParse(process.env.DD_TRACE_SAMPLING_RULES),
|
|
275
|
+
[]
|
|
276
|
+
).map(rule => {
|
|
264
277
|
return remapify(rule, {
|
|
265
278
|
sample_rate: 'sampleRate'
|
|
266
279
|
})
|
|
280
|
+
}),
|
|
281
|
+
spanSamplingRules: coalesce(
|
|
282
|
+
options.spanSamplingRules,
|
|
283
|
+
safeJsonParse(maybeFile(process.env.DD_SPAN_SAMPLING_RULES_FILE)),
|
|
284
|
+
safeJsonParse(process.env.DD_SPAN_SAMPLING_RULES),
|
|
285
|
+
[]
|
|
286
|
+
).map(rule => {
|
|
287
|
+
return remapify(rule, {
|
|
288
|
+
sample_rate: 'sampleRate',
|
|
289
|
+
max_per_second: 'maxPerSecond'
|
|
290
|
+
})
|
|
267
291
|
})
|
|
268
292
|
}
|
|
269
293
|
|
|
@@ -282,8 +306,9 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
282
306
|
this.flushInterval = coalesce(parseInt(options.flushInterval, 10), defaultFlushInterval)
|
|
283
307
|
this.flushMinSpans = DD_TRACE_PARTIAL_FLUSH_MIN_SPANS
|
|
284
308
|
this.sampleRate = coalesce(Math.min(Math.max(sampler.sampleRate, 0), 1), 1)
|
|
285
|
-
this.clientIpHeaderDisabled = isTrue(
|
|
309
|
+
this.clientIpHeaderDisabled = !isTrue(DD_APPSEC_ENABLED)
|
|
286
310
|
this.clientIpHeader = DD_TRACE_CLIENT_IP_HEADER
|
|
311
|
+
this.queryStringObfuscation = DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP
|
|
287
312
|
this.logger = options.logger
|
|
288
313
|
this.plugins = !!coalesce(options.plugins, true)
|
|
289
314
|
this.service = DD_SERVICE
|
|
@@ -15,6 +15,9 @@ module.exports = {
|
|
|
15
15
|
SAMPLING_MECHANISM_MANUAL: 4,
|
|
16
16
|
SAMPLING_MECHANISM_APPSEC: 5,
|
|
17
17
|
SAMPLING_MECHANISM_SPAN: 8,
|
|
18
|
+
SPAN_SAMPLING_MECHANISM: '_dd.span_sampling.mechanism',
|
|
19
|
+
SPAN_SAMPLING_RULE_RATE: '_dd.span_sampling.rule_rate',
|
|
20
|
+
SPAN_SAMPLING_MAX_PER_SECOND: '_dd.span_sampling.max_per_second',
|
|
18
21
|
DATADOG_LAMBDA_EXTENSION_PATH: '/opt/extensions/datadog-agent',
|
|
19
22
|
DECISION_MAKER_KEY: '_dd.p.dm'
|
|
20
23
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const lookup = require('dns').lookup // cache to avoid instrumentation
|
|
4
|
+
const request = require('./exporters/common/request')
|
|
4
5
|
const dgram = require('dgram')
|
|
5
6
|
const isIP = require('net').isIP
|
|
6
7
|
const log = require('./log')
|
|
@@ -11,6 +12,13 @@ class Client {
|
|
|
11
12
|
constructor (options) {
|
|
12
13
|
options = options || {}
|
|
13
14
|
|
|
15
|
+
if (options.metricsProxyUrl) {
|
|
16
|
+
this._httpOptions = {
|
|
17
|
+
url: options.metricsProxyUrl.toString(),
|
|
18
|
+
path: '/dogstatsd/v2/proxy'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
this._host = options.host || 'localhost'
|
|
15
23
|
this._family = isIP(this._host)
|
|
16
24
|
this._port = options.port || 8125
|
|
@@ -38,26 +46,50 @@ class Client {
|
|
|
38
46
|
|
|
39
47
|
this._queue = []
|
|
40
48
|
|
|
49
|
+
if (this._httpOptions) {
|
|
50
|
+
this._sendHttp(queue)
|
|
51
|
+
} else {
|
|
52
|
+
this._sendUdp(queue)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_sendHttp (queue) {
|
|
57
|
+
const buffer = Buffer.concat(queue)
|
|
58
|
+
request(buffer, this._httpOptions, (err) => {
|
|
59
|
+
if (err) {
|
|
60
|
+
log.error('HTTP error from agent: ' + err.stack)
|
|
61
|
+
if (err.status) {
|
|
62
|
+
// Inside this if-block, we have connectivity to the agent, but
|
|
63
|
+
// we're not getting a 200 from the proxy endpoint. If it's a 404,
|
|
64
|
+
// then we know we'll never have the endpoint, so just clear out the
|
|
65
|
+
// options. Either way, we can give UDP a try.
|
|
66
|
+
if (err.status === 404) {
|
|
67
|
+
this._httpOptions = null
|
|
68
|
+
}
|
|
69
|
+
this._sendUdp(queue)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
_sendUdp (queue) {
|
|
41
76
|
if (this._family !== 0) {
|
|
42
|
-
this.
|
|
77
|
+
this._sendUdpFromQueue(queue, this._host, this._family)
|
|
43
78
|
} else {
|
|
44
79
|
lookup(this._host, (err, address, family) => {
|
|
45
80
|
if (err) return log.error(err)
|
|
46
|
-
this.
|
|
81
|
+
this._sendUdpFromQueue(queue, address, family)
|
|
47
82
|
})
|
|
48
83
|
}
|
|
49
84
|
}
|
|
50
85
|
|
|
51
|
-
|
|
86
|
+
_sendUdpFromQueue (queue, address, family) {
|
|
52
87
|
const socket = family === 6 ? this._udp6 : this._udp4
|
|
53
88
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
_sendAll (queue, address, family) {
|
|
60
|
-
queue.forEach((buffer) => this._send(address, family, buffer))
|
|
89
|
+
queue.forEach((buffer) => {
|
|
90
|
+
log.debug(`Sending to DogStatsD: ${buffer}`)
|
|
91
|
+
socket.send(buffer, 0, buffer.length, this._port, address)
|
|
92
|
+
})
|
|
61
93
|
}
|
|
62
94
|
|
|
63
95
|
_add (stat, value, type, tags) {
|
|
@@ -197,8 +197,16 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
_encode (bytes, trace) {
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
const rawEvents = trace.map(formatSpan)
|
|
201
|
+
|
|
202
|
+
const testSessionEvents = rawEvents.filter(
|
|
203
|
+
event => event.type === 'test_session_end' || event.type === 'test_suite_end'
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
const isTestSessionTrace = !!testSessionEvents.length
|
|
207
|
+
const events = isTestSessionTrace ? testSessionEvents : rawEvents
|
|
208
|
+
|
|
209
|
+
this._eventCount += events.length
|
|
202
210
|
|
|
203
211
|
for (const event of events) {
|
|
204
212
|
this._encodeEvent(bytes, event)
|
|
@@ -85,21 +85,14 @@ function makeRequest (version, data, count, url, headers, lookup, needsStartupLo
|
|
|
85
85
|
'Datadog-Meta-Tracer-Version': tracerVersion,
|
|
86
86
|
'X-Datadog-Trace-Count': String(count)
|
|
87
87
|
},
|
|
88
|
-
lookup
|
|
88
|
+
lookup,
|
|
89
|
+
url
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
setHeader(options.headers, 'Datadog-Meta-Lang', 'nodejs')
|
|
92
93
|
setHeader(options.headers, 'Datadog-Meta-Lang-Version', process.version)
|
|
93
94
|
setHeader(options.headers, 'Datadog-Meta-Lang-Interpreter', process.jsEngine || 'v8')
|
|
94
95
|
|
|
95
|
-
if (url.protocol === 'unix:') {
|
|
96
|
-
options.socketPath = url.pathname
|
|
97
|
-
} else {
|
|
98
|
-
options.protocol = url.protocol
|
|
99
|
-
options.hostname = url.hostname
|
|
100
|
-
options.port = url.port
|
|
101
|
-
}
|
|
102
|
-
|
|
103
96
|
log.debug(() => `Request to the agent: ${JSON.stringify(options)}`)
|
|
104
97
|
|
|
105
98
|
request(data, options, (err, res, status) => {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
const { Readable } = require('stream')
|
|
7
7
|
const http = require('http')
|
|
8
8
|
const https = require('https')
|
|
9
|
+
const { parse: urlParse } = require('url')
|
|
9
10
|
const docker = require('./docker')
|
|
10
11
|
const { storage } = require('../../../../datadog-core')
|
|
11
12
|
const log = require('../../log')
|
|
@@ -24,6 +25,17 @@ function request (data, options, callback) {
|
|
|
24
25
|
options.headers = {}
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
if (options.url) {
|
|
29
|
+
const url = typeof options.url === 'object' ? options.url : urlParse(options.url)
|
|
30
|
+
if (url.protocol === 'unix:') {
|
|
31
|
+
options.socketPath = url.pathname
|
|
32
|
+
} else {
|
|
33
|
+
options.protocol = url.protocol
|
|
34
|
+
options.hostname = url.hostname
|
|
35
|
+
options.port = url.port
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
27
39
|
const isReadable = data instanceof Readable
|
|
28
40
|
|
|
29
41
|
// The timeout should be kept low to avoid excessive queueing.
|
|
@@ -9,6 +9,10 @@ const SAMPLING_PRIORITY_KEY = constants.SAMPLING_PRIORITY_KEY
|
|
|
9
9
|
const SAMPLING_RULE_DECISION = constants.SAMPLING_RULE_DECISION
|
|
10
10
|
const SAMPLING_LIMIT_DECISION = constants.SAMPLING_LIMIT_DECISION
|
|
11
11
|
const SAMPLING_AGENT_DECISION = constants.SAMPLING_AGENT_DECISION
|
|
12
|
+
const SPAN_SAMPLING_MECHANISM = constants.SPAN_SAMPLING_MECHANISM
|
|
13
|
+
const SPAN_SAMPLING_RULE_RATE = constants.SPAN_SAMPLING_RULE_RATE
|
|
14
|
+
const SPAN_SAMPLING_MAX_PER_SECOND = constants.SPAN_SAMPLING_MAX_PER_SECOND
|
|
15
|
+
const SAMPLING_MECHANISM_SPAN = constants.SAMPLING_MECHANISM_SPAN
|
|
12
16
|
const MEASURED = tags.MEASURED
|
|
13
17
|
const ORIGIN_KEY = constants.ORIGIN_KEY
|
|
14
18
|
const HOSTNAME_KEY = constants.HOSTNAME_KEY
|
|
@@ -47,6 +51,13 @@ function formatSpan (span) {
|
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
53
|
|
|
54
|
+
function setSingleSpanIngestionTags (span, options) {
|
|
55
|
+
if (!options) return
|
|
56
|
+
addTag({}, span.metrics, SPAN_SAMPLING_MECHANISM, SAMPLING_MECHANISM_SPAN)
|
|
57
|
+
addTag({}, span.metrics, SPAN_SAMPLING_RULE_RATE, options.sampleRate)
|
|
58
|
+
addTag({}, span.metrics, SPAN_SAMPLING_MAX_PER_SECOND, options.maxPerSecond)
|
|
59
|
+
}
|
|
60
|
+
|
|
50
61
|
function extractTags (trace, span) {
|
|
51
62
|
const context = span.context()
|
|
52
63
|
const origin = context._trace.origin
|
|
@@ -96,6 +107,8 @@ function extractTags (trace, span) {
|
|
|
96
107
|
addTag(trace.meta, trace.metrics, 'language', 'javascript')
|
|
97
108
|
}
|
|
98
109
|
|
|
110
|
+
setSingleSpanIngestionTags(trace, context._sampling.spanSampling)
|
|
111
|
+
|
|
99
112
|
addTag(trace.meta, trace.metrics, SAMPLING_PRIORITY_KEY, priority)
|
|
100
113
|
addTag(trace.meta, trace.metrics, ORIGIN_KEY, origin)
|
|
101
114
|
addTag(trace.meta, trace.metrics, HOSTNAME_KEY, hostname)
|
|
@@ -48,11 +48,19 @@ module.exports = {
|
|
|
48
48
|
nativeMetrics = null
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
const clientConfig = {
|
|
52
52
|
host: config.dogstatsd.hostname,
|
|
53
53
|
port: config.dogstatsd.port,
|
|
54
54
|
tags
|
|
55
|
-
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (config.url) {
|
|
58
|
+
clientConfig.metricsProxyUrl = config.url
|
|
59
|
+
} else if (config.port) {
|
|
60
|
+
clientConfig.metricsProxyUrl = new URL(`http://${config.hostname || 'localhost'}:${config.port}`)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
client = new Client(clientConfig)
|
|
56
64
|
|
|
57
65
|
time = process.hrtime()
|
|
58
66
|
|
|
@@ -123,7 +123,8 @@ module.exports = class PluginManager {
|
|
|
123
123
|
clientIpHeader,
|
|
124
124
|
isIntelligentTestRunnerEnabled,
|
|
125
125
|
site,
|
|
126
|
-
experimental
|
|
126
|
+
experimental,
|
|
127
|
+
queryStringObfuscation
|
|
127
128
|
} = this._tracerConfig
|
|
128
129
|
|
|
129
130
|
const sharedConfig = {}
|
|
@@ -132,6 +133,10 @@ module.exports = class PluginManager {
|
|
|
132
133
|
sharedConfig.logInjection = logInjection
|
|
133
134
|
}
|
|
134
135
|
|
|
136
|
+
if (queryStringObfuscation !== undefined) {
|
|
137
|
+
sharedConfig.queryStringObfuscation = queryStringObfuscation
|
|
138
|
+
}
|
|
139
|
+
|
|
135
140
|
if (clientIpHeaderDisabled !== undefined) {
|
|
136
141
|
sharedConfig.clientIpHeaderDisabled = clientIpHeaderDisabled
|
|
137
142
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const Plugin = require('./plugin')
|
|
4
|
+
|
|
5
|
+
class CompositePlugin extends Plugin {
|
|
6
|
+
constructor (...args) {
|
|
7
|
+
super(...args)
|
|
8
|
+
|
|
9
|
+
for (const [name, PluginClass] of Object.entries(this.constructor.plugins)) {
|
|
10
|
+
this[name] = new PluginClass(...args)
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
configure (config) {
|
|
15
|
+
for (const name in this.constructor.plugins) {
|
|
16
|
+
const pluginConfig = config[name] === false ? false : {
|
|
17
|
+
...config,
|
|
18
|
+
...config[name]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this[name].configure(pluginConfig)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
module.exports = CompositePlugin
|
|
@@ -10,6 +10,7 @@ module.exports = {
|
|
|
10
10
|
get '@jest/core' () { return require('../../../datadog-plugin-jest/src') },
|
|
11
11
|
get '@koa/router' () { return require('../../../datadog-plugin-koa/src') },
|
|
12
12
|
get '@node-redis/client' () { return require('../../../datadog-plugin-redis/src') },
|
|
13
|
+
get '@opensearch-project/opensearch' () { return require('../../../datadog-plugin-opensearch/src') },
|
|
13
14
|
get '@redis/client' () { return require('../../../datadog-plugin-redis/src') },
|
|
14
15
|
get 'amqp10' () { return require('../../../datadog-plugin-amqp10/src') },
|
|
15
16
|
get 'amqplib' () { return require('../../../datadog-plugin-amqplib/src') },
|