dd-trace 4.10.0 → 4.11.1
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/package.json +2 -2
- package/packages/datadog-instrumentations/src/http2/client.js +2 -0
- package/packages/datadog-plugin-http/src/client.js +7 -6
- package/packages/datadog-plugin-pg/src/index.js +1 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +2 -0
- package/packages/dd-trace/src/appsec/remote_config/manager.js +9 -4
- package/packages/dd-trace/src/config.js +138 -16
- package/packages/dd-trace/src/noop/tracer.js +2 -0
- package/packages/dd-trace/src/plugin_manager.js +2 -0
- package/packages/dd-trace/src/plugins/database.js +12 -0
- package/packages/dd-trace/src/plugins/util/web.js +6 -4
- package/packages/dd-trace/src/priority_sampler.js +6 -3
- package/packages/dd-trace/src/proxy.js +18 -3
- package/packages/dd-trace/src/startup-log.js +1 -1
- package/packages/dd-trace/src/telemetry/index.js +31 -3
- package/packages/dd-trace/src/tracer.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.11.1",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"crypto-randomuuid": "^1.0.0",
|
|
78
78
|
"diagnostics_channel": "^1.1.0",
|
|
79
79
|
"ignore": "^5.2.4",
|
|
80
|
-
"import-in-the-middle": "^1.4.
|
|
80
|
+
"import-in-the-middle": "^1.4.2",
|
|
81
81
|
"int64-buffer": "^0.1.9",
|
|
82
82
|
"ipaddr.js": "^2.1.0",
|
|
83
83
|
"istanbul-lib-coverage": "3.2.0",
|
|
@@ -30,6 +30,8 @@ function createWrapEmit (ctx) {
|
|
|
30
30
|
function createWrapRequest (authority, options) {
|
|
31
31
|
return function wrapRequest (request) {
|
|
32
32
|
return function (headers) {
|
|
33
|
+
if (!startChannel.hasSubscribers) return request.apply(this, arguments)
|
|
34
|
+
|
|
33
35
|
const ctx = { headers, authority, options }
|
|
34
36
|
|
|
35
37
|
return startChannel.runStores(ctx, () => {
|
|
@@ -121,11 +121,11 @@ function addResponseHeaders (res, span, config) {
|
|
|
121
121
|
? Object.fromEntries(res.headers.entries())
|
|
122
122
|
: res.headers
|
|
123
123
|
|
|
124
|
-
config.headers.forEach(key => {
|
|
124
|
+
config.headers.forEach(([key, tag]) => {
|
|
125
125
|
const value = headers[key]
|
|
126
126
|
|
|
127
127
|
if (value) {
|
|
128
|
-
span.setTag(`${HTTP_RESPONSE_HEADERS}.${key}`, value)
|
|
128
|
+
span.setTag(tag || `${HTTP_RESPONSE_HEADERS}.${key}`, value)
|
|
129
129
|
}
|
|
130
130
|
})
|
|
131
131
|
}
|
|
@@ -135,11 +135,11 @@ function addRequestHeaders (req, span, config) {
|
|
|
135
135
|
? Object.fromEntries(req.headers.entries())
|
|
136
136
|
: req.headers || req.getHeaders()
|
|
137
137
|
|
|
138
|
-
config.headers.forEach(key => {
|
|
139
|
-
const value = headers[key]
|
|
138
|
+
config.headers.forEach(([key, tag]) => {
|
|
139
|
+
const value = Array.isArray(headers[key]) ? headers[key].toString() : headers[key]
|
|
140
140
|
|
|
141
141
|
if (value) {
|
|
142
|
-
span.setTag(`${HTTP_REQUEST_HEADERS}.${key}`,
|
|
142
|
+
span.setTag(tag || `${HTTP_REQUEST_HEADERS}.${key}`, value)
|
|
143
143
|
}
|
|
144
144
|
})
|
|
145
145
|
}
|
|
@@ -182,7 +182,8 @@ function getHeaders (config) {
|
|
|
182
182
|
|
|
183
183
|
return config.headers
|
|
184
184
|
.filter(key => typeof key === 'string')
|
|
185
|
-
.map(
|
|
185
|
+
.map(h => h.split(':'))
|
|
186
|
+
.map(([key, tag]) => [key.toLowerCase(), tag])
|
|
186
187
|
}
|
|
187
188
|
|
|
188
189
|
function getHooks (config) {
|
|
@@ -10,7 +10,7 @@ class PGPlugin extends DatabasePlugin {
|
|
|
10
10
|
|
|
11
11
|
start ({ params = {}, query, processId }) {
|
|
12
12
|
const service = this.serviceName({ pluginConfig: this.config, params })
|
|
13
|
-
const originalStatement = query.text
|
|
13
|
+
const originalStatement = this.maybeTruncate(query.text)
|
|
14
14
|
|
|
15
15
|
this.startSpan(this.operationName(), {
|
|
16
16
|
service,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { URL, format } = require('url')
|
|
3
4
|
const uuid = require('crypto-randomuuid')
|
|
4
5
|
const { EventEmitter } = require('events')
|
|
5
6
|
const Scheduler = require('./scheduler')
|
|
@@ -22,13 +23,17 @@ class RemoteConfigManager extends EventEmitter {
|
|
|
22
23
|
constructor (config) {
|
|
23
24
|
super()
|
|
24
25
|
|
|
25
|
-
const pollInterval = config.remoteConfig.pollInterval * 1000
|
|
26
|
+
const pollInterval = Math.floor(config.remoteConfig.pollInterval * 1000)
|
|
27
|
+
const url = config.url || new URL(format({
|
|
28
|
+
protocol: 'http:',
|
|
29
|
+
hostname: config.hostname || 'localhost',
|
|
30
|
+
port: config.port
|
|
31
|
+
}))
|
|
32
|
+
|
|
26
33
|
this.scheduler = new Scheduler((cb) => this.poll(cb), pollInterval)
|
|
27
34
|
|
|
28
35
|
this.requestOptions = {
|
|
29
|
-
url
|
|
30
|
-
hostname: config.hostname,
|
|
31
|
-
port: config.port,
|
|
36
|
+
url,
|
|
32
37
|
method: 'POST',
|
|
33
38
|
path: '/v0.7/config'
|
|
34
39
|
}
|
|
@@ -11,6 +11,7 @@ const tagger = require('./tagger')
|
|
|
11
11
|
const { isTrue, isFalse } = require('./util')
|
|
12
12
|
const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('./plugins/util/tags')
|
|
13
13
|
const { getGitMetadataFromGitProperties } = require('./git_properties')
|
|
14
|
+
const { updateConfig } = require('./telemetry')
|
|
14
15
|
const { getIsGCPFunction, getIsAzureFunctionConsumptionPlan } = require('./serverless')
|
|
15
16
|
|
|
16
17
|
const fromEntries = Object.fromEntries || (entries =>
|
|
@@ -130,11 +131,6 @@ class Config {
|
|
|
130
131
|
'agent'
|
|
131
132
|
)
|
|
132
133
|
const DD_PROFILING_SOURCE_MAP = process.env.DD_PROFILING_SOURCE_MAP
|
|
133
|
-
const DD_LOGS_INJECTION = coalesce(
|
|
134
|
-
options.logInjection,
|
|
135
|
-
process.env.DD_LOGS_INJECTION,
|
|
136
|
-
false
|
|
137
|
-
)
|
|
138
134
|
const DD_RUNTIME_METRICS_ENABLED = coalesce(
|
|
139
135
|
options.runtimeMetrics, // TODO: remove when enabled by default
|
|
140
136
|
process.env.DD_RUNTIME_METRICS_ENABLED,
|
|
@@ -239,7 +235,7 @@ class Config {
|
|
|
239
235
|
!inServerlessEnvironment
|
|
240
236
|
)
|
|
241
237
|
const DD_TELEMETRY_HEARTBEAT_INTERVAL = process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL
|
|
242
|
-
?
|
|
238
|
+
? Math.floor(parseFloat(process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL) * 1000)
|
|
243
239
|
: 60000
|
|
244
240
|
const DD_OPENAI_SPAN_CHAR_LIMIT = process.env.DD_OPENAI_SPAN_CHAR_LIMIT
|
|
245
241
|
? parseInt(process.env.DD_OPENAI_SPAN_CHAR_LIMIT)
|
|
@@ -441,8 +437,8 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
441
437
|
!inServerlessEnvironment
|
|
442
438
|
)
|
|
443
439
|
const DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS = coalesce(
|
|
444
|
-
|
|
445
|
-
|
|
440
|
+
parseFloat(remoteConfigOptions.pollInterval),
|
|
441
|
+
parseFloat(process.env.DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS),
|
|
446
442
|
5 // seconds
|
|
447
443
|
)
|
|
448
444
|
|
|
@@ -510,11 +506,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
510
506
|
const ingestion = options.ingestion || {}
|
|
511
507
|
const dogstatsd = coalesce(options.dogstatsd, {})
|
|
512
508
|
const sampler = {
|
|
513
|
-
sampleRate: coalesce(
|
|
514
|
-
options.sampleRate,
|
|
515
|
-
process.env.DD_TRACE_SAMPLE_RATE,
|
|
516
|
-
ingestion.sampleRate
|
|
517
|
-
),
|
|
518
509
|
rateLimit: coalesce(options.rateLimit, process.env.DD_TRACE_RATE_LIMIT, ingestion.rateLimit),
|
|
519
510
|
rules: coalesce(
|
|
520
511
|
options.samplingRules,
|
|
@@ -538,14 +529,13 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
538
529
|
})
|
|
539
530
|
}
|
|
540
531
|
|
|
541
|
-
const defaultFlushInterval =
|
|
532
|
+
const defaultFlushInterval = inAWSLambda ? 0 : 2000
|
|
542
533
|
|
|
543
534
|
this.tracing = !isFalse(DD_TRACING_ENABLED)
|
|
544
535
|
this.dbmPropagationMode = DD_DBM_PROPAGATION_MODE
|
|
545
536
|
this.dsmEnabled = isTrue(DD_DATA_STREAMS_ENABLED)
|
|
546
537
|
this.openAiLogsEnabled = DD_OPENAI_LOGS_ENABLED
|
|
547
538
|
this.apiKey = DD_API_KEY
|
|
548
|
-
this.logInjection = isTrue(DD_LOGS_INJECTION)
|
|
549
539
|
this.env = DD_ENV
|
|
550
540
|
this.url = DD_CIVISIBILITY_AGENTLESS_URL ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
|
|
551
541
|
: getAgentUrl(DD_TRACE_AGENT_URL, options)
|
|
@@ -554,7 +544,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
554
544
|
this.port = String(DD_TRACE_AGENT_PORT || (this.url && this.url.port))
|
|
555
545
|
this.flushInterval = coalesce(parseInt(options.flushInterval, 10), defaultFlushInterval)
|
|
556
546
|
this.flushMinSpans = DD_TRACE_PARTIAL_FLUSH_MIN_SPANS
|
|
557
|
-
this.sampleRate = coalesce(Math.min(Math.max(sampler.sampleRate, 0), 1), 1)
|
|
558
547
|
this.queryStringObfuscation = DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP
|
|
559
548
|
this.clientIpEnabled = DD_TRACE_CLIENT_IP_ENABLED
|
|
560
549
|
this.clientIpHeader = DD_TRACE_CLIENT_IP_HEADER
|
|
@@ -687,6 +676,139 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
687
676
|
version: this.version,
|
|
688
677
|
'runtime-id': uuid()
|
|
689
678
|
})
|
|
679
|
+
|
|
680
|
+
this._applyDefaults()
|
|
681
|
+
this._applyEnvironment()
|
|
682
|
+
this._applyOptions(options)
|
|
683
|
+
this._applyRemote({})
|
|
684
|
+
this._merge()
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// Supports only a subset of options for now.
|
|
688
|
+
configure (options, remote) {
|
|
689
|
+
if (remote) {
|
|
690
|
+
this._applyRemote(options)
|
|
691
|
+
} else {
|
|
692
|
+
this._applyOptions(options)
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
this._merge()
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
_applyDefaults () {
|
|
699
|
+
const defaults = this._defaults = {}
|
|
700
|
+
|
|
701
|
+
this._setUnit(defaults, 'sampleRate', undefined)
|
|
702
|
+
this._setBoolean(defaults, 'logInjection', false)
|
|
703
|
+
this._setArray(defaults, 'headerTags', [])
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
_applyEnvironment () {
|
|
707
|
+
const {
|
|
708
|
+
DD_TRACE_SAMPLE_RATE,
|
|
709
|
+
DD_LOGS_INJECTION,
|
|
710
|
+
DD_TRACE_HEADER_TAGS
|
|
711
|
+
} = process.env
|
|
712
|
+
|
|
713
|
+
const env = this._env = {}
|
|
714
|
+
|
|
715
|
+
this._setUnit(env, 'sampleRate', DD_TRACE_SAMPLE_RATE)
|
|
716
|
+
this._setBoolean(env, 'logInjection', DD_LOGS_INJECTION)
|
|
717
|
+
this._setArray(env, 'headerTags', DD_TRACE_HEADER_TAGS)
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
_applyOptions (options) {
|
|
721
|
+
const opts = this._options = this._options || {}
|
|
722
|
+
|
|
723
|
+
options = Object.assign({ ingestion: {} }, options, opts)
|
|
724
|
+
|
|
725
|
+
this._setUnit(opts, 'sampleRate', coalesce(options.sampleRate, options.ingestion.sampleRate))
|
|
726
|
+
this._setBoolean(opts, 'logInjection', options.logInjection)
|
|
727
|
+
this._setArray(opts, 'headerTags', options.headerTags)
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
_applyRemote (options) {
|
|
731
|
+
const opts = this._remote = this._remote || {}
|
|
732
|
+
const headerTags = options.tracing_header_tags
|
|
733
|
+
? options.tracing_header_tags.map(tag => {
|
|
734
|
+
return tag.tag_name ? `${tag.header}:${tag.tag_name}` : tag.header
|
|
735
|
+
})
|
|
736
|
+
: undefined
|
|
737
|
+
|
|
738
|
+
this._setUnit(opts, 'sampleRate', options.tracing_sampling_rate)
|
|
739
|
+
this._setBoolean(opts, 'logInjection', options.log_injection_enabled)
|
|
740
|
+
this._setArray(opts, 'headerTags', headerTags)
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
_setBoolean (obj, name, value) {
|
|
744
|
+
if (value === undefined || value === null) {
|
|
745
|
+
this._setValue(obj, name, value)
|
|
746
|
+
} else if (isTrue(value)) {
|
|
747
|
+
this._setValue(obj, name, true)
|
|
748
|
+
} else if (isFalse(value)) {
|
|
749
|
+
this._setValue(obj, name, false)
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
_setUnit (obj, name, value) {
|
|
754
|
+
if (value === null || value === undefined) {
|
|
755
|
+
return this._setValue(obj, name, value)
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
value = parseFloat(value)
|
|
759
|
+
|
|
760
|
+
if (!isNaN(value)) {
|
|
761
|
+
// TODO: Ignore out of range values instead of normalizing them.
|
|
762
|
+
this._setValue(obj, name, Math.min(Math.max(value, 0), 1))
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
_setArray (obj, name, value) {
|
|
767
|
+
if (value === null || value === undefined) {
|
|
768
|
+
return this._setValue(obj, name, null)
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (typeof value === 'string') {
|
|
772
|
+
value = value && value.split(',')
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
if (Array.isArray(value)) {
|
|
776
|
+
this._setValue(obj, name, value)
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
_setValue (obj, name, value) {
|
|
781
|
+
obj[name] = value
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// TODO: Report origin changes and errors to telemetry.
|
|
785
|
+
// TODO: Deeply merge configurations.
|
|
786
|
+
// TODO: Move change tracking to telemetry.
|
|
787
|
+
_merge () {
|
|
788
|
+
const containers = [this._remote, this._options, this._env, this._defaults]
|
|
789
|
+
const origins = ['remote_config', 'code', 'env_var', 'default']
|
|
790
|
+
const changes = []
|
|
791
|
+
|
|
792
|
+
for (const name in this._defaults) {
|
|
793
|
+
for (let i = 0; i < containers.length; i++) {
|
|
794
|
+
const container = containers[i]
|
|
795
|
+
const origin = origins[i]
|
|
796
|
+
|
|
797
|
+
if ((container[name] !== null && container[name] !== undefined) || container === this._defaults) {
|
|
798
|
+
if (this[name] === container[name] && this.hasOwnProperty(name)) break
|
|
799
|
+
|
|
800
|
+
const value = this[name] = container[name]
|
|
801
|
+
|
|
802
|
+
changes.push({ name, value, origin })
|
|
803
|
+
|
|
804
|
+
break
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
this.sampler.sampleRate = this.sampleRate
|
|
810
|
+
|
|
811
|
+
updateConfig(changes, this)
|
|
690
812
|
}
|
|
691
813
|
}
|
|
692
814
|
|
|
@@ -134,6 +134,7 @@ module.exports = class PluginManager {
|
|
|
134
134
|
queryStringObfuscation,
|
|
135
135
|
site,
|
|
136
136
|
url,
|
|
137
|
+
headerTags,
|
|
137
138
|
dbmPropagationMode,
|
|
138
139
|
dsmEnabled,
|
|
139
140
|
clientIpEnabled
|
|
@@ -162,6 +163,7 @@ module.exports = class PluginManager {
|
|
|
162
163
|
|
|
163
164
|
sharedConfig.site = site
|
|
164
165
|
sharedConfig.url = url
|
|
166
|
+
sharedConfig.headers = headerTags || []
|
|
165
167
|
|
|
166
168
|
return sharedConfig
|
|
167
169
|
}
|
|
@@ -55,6 +55,18 @@ class DatabasePlugin extends StoragePlugin {
|
|
|
55
55
|
return `/*${servicePropagation},traceparent='${traceparent}'*/ ${query}`
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
maybeTruncate (query) {
|
|
60
|
+
const maxLength = typeof this.config.truncate === 'number'
|
|
61
|
+
? this.config.truncate
|
|
62
|
+
: 5000 // same as what the agent does
|
|
63
|
+
|
|
64
|
+
if (this.config.truncate && query && query.length > maxLength) {
|
|
65
|
+
query = `${query.slice(0, maxLength - 3)}...`
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return query
|
|
69
|
+
}
|
|
58
70
|
}
|
|
59
71
|
|
|
60
72
|
module.exports = DatabasePlugin
|
|
@@ -477,16 +477,16 @@ function addResourceTag (context) {
|
|
|
477
477
|
function addHeaders (context) {
|
|
478
478
|
const { req, res, config, span } = context
|
|
479
479
|
|
|
480
|
-
config.headers.forEach(key => {
|
|
480
|
+
config.headers.forEach(([key, tag]) => {
|
|
481
481
|
const reqHeader = req.headers[key]
|
|
482
482
|
const resHeader = res.getHeader(key)
|
|
483
483
|
|
|
484
484
|
if (reqHeader) {
|
|
485
|
-
span.setTag(`${HTTP_REQUEST_HEADERS}.${key}`, reqHeader)
|
|
485
|
+
span.setTag(tag || `${HTTP_REQUEST_HEADERS}.${key}`, reqHeader)
|
|
486
486
|
}
|
|
487
487
|
|
|
488
488
|
if (resHeader) {
|
|
489
|
-
span.setTag(`${HTTP_RESPONSE_HEADERS}.${key}`, resHeader)
|
|
489
|
+
span.setTag(tag || `${HTTP_RESPONSE_HEADERS}.${key}`, resHeader)
|
|
490
490
|
}
|
|
491
491
|
})
|
|
492
492
|
}
|
|
@@ -512,7 +512,9 @@ function getProtocol (req) {
|
|
|
512
512
|
function getHeadersToRecord (config) {
|
|
513
513
|
if (Array.isArray(config.headers)) {
|
|
514
514
|
try {
|
|
515
|
-
return config.headers
|
|
515
|
+
return config.headers
|
|
516
|
+
.map(h => h.split(':'))
|
|
517
|
+
.map(([key, tag]) => [key.toLowerCase(), tag])
|
|
516
518
|
} catch (err) {
|
|
517
519
|
log.error(err)
|
|
518
520
|
}
|
|
@@ -29,14 +29,17 @@ const DEFAULT_KEY = 'service:,env:'
|
|
|
29
29
|
const defaultSampler = new Sampler(AUTO_KEEP)
|
|
30
30
|
|
|
31
31
|
class PrioritySampler {
|
|
32
|
-
constructor (env,
|
|
32
|
+
constructor (env, config) {
|
|
33
|
+
this.configure(env, config)
|
|
34
|
+
this.update({})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
configure (env, { sampleRate, rateLimit = 100, rules = [] } = {}) {
|
|
33
38
|
this._env = env
|
|
34
39
|
this._rules = this._normalizeRules(rules, sampleRate)
|
|
35
40
|
this._limiter = new RateLimiter(rateLimit)
|
|
36
41
|
|
|
37
42
|
setSamplingRules(this._rules)
|
|
38
|
-
|
|
39
|
-
this.update({})
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
isSampled (span) {
|
|
@@ -24,10 +24,23 @@ class Tracer extends NoopProxy {
|
|
|
24
24
|
this._initialized = true
|
|
25
25
|
|
|
26
26
|
try {
|
|
27
|
-
const config = new Config(options) // TODO: support dynamic config
|
|
27
|
+
const config = new Config(options) // TODO: support dynamic code config
|
|
28
28
|
|
|
29
29
|
if (config.remoteConfig.enabled && !config.isCiVisibility) {
|
|
30
|
-
remoteConfig.enable(config)
|
|
30
|
+
const rc = remoteConfig.enable(config)
|
|
31
|
+
|
|
32
|
+
rc.on('APM_TRACING', (action, conf) => {
|
|
33
|
+
if (action === 'unapply') {
|
|
34
|
+
config.configure({}, true)
|
|
35
|
+
} else {
|
|
36
|
+
config.configure(conf.lib_config, true)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (config.tracing) {
|
|
40
|
+
this._tracer.configure(config)
|
|
41
|
+
this._pluginManager.configure(config)
|
|
42
|
+
}
|
|
43
|
+
})
|
|
31
44
|
}
|
|
32
45
|
|
|
33
46
|
if (config.isGCPFunction || config.isAzureFunctionConsumptionPlan) {
|
|
@@ -49,6 +62,9 @@ class Tracer extends NoopProxy {
|
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
if (config.tracing) {
|
|
65
|
+
// TODO: This should probably not require tracing to be enabled.
|
|
66
|
+
telemetry.start(config, this._pluginManager)
|
|
67
|
+
|
|
52
68
|
// dirty require for now so zero appsec code is executed unless explicitly enabled
|
|
53
69
|
if (config.appsec.enabled) {
|
|
54
70
|
require('./appsec').enable(config)
|
|
@@ -63,7 +79,6 @@ class Tracer extends NoopProxy {
|
|
|
63
79
|
|
|
64
80
|
this._pluginManager.configure(config)
|
|
65
81
|
setStartupLogPluginManager(this._pluginManager)
|
|
66
|
-
telemetry.start(config, this._pluginManager)
|
|
67
82
|
|
|
68
83
|
if (config.isManualApiEnabled) {
|
|
69
84
|
const TestApiManualPlugin = require('./ci-visibility/test-api-manual/test-api-manual-plugin')
|
|
@@ -62,7 +62,7 @@ function startupLog ({ agentError } = {}) {
|
|
|
62
62
|
out.agent_error = agentError.message
|
|
63
63
|
}
|
|
64
64
|
out.debug = !!config.debug
|
|
65
|
-
out.sample_rate = config.sampleRate
|
|
65
|
+
out.sample_rate = config.sampler.sampleRate
|
|
66
66
|
out.sampling_rules = samplingRules
|
|
67
67
|
out.tags = config.tags
|
|
68
68
|
if (config.tags && config.tags.version) {
|
|
@@ -66,7 +66,7 @@ function onBeforeExit () {
|
|
|
66
66
|
sendData(config, application, host, 'app-closing')
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
function createAppObject () {
|
|
69
|
+
function createAppObject (config) {
|
|
70
70
|
return {
|
|
71
71
|
service_name: config.service,
|
|
72
72
|
env: config.env,
|
|
@@ -116,7 +116,7 @@ function start (aConfig, thePluginManager) {
|
|
|
116
116
|
}
|
|
117
117
|
config = aConfig
|
|
118
118
|
pluginManager = thePluginManager
|
|
119
|
-
application = createAppObject()
|
|
119
|
+
application = createAppObject(config)
|
|
120
120
|
host = createHostObject()
|
|
121
121
|
heartbeatInterval = config.telemetry.heartbeatInterval
|
|
122
122
|
|
|
@@ -155,8 +155,36 @@ function updateIntegrations () {
|
|
|
155
155
|
sendData(config, application, host, 'app-integrations-change', { integrations })
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
function updateConfig (changes, config) {
|
|
159
|
+
if (!config.telemetry.enabled) return
|
|
160
|
+
if (changes.length === 0) return
|
|
161
|
+
|
|
162
|
+
// Hack to make system tests happy until we ship telemetry v2
|
|
163
|
+
if (process.env.DD_INTERNAL_TELEMETRY_V2_ENABLED !== '1') return
|
|
164
|
+
|
|
165
|
+
const application = createAppObject(config)
|
|
166
|
+
const host = createHostObject()
|
|
167
|
+
|
|
168
|
+
const names = {
|
|
169
|
+
sampleRate: 'DD_TRACE_SAMPLE_RATE',
|
|
170
|
+
logInjection: 'DD_LOG_INJECTION',
|
|
171
|
+
headerTags: 'DD_TRACE_HEADER_TAGS'
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const configuration = changes.map(change => ({
|
|
175
|
+
name: names[change.name],
|
|
176
|
+
value: Array.isArray(change.value) ? change.value.join(',') : change.value,
|
|
177
|
+
origin: change.origin
|
|
178
|
+
}))
|
|
179
|
+
|
|
180
|
+
sendData(config, application, host, 'app-client-configuration-change', {
|
|
181
|
+
configuration
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
158
185
|
module.exports = {
|
|
159
186
|
start,
|
|
160
187
|
stop,
|
|
161
|
-
updateIntegrations
|
|
188
|
+
updateIntegrations,
|
|
189
|
+
updateConfig
|
|
162
190
|
}
|
|
@@ -25,6 +25,10 @@ class DatadogTracer extends Tracer {
|
|
|
25
25
|
setStartupLogConfig(config)
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
configure ({ env, sampler }) {
|
|
29
|
+
this._prioritySampler.configure(env, sampler)
|
|
30
|
+
}
|
|
31
|
+
|
|
28
32
|
// todo[piochelepiotr] These two methods are not related to the tracer, but to data streams monitoring.
|
|
29
33
|
// They should be moved outside of the tracer in the future.
|
|
30
34
|
setCheckpoint (edgeTags) {
|