dd-trace 4.22.0 → 4.24.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/package.json +4 -4
- package/packages/datadog-instrumentations/src/child-process.js +4 -5
- package/packages/datadog-instrumentations/src/couchbase.js +5 -4
- package/packages/datadog-instrumentations/src/crypto.js +2 -1
- package/packages/datadog-instrumentations/src/dns.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +7 -2
- package/packages/datadog-instrumentations/src/helpers/instrument.js +8 -3
- package/packages/datadog-instrumentations/src/helpers/register.js +18 -2
- package/packages/datadog-instrumentations/src/http/client.js +2 -2
- package/packages/datadog-instrumentations/src/http/server.js +7 -4
- package/packages/datadog-instrumentations/src/http2/client.js +3 -1
- package/packages/datadog-instrumentations/src/http2/server.js +3 -1
- package/packages/datadog-instrumentations/src/jest.js +3 -1
- package/packages/datadog-instrumentations/src/net.js +10 -2
- package/packages/datadog-plugin-cucumber/src/index.js +34 -2
- package/packages/datadog-plugin-cypress/src/plugin.js +60 -8
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -0
- package/packages/datadog-plugin-jest/src/index.js +60 -6
- package/packages/datadog-plugin-jest/src/util.js +38 -16
- package/packages/datadog-plugin-mocha/src/index.js +32 -1
- package/packages/datadog-plugin-playwright/src/index.js +17 -1
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +5 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +4 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +36 -4
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +18 -1
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +26 -1
- package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
- package/packages/dd-trace/src/config.js +100 -59
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +14 -1
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
- package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
- package/packages/dd-trace/src/opentracing/tracer.js +2 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +44 -8
- package/packages/dd-trace/src/plugins/index.js +5 -0
- package/packages/dd-trace/src/plugins/util/exec.js +23 -2
- package/packages/dd-trace/src/plugins/util/git.js +94 -19
- package/packages/dd-trace/src/priority_sampler.js +30 -38
- package/packages/dd-trace/src/profiling/config.js +17 -2
- package/packages/dd-trace/src/profiling/exporters/agent.js +1 -0
- package/packages/dd-trace/src/profiling/exporters/file.js +2 -1
- package/packages/dd-trace/src/profiling/profiler.js +18 -14
- package/packages/dd-trace/src/profiling/profilers/events.js +11 -5
- package/packages/dd-trace/src/profiling/profilers/shared.js +7 -1
- package/packages/dd-trace/src/profiling/profilers/space.js +17 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +34 -21
- package/packages/dd-trace/src/sampling_rule.js +130 -0
- package/packages/dd-trace/src/span_sampler.js +6 -64
- package/packages/dd-trace/src/telemetry/index.js +43 -5
- package/packages/dd-trace/src/telemetry/send-data.js +35 -16
|
@@ -7,7 +7,7 @@ const { HTTP_METHOD, HTTP_ROUTE, RESOURCE_NAME, SPAN_TYPE } = require('../../../
|
|
|
7
7
|
const { WEB } = require('../../../../../ext/types')
|
|
8
8
|
const runtimeMetrics = require('../../runtime_metrics')
|
|
9
9
|
const telemetryMetrics = require('../../telemetry/metrics')
|
|
10
|
-
const { END_TIMESTAMP_LABEL, getThreadLabels } = require('./shared')
|
|
10
|
+
const { END_TIMESTAMP_LABEL, getNonJSThreadsLabels, getThreadLabels } = require('./shared')
|
|
11
11
|
|
|
12
12
|
const beforeCh = dc.channel('dd-trace:storage:before')
|
|
13
13
|
const enterCh = dc.channel('dd-trace:storage:enter')
|
|
@@ -78,13 +78,15 @@ class NativeWallProfiler {
|
|
|
78
78
|
this._codeHotspotsEnabled = !!options.codeHotspotsEnabled
|
|
79
79
|
this._endpointCollectionEnabled = !!options.endpointCollectionEnabled
|
|
80
80
|
this._timelineEnabled = !!options.timelineEnabled
|
|
81
|
+
this._cpuProfilingEnabled = !!options.cpuProfilingEnabled
|
|
81
82
|
// We need to capture span data into the sample context for either code hotspots
|
|
82
83
|
// or endpoint collection.
|
|
83
84
|
this._captureSpanData = this._codeHotspotsEnabled || this._endpointCollectionEnabled
|
|
84
85
|
// We need to run the pprof wall profiler with sample contexts if we're either
|
|
85
86
|
// capturing span data or timeline is enabled (so we need sample timestamps, and for now
|
|
86
|
-
// timestamps require the sample contexts feature in the pprof wall profiler
|
|
87
|
-
|
|
87
|
+
// timestamps require the sample contexts feature in the pprof wall profiler), or
|
|
88
|
+
// cpu profiling is enabled.
|
|
89
|
+
this._withContexts = this._captureSpanData || this._timelineEnabled || this._cpuProfilingEnabled
|
|
88
90
|
this._v8ProfilerBugWorkaroundEnabled = !!options.v8ProfilerBugWorkaroundEnabled
|
|
89
91
|
this._mapper = undefined
|
|
90
92
|
this._pprof = undefined
|
|
@@ -131,7 +133,8 @@ class NativeWallProfiler {
|
|
|
131
133
|
sourceMapper: this._mapper,
|
|
132
134
|
withContexts: this._withContexts,
|
|
133
135
|
lineNumbers: false,
|
|
134
|
-
workaroundV8Bug: this._v8ProfilerBugWorkaroundEnabled
|
|
136
|
+
workaroundV8Bug: this._v8ProfilerBugWorkaroundEnabled,
|
|
137
|
+
collectCpuTime: this._cpuProfilingEnabled
|
|
135
138
|
})
|
|
136
139
|
|
|
137
140
|
if (this._withContexts) {
|
|
@@ -220,22 +223,42 @@ class NativeWallProfiler {
|
|
|
220
223
|
|
|
221
224
|
_stop (restart) {
|
|
222
225
|
if (!this._started) return
|
|
226
|
+
|
|
223
227
|
if (this._captureSpanData) {
|
|
224
228
|
// update last sample context if needed
|
|
225
229
|
this._enter()
|
|
226
230
|
this._lastSampleCount = 0
|
|
227
231
|
}
|
|
228
232
|
const profile = this._pprof.time.stop(restart, this._generateLabels)
|
|
233
|
+
|
|
229
234
|
if (restart) {
|
|
230
235
|
const v8BugDetected = this._pprof.time.v8ProfilerStuckEventLoopDetected()
|
|
231
236
|
if (v8BugDetected !== 0) {
|
|
232
237
|
this._reportV8bug(v8BugDetected === 1)
|
|
233
238
|
}
|
|
239
|
+
} else {
|
|
240
|
+
if (this._captureSpanData) {
|
|
241
|
+
beforeCh.unsubscribe(this._enter)
|
|
242
|
+
enterCh.unsubscribe(this._enter)
|
|
243
|
+
spanFinishCh.unsubscribe(this._spanFinished)
|
|
244
|
+
this._profilerState = undefined
|
|
245
|
+
this._lastSpan = undefined
|
|
246
|
+
this._lastStartedSpans = undefined
|
|
247
|
+
this._lastWebTags = undefined
|
|
248
|
+
}
|
|
249
|
+
this._started = false
|
|
234
250
|
}
|
|
251
|
+
|
|
235
252
|
return profile
|
|
236
253
|
}
|
|
237
254
|
|
|
238
|
-
_generateLabels (context) {
|
|
255
|
+
_generateLabels ({ node, context }) {
|
|
256
|
+
// check for special node that represents CPU time all non-JS threads.
|
|
257
|
+
// In that case only return a special thread name label since we cannot associate any timestamp/span/endpoint to it.
|
|
258
|
+
if (node.name === this._pprof.time.constants.NON_JS_THREADS_FUNCTION_NAME) {
|
|
259
|
+
return getNonJSThreadsLabels()
|
|
260
|
+
}
|
|
261
|
+
|
|
239
262
|
if (context == null) {
|
|
240
263
|
// generateLabels is also called for samples without context.
|
|
241
264
|
// In that case just return thread labels.
|
|
@@ -267,8 +290,8 @@ class NativeWallProfiler {
|
|
|
267
290
|
return labels
|
|
268
291
|
}
|
|
269
292
|
|
|
270
|
-
profile () {
|
|
271
|
-
return this._stop(
|
|
293
|
+
profile (restart) {
|
|
294
|
+
return this._stop(restart)
|
|
272
295
|
}
|
|
273
296
|
|
|
274
297
|
encode (profile) {
|
|
@@ -276,21 +299,11 @@ class NativeWallProfiler {
|
|
|
276
299
|
}
|
|
277
300
|
|
|
278
301
|
stop () {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
const profile = this._stop(false)
|
|
282
|
-
if (this._captureSpanData) {
|
|
283
|
-
beforeCh.unsubscribe(this._enter)
|
|
284
|
-
enterCh.unsubscribe(this._enter)
|
|
285
|
-
spanFinishCh.unsubscribe(this._spanFinished)
|
|
286
|
-
this._profilerState = undefined
|
|
287
|
-
this._lastSpan = undefined
|
|
288
|
-
this._lastStartedSpans = undefined
|
|
289
|
-
this._lastWebTags = undefined
|
|
290
|
-
}
|
|
302
|
+
this._stop(false)
|
|
303
|
+
}
|
|
291
304
|
|
|
292
|
-
|
|
293
|
-
return
|
|
305
|
+
isStarted () {
|
|
306
|
+
return this._started
|
|
294
307
|
}
|
|
295
308
|
}
|
|
296
309
|
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { globMatch } = require('../src/util')
|
|
4
|
+
const RateLimiter = require('./rate_limiter')
|
|
5
|
+
const Sampler = require('./sampler')
|
|
6
|
+
|
|
7
|
+
class AlwaysMatcher {
|
|
8
|
+
match () {
|
|
9
|
+
return true
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
class GlobMatcher {
|
|
14
|
+
constructor (pattern, locator) {
|
|
15
|
+
this.pattern = pattern
|
|
16
|
+
this.locator = locator
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
match (span) {
|
|
20
|
+
const subject = this.locator(span)
|
|
21
|
+
if (!subject) return false
|
|
22
|
+
return globMatch(this.pattern, subject)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
class RegExpMatcher {
|
|
27
|
+
constructor (pattern, locator) {
|
|
28
|
+
this.pattern = pattern
|
|
29
|
+
this.locator = locator
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
match (span) {
|
|
33
|
+
const subject = this.locator(span)
|
|
34
|
+
if (!subject) return false
|
|
35
|
+
return this.pattern.test(subject)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function matcher (pattern, locator) {
|
|
40
|
+
if (pattern instanceof RegExp) {
|
|
41
|
+
return new RegExpMatcher(pattern, locator)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (typeof pattern === 'string' && pattern !== '*') {
|
|
45
|
+
return new GlobMatcher(pattern, locator)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return new AlwaysMatcher()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function makeTagLocator (tag) {
|
|
52
|
+
return (span) => span.context()._tags[tag]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function nameLocator (span) {
|
|
56
|
+
return span.context()._name
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function serviceLocator (span) {
|
|
60
|
+
const { _tags: tags } = span.context()
|
|
61
|
+
return tags.service ||
|
|
62
|
+
tags['service.name'] ||
|
|
63
|
+
span.tracer()._service
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
class SamplingRule {
|
|
67
|
+
constructor ({ name, service, resource, tags, sampleRate = 1.0, maxPerSecond } = {}) {
|
|
68
|
+
this.matchers = []
|
|
69
|
+
|
|
70
|
+
if (name) {
|
|
71
|
+
this.matchers.push(matcher(name, nameLocator))
|
|
72
|
+
}
|
|
73
|
+
if (service) {
|
|
74
|
+
this.matchers.push(matcher(service, serviceLocator))
|
|
75
|
+
}
|
|
76
|
+
if (resource) {
|
|
77
|
+
this.matchers.push(matcher(resource, makeTagLocator('resource.name')))
|
|
78
|
+
}
|
|
79
|
+
for (const [key, value] of Object.entries(tags || {})) {
|
|
80
|
+
this.matchers.push(matcher(value, makeTagLocator(key)))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this._sampler = new Sampler(sampleRate)
|
|
84
|
+
this._limiter = undefined
|
|
85
|
+
|
|
86
|
+
if (Number.isFinite(maxPerSecond)) {
|
|
87
|
+
this._limiter = new RateLimiter(maxPerSecond)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
static from (config) {
|
|
92
|
+
return new SamplingRule(config)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get sampleRate () {
|
|
96
|
+
return this._sampler.rate()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get effectiveRate () {
|
|
100
|
+
return this._limiter && this._limiter.effectiveRate()
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get maxPerSecond () {
|
|
104
|
+
return this._limiter && this._limiter._rateLimit
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
match (span) {
|
|
108
|
+
for (const matcher of this.matchers) {
|
|
109
|
+
if (!matcher.match(span)) {
|
|
110
|
+
return false
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return true
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
sample () {
|
|
118
|
+
if (!this._sampler.isSampled()) {
|
|
119
|
+
return false
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (this._limiter) {
|
|
123
|
+
return this._limiter.isAllowed()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return true
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module.exports = SamplingRule
|
|
@@ -1,67 +1,16 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
const { globMatch } = require('../src/util')
|
|
3
|
-
const { USER_KEEP, AUTO_KEEP } = require('../../../ext').priority
|
|
4
|
-
const RateLimiter = require('./rate_limiter')
|
|
5
|
-
const Sampler = require('./sampler')
|
|
6
|
-
|
|
7
|
-
class SpanSamplingRule {
|
|
8
|
-
constructor ({ service, name, sampleRate = 1.0, maxPerSecond } = {}) {
|
|
9
|
-
this.service = service
|
|
10
|
-
this.name = name
|
|
11
|
-
|
|
12
|
-
this._sampler = new Sampler(sampleRate)
|
|
13
|
-
this._limiter = undefined
|
|
14
|
-
|
|
15
|
-
if (Number.isFinite(maxPerSecond)) {
|
|
16
|
-
this._limiter = new RateLimiter(maxPerSecond)
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
get sampleRate () {
|
|
21
|
-
return this._sampler.rate()
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
get maxPerSecond () {
|
|
25
|
-
return this._limiter && this._limiter._rateLimit
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static from (config) {
|
|
29
|
-
return new SpanSamplingRule(config)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
match (service, name) {
|
|
33
|
-
if (this.service && !globMatch(this.service, service)) {
|
|
34
|
-
return false
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (this.name && !globMatch(this.name, name)) {
|
|
38
|
-
return false
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return true
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
sample () {
|
|
45
|
-
if (!this._sampler.isSampled()) {
|
|
46
|
-
return false
|
|
47
|
-
}
|
|
48
2
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return true
|
|
54
|
-
}
|
|
55
|
-
}
|
|
3
|
+
const { USER_KEEP, AUTO_KEEP } = require('../../../ext').priority
|
|
4
|
+
const SamplingRule = require('./sampling_rule')
|
|
56
5
|
|
|
57
6
|
class SpanSampler {
|
|
58
7
|
constructor ({ spanSamplingRules = [] } = {}) {
|
|
59
|
-
this._rules = spanSamplingRules.map(
|
|
8
|
+
this._rules = spanSamplingRules.map(SamplingRule.from)
|
|
60
9
|
}
|
|
61
10
|
|
|
62
|
-
findRule (
|
|
11
|
+
findRule (context) {
|
|
63
12
|
for (const rule of this._rules) {
|
|
64
|
-
if (rule.match(
|
|
13
|
+
if (rule.match(context)) {
|
|
65
14
|
return rule
|
|
66
15
|
}
|
|
67
16
|
}
|
|
@@ -73,14 +22,7 @@ class SpanSampler {
|
|
|
73
22
|
|
|
74
23
|
const { started } = spanContext._trace
|
|
75
24
|
for (const span of started) {
|
|
76
|
-
const
|
|
77
|
-
const tags = context._tags || {}
|
|
78
|
-
const name = context._name
|
|
79
|
-
const service = tags.service ||
|
|
80
|
-
tags['service.name'] ||
|
|
81
|
-
span.tracer()._service
|
|
82
|
-
|
|
83
|
-
const rule = this.findRule(service, name)
|
|
25
|
+
const rule = this.findRule(span)
|
|
84
26
|
if (rule && rule.sample()) {
|
|
85
27
|
span.context()._spanSampling = {
|
|
86
28
|
sampleRate: rule.sampleRate,
|
|
@@ -112,11 +112,26 @@ function flatten (input, result = [], prefix = [], traversedObjects = null) {
|
|
|
112
112
|
return result
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
function getInstallSignature (config) {
|
|
116
|
+
const { installSignature: sig } = config
|
|
117
|
+
if (sig && (sig.id || sig.time || sig.type)) {
|
|
118
|
+
return {
|
|
119
|
+
install_id: sig.id,
|
|
120
|
+
install_time: sig.time,
|
|
121
|
+
install_type: sig.type
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
115
126
|
function appStarted (config) {
|
|
116
127
|
const app = {
|
|
117
128
|
products: getProducts(config),
|
|
118
129
|
configuration: flatten(config)
|
|
119
130
|
}
|
|
131
|
+
const installSignature = getInstallSignature(config)
|
|
132
|
+
if (installSignature) {
|
|
133
|
+
app.install_signature = installSignature
|
|
134
|
+
}
|
|
120
135
|
// TODO: add app.error with correct error codes
|
|
121
136
|
// if (errors.agentError) {
|
|
122
137
|
// app.error = errors.agentError
|
|
@@ -129,6 +144,10 @@ function onBeforeExit () {
|
|
|
129
144
|
process.removeListener('beforeExit', onBeforeExit)
|
|
130
145
|
const { reqType, payload } = createPayload('app-closing')
|
|
131
146
|
sendData(config, application, host, reqType, payload)
|
|
147
|
+
// we flush before shutting down. Only in CI Visibility
|
|
148
|
+
if (config.isCiVisibility) {
|
|
149
|
+
metricsManager.send(config, application, host)
|
|
150
|
+
}
|
|
132
151
|
}
|
|
133
152
|
|
|
134
153
|
function createAppObject (config) {
|
|
@@ -286,11 +305,30 @@ function updateConfig (changes, config) {
|
|
|
286
305
|
const application = createAppObject(config)
|
|
287
306
|
const host = createHostObject()
|
|
288
307
|
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
308
|
+
const names = {
|
|
309
|
+
sampleRate: 'DD_TRACE_SAMPLE_RATE',
|
|
310
|
+
logInjection: 'DD_LOG_INJECTION',
|
|
311
|
+
headerTags: 'DD_TRACE_HEADER_TAGS',
|
|
312
|
+
tags: 'DD_TAGS'
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const configuration = []
|
|
316
|
+
|
|
317
|
+
for (const change of changes) {
|
|
318
|
+
if (!names.hasOwnProperty(change.name)) continue
|
|
319
|
+
|
|
320
|
+
const name = names[change.name]
|
|
321
|
+
const { origin, value } = change
|
|
322
|
+
const entry = { name, origin, value }
|
|
323
|
+
|
|
324
|
+
if (Array.isArray(value)) {
|
|
325
|
+
entry.value = value.join(',')
|
|
326
|
+
} else if (name === 'DD_TAGS') {
|
|
327
|
+
entry.value = Object.entries(value).map(([key, value]) => `${key}:${value}`)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
configuration.push(entry)
|
|
331
|
+
}
|
|
294
332
|
|
|
295
333
|
const { reqType, payload } = createPayload('app-client-configuration-change', { configuration })
|
|
296
334
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
const request = require('../exporters/common/request')
|
|
3
3
|
const log = require('../log')
|
|
4
|
+
|
|
4
5
|
let agentTelemetry = true
|
|
5
6
|
|
|
6
7
|
function getHeaders (config, application, reqType) {
|
|
@@ -15,9 +16,22 @@ function getHeaders (config, application, reqType) {
|
|
|
15
16
|
if (debug) {
|
|
16
17
|
headers['dd-telemetry-debug-enabled'] = 'true'
|
|
17
18
|
}
|
|
19
|
+
if (config.apiKey) {
|
|
20
|
+
headers['dd-api-key'] = config.apiKey
|
|
21
|
+
}
|
|
18
22
|
return headers
|
|
19
23
|
}
|
|
20
24
|
|
|
25
|
+
function getAgentlessTelemetryEndpoint (site) {
|
|
26
|
+
if (site === 'datad0g.com') { // staging
|
|
27
|
+
return 'https://all-http-intake.logs.datad0g.com'
|
|
28
|
+
}
|
|
29
|
+
if (site === 'datadoghq.eu') {
|
|
30
|
+
return 'https://instrumentation-telemetry-intake.eu1.datadoghq.com'
|
|
31
|
+
}
|
|
32
|
+
return `https://instrumentation-telemetry-intake.${site}`
|
|
33
|
+
}
|
|
34
|
+
|
|
21
35
|
let seqId = 0
|
|
22
36
|
|
|
23
37
|
function getPayload (payload) {
|
|
@@ -35,17 +49,33 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
|
|
|
35
49
|
const {
|
|
36
50
|
hostname,
|
|
37
51
|
port,
|
|
38
|
-
|
|
52
|
+
experimental,
|
|
53
|
+
isCiVisibility
|
|
39
54
|
} = config
|
|
40
55
|
|
|
56
|
+
let url = config.url
|
|
57
|
+
|
|
58
|
+
const isCiVisibilityAgentlessMode = isCiVisibility && experimental?.exporter === 'datadog'
|
|
59
|
+
|
|
60
|
+
if (isCiVisibilityAgentlessMode) {
|
|
61
|
+
try {
|
|
62
|
+
url = url || new URL(getAgentlessTelemetryEndpoint(config.site))
|
|
63
|
+
} catch (err) {
|
|
64
|
+
log.error(err)
|
|
65
|
+
// No point to do the request if the URL is invalid
|
|
66
|
+
return cb(err, { payload, reqType })
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
41
70
|
const options = {
|
|
42
71
|
url,
|
|
43
72
|
hostname,
|
|
44
73
|
port,
|
|
45
74
|
method: 'POST',
|
|
46
|
-
path: '/telemetry/proxy/api/v2/apmtelemetry',
|
|
75
|
+
path: isCiVisibilityAgentlessMode ? '/api/v2/apmtelemetry' : '/telemetry/proxy/api/v2/apmtelemetry',
|
|
47
76
|
headers: getHeaders(config, application, reqType)
|
|
48
77
|
}
|
|
78
|
+
|
|
49
79
|
const data = JSON.stringify({
|
|
50
80
|
api_version: 'v2',
|
|
51
81
|
naming_schema_version: config.spanAttributeSchema ? config.spanAttributeSchema : '',
|
|
@@ -65,24 +95,13 @@ function sendData (config, application, host, reqType, payload = {}, cb = () =>
|
|
|
65
95
|
agentTelemetry = false
|
|
66
96
|
}
|
|
67
97
|
// figure out which data center to send to
|
|
68
|
-
|
|
69
|
-
const dataCenters = [
|
|
70
|
-
'datadoghq.com',
|
|
71
|
-
'us3.datadoghq.com',
|
|
72
|
-
'us5.datadoghq.com',
|
|
73
|
-
'ap1.datadoghq.com',
|
|
74
|
-
'eu1.datadoghq.com'
|
|
75
|
-
]
|
|
76
|
-
if (config.site === 'datad0g.com') { // staging
|
|
77
|
-
backendUrl = 'https://all-http-intake.logs.datad0g.com/api/v2/apmtelemetry'
|
|
78
|
-
} else if (dataCenters.includes(config.site)) {
|
|
79
|
-
backendUrl = 'https://instrumentation-telemetry-intake.' + config.site + '/api/v2/apmtelemetry'
|
|
80
|
-
}
|
|
98
|
+
const backendUrl = getAgentlessTelemetryEndpoint(config.site)
|
|
81
99
|
const backendHeader = { ...options.headers, 'DD-API-KEY': process.env.DD_API_KEY }
|
|
82
100
|
const backendOptions = {
|
|
83
101
|
...options,
|
|
84
102
|
url: backendUrl,
|
|
85
|
-
headers: backendHeader
|
|
103
|
+
headers: backendHeader,
|
|
104
|
+
path: '/api/v2/apmtelemetry'
|
|
86
105
|
}
|
|
87
106
|
if (backendUrl) {
|
|
88
107
|
request(data, backendOptions, (error) => { log.error(error) })
|