dd-trace 4.18.0 → 4.22.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/LICENSE-3rdparty.csv +3 -2
- package/README.md +3 -3
- package/ext/kinds.d.ts +1 -0
- package/ext/kinds.js +2 -1
- package/ext/tags.d.ts +2 -1
- package/ext/tags.js +6 -1
- package/index.d.ts +29 -0
- package/package.json +11 -10
- package/packages/datadog-core/src/storage/async_resource.js +1 -1
- package/packages/datadog-esbuild/index.js +1 -20
- package/packages/datadog-instrumentations/src/aerospike.js +47 -0
- package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
- package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
- package/packages/datadog-instrumentations/src/graphql.js +18 -4
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/http/client.js +10 -0
- package/packages/datadog-instrumentations/src/jest.js +11 -5
- package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
- package/packages/datadog-instrumentations/src/next.js +18 -6
- package/packages/datadog-instrumentations/src/restify.js +14 -1
- package/packages/datadog-instrumentations/src/rhea.js +15 -9
- package/packages/datadog-plugin-aerospike/src/index.js +113 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +26 -18
- package/packages/datadog-plugin-http/src/client.js +19 -2
- package/packages/datadog-plugin-kafkajs/src/consumer.js +59 -6
- package/packages/datadog-plugin-kafkajs/src/producer.js +64 -6
- package/packages/datadog-plugin-next/src/index.js +40 -14
- package/packages/dd-trace/src/appsec/activation.js +29 -0
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +48 -0
- package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
- package/packages/dd-trace/src/appsec/blocking.js +95 -43
- package/packages/dd-trace/src/appsec/channels.js +5 -2
- package/packages/dd-trace/src/appsec/graphql.js +146 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
- package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +33 -32
- package/packages/dd-trace/src/appsec/recommended.json +1737 -120
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +36 -15
- package/packages/dd-trace/src/appsec/reporter.js +50 -34
- package/packages/dd-trace/src/appsec/rule_manager.js +9 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +17 -1
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +75 -56
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +22 -6
- package/packages/dd-trace/src/config.js +48 -7
- package/packages/dd-trace/src/datastreams/processor.js +166 -26
- package/packages/dd-trace/src/format.js +6 -1
- package/packages/dd-trace/src/id.js +12 -0
- package/packages/dd-trace/src/iitm.js +1 -1
- package/packages/dd-trace/src/log/channels.js +1 -1
- package/packages/dd-trace/src/noop/proxy.js +4 -0
- package/packages/dd-trace/src/opentelemetry/span.js +95 -2
- package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +14 -5
- package/packages/dd-trace/src/opentracing/span.js +6 -0
- package/packages/dd-trace/src/opentracing/span_context.js +5 -2
- package/packages/dd-trace/src/plugin_manager.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +2 -1
- package/packages/dd-trace/src/plugins/database.js +1 -1
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/util/ci.js +6 -19
- package/packages/dd-trace/src/plugins/util/git.js +4 -3
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
- package/packages/dd-trace/src/plugins/util/test.js +3 -2
- package/packages/dd-trace/src/plugins/util/url.js +26 -0
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
- package/packages/dd-trace/src/profiler.js +5 -3
- package/packages/dd-trace/src/profiling/config.js +26 -2
- package/packages/dd-trace/src/profiling/profiler.js +17 -10
- package/packages/dd-trace/src/profiling/profilers/events.js +264 -0
- package/packages/dd-trace/src/profiling/profilers/shared.js +39 -0
- package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +121 -58
- package/packages/dd-trace/src/proxy.js +25 -1
- package/packages/dd-trace/src/ritm.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
- package/packages/dd-trace/src/span_processor.js +4 -0
- package/packages/dd-trace/src/spanleak.js +98 -0
- package/packages/dd-trace/src/startup-log.js +7 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
- package/packages/dd-trace/src/telemetry/index.js +136 -44
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +47 -5
- package/packages/dd-trace/src/tracer.js +8 -2
- package/scripts/install_plugin_modules.js +11 -3
- package/packages/diagnostics_channel/index.js +0 -3
- package/packages/diagnostics_channel/src/index.js +0 -121
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
/* eslint-disable no-console */
|
|
4
|
+
|
|
5
|
+
const SortedSet = require('tlhunter-sorted-set')
|
|
6
|
+
|
|
7
|
+
const INTERVAL = 1000 // look for expired spans every 1s
|
|
8
|
+
const LIFETIME = 60 * 1000 // all spans have a max lifetime of 1m
|
|
9
|
+
|
|
10
|
+
const MODES = {
|
|
11
|
+
DISABLED: 0,
|
|
12
|
+
// METRICS_ONLY
|
|
13
|
+
LOG: 1,
|
|
14
|
+
GC_AND_LOG: 2
|
|
15
|
+
// GC
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports.MODES = MODES
|
|
19
|
+
|
|
20
|
+
const spans = new SortedSet()
|
|
21
|
+
|
|
22
|
+
// TODO: should these also be delivered as runtime metrics?
|
|
23
|
+
|
|
24
|
+
// const registry = new FinalizationRegistry(name => {
|
|
25
|
+
// spans.del(span) // there is no span
|
|
26
|
+
// })
|
|
27
|
+
|
|
28
|
+
let interval
|
|
29
|
+
let mode = MODES.DISABLED
|
|
30
|
+
|
|
31
|
+
module.exports.disable = function () {
|
|
32
|
+
mode = MODES.DISABLED
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports.enableLogging = function () {
|
|
36
|
+
mode = MODES.LOG
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports.enableGarbageCollection = function () {
|
|
40
|
+
mode = MODES.GC_AND_LOG
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
module.exports.startScrubber = function () {
|
|
44
|
+
if (!isEnabled()) return
|
|
45
|
+
|
|
46
|
+
interval = setInterval(() => {
|
|
47
|
+
const now = Date.now()
|
|
48
|
+
const expired = spans.rangeByScore(0, now)
|
|
49
|
+
|
|
50
|
+
if (!expired.length) return
|
|
51
|
+
|
|
52
|
+
const gc = isGarbageCollecting()
|
|
53
|
+
|
|
54
|
+
const expirationsByType = Object.create(null) // { [spanType]: count }
|
|
55
|
+
|
|
56
|
+
for (const wrapped of expired) {
|
|
57
|
+
spans.del(wrapped)
|
|
58
|
+
const span = wrapped.deref()
|
|
59
|
+
|
|
60
|
+
if (!span) continue // span has already been garbage collected
|
|
61
|
+
|
|
62
|
+
// TODO: Should we also do things like record the route to help users debug leaks?
|
|
63
|
+
if (!expirationsByType[span._name]) expirationsByType[span._name] = 0
|
|
64
|
+
expirationsByType[span._name]++
|
|
65
|
+
|
|
66
|
+
if (!gc) continue // everything after this point is related to manual GC
|
|
67
|
+
|
|
68
|
+
// TODO: what else can we do to alleviate memory usage
|
|
69
|
+
span.context()._tags = Object.create(null)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log('expired spans:' +
|
|
73
|
+
Object.keys(expirationsByType).reduce((a, c) => `${a} ${c}: ${expirationsByType[c]}`, ''))
|
|
74
|
+
}, INTERVAL)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports.stopScrubber = function () {
|
|
78
|
+
clearInterval(interval)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
module.exports.addSpan = function (span) {
|
|
82
|
+
if (!isEnabled()) return
|
|
83
|
+
|
|
84
|
+
const now = Date.now()
|
|
85
|
+
const expiration = now + LIFETIME
|
|
86
|
+
// eslint-disable-next-line no-undef
|
|
87
|
+
const wrapped = new WeakRef(span)
|
|
88
|
+
spans.add(wrapped, expiration)
|
|
89
|
+
// registry.register(span, span._name)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function isEnabled () {
|
|
93
|
+
return mode > MODES.DISABLED
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isGarbageCollecting () {
|
|
97
|
+
return mode >= MODES.GC_AND_LOG
|
|
98
|
+
}
|
|
@@ -6,6 +6,7 @@ const os = require('os')
|
|
|
6
6
|
const { inspect } = require('util')
|
|
7
7
|
const tracerVersion = require('../../../package.json').version
|
|
8
8
|
|
|
9
|
+
const errors = {}
|
|
9
10
|
let config
|
|
10
11
|
let pluginManager
|
|
11
12
|
let samplingRules = []
|
|
@@ -89,6 +90,10 @@ function startupLog ({ agentError } = {}) {
|
|
|
89
90
|
info('DATADOG TRACER CONFIGURATION - ' + out)
|
|
90
91
|
if (agentError) {
|
|
91
92
|
warn('DATADOG TRACER DIAGNOSTIC - Agent Error: ' + agentError.message)
|
|
93
|
+
errors.agentError = {
|
|
94
|
+
code: agentError.code ? agentError.code : '',
|
|
95
|
+
message: `Agent Error:${agentError.message}`
|
|
96
|
+
}
|
|
92
97
|
}
|
|
93
98
|
|
|
94
99
|
config = undefined
|
|
@@ -112,5 +117,6 @@ module.exports = {
|
|
|
112
117
|
startupLog,
|
|
113
118
|
setStartupLogConfig,
|
|
114
119
|
setStartupLogPluginManager,
|
|
115
|
-
setSamplingRules
|
|
120
|
+
setSamplingRules,
|
|
121
|
+
errors
|
|
116
122
|
}
|
|
@@ -4,8 +4,9 @@ const path = require('path')
|
|
|
4
4
|
const parse = require('module-details-from-path')
|
|
5
5
|
const requirePackageJson = require('../require-package-json')
|
|
6
6
|
const { sendData } = require('./send-data')
|
|
7
|
-
const dc = require('
|
|
7
|
+
const dc = require('dc-polyfill')
|
|
8
8
|
const { fileURLToPath } = require('url')
|
|
9
|
+
const { isTrue } = require('../../src/util')
|
|
9
10
|
|
|
10
11
|
const savedDependenciesToSend = new Set()
|
|
11
12
|
const detectedDependencyKeys = new Set()
|
|
@@ -14,20 +15,57 @@ const detectedDependencyVersions = new Set()
|
|
|
14
15
|
const FILE_URI_START = `file://`
|
|
15
16
|
const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart')
|
|
16
17
|
|
|
17
|
-
let immediate, config, application, host
|
|
18
|
+
let immediate, config, application, host, initialLoad
|
|
18
19
|
let isFirstModule = true
|
|
20
|
+
let getRetryData
|
|
21
|
+
let updateRetryData
|
|
19
22
|
|
|
23
|
+
function createBatchPayload (payload) {
|
|
24
|
+
const batchPayload = []
|
|
25
|
+
payload.map(item => {
|
|
26
|
+
batchPayload.push({
|
|
27
|
+
request_type: item.reqType,
|
|
28
|
+
payload: item.payload
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
return batchPayload
|
|
33
|
+
}
|
|
20
34
|
function waitAndSend (config, application, host) {
|
|
21
35
|
if (!immediate) {
|
|
22
36
|
immediate = setImmediate(() => {
|
|
23
37
|
immediate = null
|
|
24
38
|
if (savedDependenciesToSend.size > 0) {
|
|
25
|
-
const dependencies = Array.from(savedDependenciesToSend.values())
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
const dependencies = Array.from(savedDependenciesToSend.values())
|
|
40
|
+
// if a depencdency is from the initial load, *always* send the event
|
|
41
|
+
// Otherwise, only send if dependencyCollection is enabled
|
|
42
|
+
.filter(dep => {
|
|
43
|
+
const initialLoadModule = isTrue(dep.split(' ')[2])
|
|
44
|
+
const sendModule = initialLoadModule || (config.telemetry?.dependencyCollection)
|
|
45
|
+
|
|
46
|
+
if (!sendModule) savedDependenciesToSend.delete(dep) // we'll never send it
|
|
47
|
+
return sendModule
|
|
48
|
+
})
|
|
49
|
+
.splice(0, 2000) // v2 documentation specifies up to 2000 dependencies can be sent at once
|
|
50
|
+
.map(pair => {
|
|
51
|
+
savedDependenciesToSend.delete(pair)
|
|
52
|
+
const [name, version] = pair.split(' ')
|
|
53
|
+
return { name, version }
|
|
54
|
+
})
|
|
55
|
+
let currPayload
|
|
56
|
+
const retryData = getRetryData()
|
|
57
|
+
if (retryData) {
|
|
58
|
+
currPayload = { reqType: 'app-dependencies-loaded', payload: { dependencies } }
|
|
59
|
+
} else {
|
|
60
|
+
if (!dependencies.length) return // no retry data and no dependencies, nothing to send
|
|
61
|
+
currPayload = { dependencies }
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const payload = retryData ? createBatchPayload([currPayload, retryData]) : currPayload
|
|
65
|
+
const reqType = retryData ? 'message-batch' : 'app-dependencies-loaded'
|
|
66
|
+
|
|
67
|
+
sendData(config, application, host, reqType, payload, updateRetryData)
|
|
68
|
+
|
|
31
69
|
if (savedDependenciesToSend.size > 0) {
|
|
32
70
|
waitAndSend(config, application, host)
|
|
33
71
|
}
|
|
@@ -76,7 +114,7 @@ function onModuleLoad (data) {
|
|
|
76
114
|
const dependencyAndVersion = `${name} ${version}`
|
|
77
115
|
|
|
78
116
|
if (!detectedDependencyVersions.has(dependencyAndVersion)) {
|
|
79
|
-
savedDependenciesToSend.add(dependencyAndVersion)
|
|
117
|
+
savedDependenciesToSend.add(`${dependencyAndVersion} ${initialLoad}`)
|
|
80
118
|
detectedDependencyVersions.add(dependencyAndVersion)
|
|
81
119
|
|
|
82
120
|
waitAndSend(config, application, host)
|
|
@@ -89,11 +127,19 @@ function onModuleLoad (data) {
|
|
|
89
127
|
}
|
|
90
128
|
}
|
|
91
129
|
}
|
|
92
|
-
function start (_config, _application, _host) {
|
|
130
|
+
function start (_config = {}, _application, _host, getRetryDataFunction, updateRetryDatafunction) {
|
|
93
131
|
config = _config
|
|
94
132
|
application = _application
|
|
95
133
|
host = _host
|
|
134
|
+
initialLoad = true
|
|
135
|
+
getRetryData = getRetryDataFunction
|
|
136
|
+
updateRetryData = updateRetryDatafunction
|
|
96
137
|
moduleLoadStartChannel.subscribe(onModuleLoad)
|
|
138
|
+
|
|
139
|
+
// try and capture intially loaded modules in the first tick
|
|
140
|
+
// since, ideally, the tracer (and this module) should be loaded first,
|
|
141
|
+
// this should capture any first-tick dependencies
|
|
142
|
+
queueMicrotask(() => { initialLoad = false })
|
|
97
143
|
}
|
|
98
144
|
|
|
99
145
|
function isDependency (filename, request) {
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
|
|
3
2
|
const tracerVersion = require('../../../../package.json').version
|
|
4
|
-
const dc = require('
|
|
3
|
+
const dc = require('dc-polyfill')
|
|
5
4
|
const os = require('os')
|
|
6
5
|
const dependencies = require('./dependencies')
|
|
7
6
|
const { sendData } = require('./send-data')
|
|
8
|
-
|
|
7
|
+
const { errors } = require('../startup-log')
|
|
9
8
|
const { manager: metricsManager } = require('./metrics')
|
|
10
|
-
const logs = require('./logs')
|
|
11
9
|
|
|
12
10
|
const telemetryStartChannel = dc.channel('datadog:telemetry:start')
|
|
13
11
|
const telemetryStopChannel = dc.channel('datadog:telemetry:stop')
|
|
@@ -17,11 +15,53 @@ let pluginManager
|
|
|
17
15
|
|
|
18
16
|
let application
|
|
19
17
|
let host
|
|
20
|
-
let interval
|
|
21
18
|
let heartbeatTimeout
|
|
22
19
|
let heartbeatInterval
|
|
20
|
+
let extendedInterval
|
|
21
|
+
let integrations
|
|
22
|
+
let retryData = null
|
|
23
|
+
const extendedHeartbeatPayload = {}
|
|
24
|
+
|
|
23
25
|
const sentIntegrations = new Set()
|
|
24
26
|
|
|
27
|
+
function getRetryData () {
|
|
28
|
+
return retryData
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function updateRetryData (error, retryObj) {
|
|
32
|
+
if (error) {
|
|
33
|
+
if (retryObj.reqType === 'message-batch') {
|
|
34
|
+
const payload = retryObj.payload[0].payload
|
|
35
|
+
const reqType = retryObj.payload[0].request_type
|
|
36
|
+
retryData = { payload: payload, reqType: reqType }
|
|
37
|
+
|
|
38
|
+
// Since this payload failed twice it now gets save in to the extended heartbeat
|
|
39
|
+
const failedPayload = retryObj.payload[1].payload
|
|
40
|
+
const failedReqType = retryObj.payload[1].request_type
|
|
41
|
+
|
|
42
|
+
// save away the dependencies and integration request for extended heartbeat.
|
|
43
|
+
if (failedReqType === 'app-integrations-change') {
|
|
44
|
+
if (extendedHeartbeatPayload['integrations']) {
|
|
45
|
+
extendedHeartbeatPayload['integrations'].push(failedPayload)
|
|
46
|
+
} else {
|
|
47
|
+
extendedHeartbeatPayload['integrations'] = [failedPayload]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (failedReqType === 'app-dependencies-loaded') {
|
|
51
|
+
if (extendedHeartbeatPayload['dependencies']) {
|
|
52
|
+
extendedHeartbeatPayload['dependencies'].push(failedPayload)
|
|
53
|
+
} else {
|
|
54
|
+
extendedHeartbeatPayload['dependencies'] = [failedPayload]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
retryData = retryObj
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
retryData = null
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
25
65
|
function getIntegrations () {
|
|
26
66
|
const newIntegrations = []
|
|
27
67
|
for (const pluginName in pluginManager._pluginsByName) {
|
|
@@ -38,6 +78,23 @@ function getIntegrations () {
|
|
|
38
78
|
return newIntegrations
|
|
39
79
|
}
|
|
40
80
|
|
|
81
|
+
function getProducts (config) {
|
|
82
|
+
const products = {
|
|
83
|
+
appsec: {
|
|
84
|
+
enabled: config.appsec.enabled
|
|
85
|
+
},
|
|
86
|
+
profiler: {
|
|
87
|
+
version: tracerVersion,
|
|
88
|
+
enabled: config.profiling.enabled
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (errors.profilingError) {
|
|
92
|
+
products.profiler.error = errors.profilingError
|
|
93
|
+
errors.profilingError = {}
|
|
94
|
+
}
|
|
95
|
+
return products
|
|
96
|
+
}
|
|
97
|
+
|
|
41
98
|
function flatten (input, result = [], prefix = [], traversedObjects = null) {
|
|
42
99
|
traversedObjects = traversedObjects || new WeakSet()
|
|
43
100
|
if (traversedObjects.has(input)) {
|
|
@@ -48,33 +105,30 @@ function flatten (input, result = [], prefix = [], traversedObjects = null) {
|
|
|
48
105
|
if (typeof value === 'object' && value !== null) {
|
|
49
106
|
flatten(value, result, [...prefix, key], traversedObjects)
|
|
50
107
|
} else {
|
|
51
|
-
|
|
108
|
+
// TODO: add correct origin value
|
|
109
|
+
result.push({ name: [...prefix, key].join('.'), value, origin: 'unknown' })
|
|
52
110
|
}
|
|
53
111
|
}
|
|
54
112
|
return result
|
|
55
113
|
}
|
|
56
114
|
|
|
57
|
-
function appStarted () {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
configuration: flatten(formatConfig(config)),
|
|
62
|
-
additional_payload: []
|
|
115
|
+
function appStarted (config) {
|
|
116
|
+
const app = {
|
|
117
|
+
products: getProducts(config),
|
|
118
|
+
configuration: flatten(config)
|
|
63
119
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
? Object.entries(config.peerServiceMapping).map(([key, value]) => `${key}:${value}`).join(',')
|
|
71
|
-
: ''
|
|
72
|
-
return config
|
|
120
|
+
// TODO: add app.error with correct error codes
|
|
121
|
+
// if (errors.agentError) {
|
|
122
|
+
// app.error = errors.agentError
|
|
123
|
+
// errors.agentError = {}
|
|
124
|
+
// }
|
|
125
|
+
return app
|
|
73
126
|
}
|
|
74
127
|
|
|
75
128
|
function onBeforeExit () {
|
|
76
129
|
process.removeListener('beforeExit', onBeforeExit)
|
|
77
|
-
|
|
130
|
+
const { reqType, payload } = createPayload('app-closing')
|
|
131
|
+
sendData(config, application, host, reqType, payload)
|
|
78
132
|
}
|
|
79
133
|
|
|
80
134
|
function createAppObject (config) {
|
|
@@ -121,14 +175,52 @@ function getTelemetryData () {
|
|
|
121
175
|
return { config, application, host, heartbeatInterval }
|
|
122
176
|
}
|
|
123
177
|
|
|
178
|
+
function createBatchPayload (payload) {
|
|
179
|
+
const batchPayload = []
|
|
180
|
+
payload.map(item => {
|
|
181
|
+
batchPayload.push({
|
|
182
|
+
request_type: item.reqType,
|
|
183
|
+
payload: item.payload
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
return batchPayload
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function createPayload (currReqType, currPayload = {}) {
|
|
191
|
+
if (getRetryData()) {
|
|
192
|
+
const payload = { reqType: currReqType, payload: currPayload }
|
|
193
|
+
const batchPayload = createBatchPayload([payload, retryData])
|
|
194
|
+
return { 'reqType': 'message-batch', 'payload': batchPayload }
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return { 'reqType': currReqType, 'payload': currPayload }
|
|
198
|
+
}
|
|
199
|
+
|
|
124
200
|
function heartbeat (config, application, host) {
|
|
125
201
|
heartbeatTimeout = setTimeout(() => {
|
|
126
|
-
|
|
202
|
+
metricsManager.send(config, application, host)
|
|
203
|
+
|
|
204
|
+
const { reqType, payload } = createPayload('app-heartbeat')
|
|
205
|
+
sendData(config, application, host, reqType, payload, updateRetryData)
|
|
127
206
|
heartbeat(config, application, host)
|
|
128
207
|
}, heartbeatInterval).unref()
|
|
129
208
|
return heartbeatTimeout
|
|
130
209
|
}
|
|
131
210
|
|
|
211
|
+
function extendedHeartbeat (config) {
|
|
212
|
+
extendedInterval = setInterval(() => {
|
|
213
|
+
const appPayload = appStarted(config)
|
|
214
|
+
const payload = {
|
|
215
|
+
...appPayload,
|
|
216
|
+
...extendedHeartbeatPayload
|
|
217
|
+
}
|
|
218
|
+
sendData(config, application, host, 'app-extended-heartbeat', payload)
|
|
219
|
+
Object.keys(extendedHeartbeatPayload).forEach(key => delete extendedHeartbeatPayload[key])
|
|
220
|
+
}, 1000 * 60 * 60 * 24).unref()
|
|
221
|
+
return extendedInterval
|
|
222
|
+
}
|
|
223
|
+
|
|
132
224
|
function start (aConfig, thePluginManager) {
|
|
133
225
|
if (!aConfig.telemetry.enabled) {
|
|
134
226
|
return
|
|
@@ -138,19 +230,22 @@ function start (aConfig, thePluginManager) {
|
|
|
138
230
|
application = createAppObject(config)
|
|
139
231
|
host = createHostObject()
|
|
140
232
|
heartbeatInterval = config.telemetry.heartbeatInterval
|
|
233
|
+
integrations = getIntegrations()
|
|
234
|
+
|
|
235
|
+
dependencies.start(config, application, host, getRetryData, updateRetryData)
|
|
236
|
+
|
|
237
|
+
sendData(config, application, host, 'app-started', appStarted(config))
|
|
141
238
|
|
|
142
|
-
|
|
143
|
-
|
|
239
|
+
if (integrations.length > 0) {
|
|
240
|
+
sendData(config, application, host, 'app-integrations-change',
|
|
241
|
+
{ integrations }, updateRetryData)
|
|
242
|
+
}
|
|
144
243
|
|
|
145
|
-
sendData(config, application, host, 'app-started', appStarted())
|
|
146
244
|
heartbeat(config, application, host)
|
|
147
|
-
interval = setInterval(() => {
|
|
148
|
-
metricsManager.send(config, application, host)
|
|
149
|
-
logs.send(config, application, host)
|
|
150
|
-
}, heartbeatInterval)
|
|
151
|
-
interval.unref()
|
|
152
|
-
process.on('beforeExit', onBeforeExit)
|
|
153
245
|
|
|
246
|
+
extendedHeartbeat(config)
|
|
247
|
+
|
|
248
|
+
process.on('beforeExit', onBeforeExit)
|
|
154
249
|
telemetryStartChannel.publish(getTelemetryData())
|
|
155
250
|
}
|
|
156
251
|
|
|
@@ -158,7 +253,7 @@ function stop () {
|
|
|
158
253
|
if (!config) {
|
|
159
254
|
return
|
|
160
255
|
}
|
|
161
|
-
clearInterval(
|
|
256
|
+
clearInterval(extendedInterval)
|
|
162
257
|
clearTimeout(heartbeatTimeout)
|
|
163
258
|
process.removeListener('beforeExit', onBeforeExit)
|
|
164
259
|
|
|
@@ -175,7 +270,10 @@ function updateIntegrations () {
|
|
|
175
270
|
if (integrations.length === 0) {
|
|
176
271
|
return
|
|
177
272
|
}
|
|
178
|
-
|
|
273
|
+
|
|
274
|
+
const { reqType, payload } = createPayload('app-integrations-change', { integrations })
|
|
275
|
+
|
|
276
|
+
sendData(config, application, host, reqType, payload, updateRetryData)
|
|
179
277
|
}
|
|
180
278
|
|
|
181
279
|
function updateConfig (changes, config) {
|
|
@@ -188,21 +286,15 @@ function updateConfig (changes, config) {
|
|
|
188
286
|
const application = createAppObject(config)
|
|
189
287
|
const host = createHostObject()
|
|
190
288
|
|
|
191
|
-
const names = {
|
|
192
|
-
sampleRate: 'DD_TRACE_SAMPLE_RATE',
|
|
193
|
-
logInjection: 'DD_LOG_INJECTION',
|
|
194
|
-
headerTags: 'DD_TRACE_HEADER_TAGS'
|
|
195
|
-
}
|
|
196
|
-
|
|
197
289
|
const configuration = changes.map(change => ({
|
|
198
|
-
name:
|
|
290
|
+
name: change.name,
|
|
199
291
|
value: Array.isArray(change.value) ? change.value.join(',') : change.value,
|
|
200
292
|
origin: change.origin
|
|
201
293
|
}))
|
|
202
294
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
295
|
+
const { reqType, payload } = createPayload('app-client-configuration-change', { configuration })
|
|
296
|
+
|
|
297
|
+
sendData(config, application, host, reqType, payload, updateRetryData)
|
|
206
298
|
}
|
|
207
299
|
|
|
208
300
|
module.exports = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const dc = require('
|
|
3
|
+
const dc = require('dc-polyfill')
|
|
4
4
|
const logCollector = require('./log-collector')
|
|
5
5
|
const { sendData } = require('../send-data')
|
|
6
6
|
|
|
@@ -52,7 +52,7 @@ function stop () {
|
|
|
52
52
|
function send (config, application, host) {
|
|
53
53
|
if (!enabled) return
|
|
54
54
|
|
|
55
|
-
const logs = logCollector.drain()
|
|
55
|
+
const logs = { 'logs': logCollector.drain() }
|
|
56
56
|
if (logs) {
|
|
57
57
|
sendData(config, application, host, 'logs', logs)
|
|
58
58
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
|
|
1
2
|
const request = require('../exporters/common/request')
|
|
3
|
+
const log = require('../log')
|
|
4
|
+
let agentTelemetry = true
|
|
2
5
|
|
|
3
6
|
function getHeaders (config, application, reqType) {
|
|
4
7
|
const headers = {
|
|
5
8
|
'content-type': 'application/json',
|
|
6
|
-
'dd-telemetry-api-version': '
|
|
9
|
+
'dd-telemetry-api-version': 'v2',
|
|
7
10
|
'dd-telemetry-request-type': reqType,
|
|
8
11
|
'dd-client-library-language': application.language_name,
|
|
9
12
|
'dd-client-library-version': application.tracer_version
|
|
@@ -28,7 +31,7 @@ function getPayload (payload) {
|
|
|
28
31
|
}
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
function sendData (config, application, host, reqType, payload = {}) {
|
|
34
|
+
function sendData (config, application, host, reqType, payload = {}, cb = () => {}) {
|
|
32
35
|
const {
|
|
33
36
|
hostname,
|
|
34
37
|
port,
|
|
@@ -44,7 +47,8 @@ function sendData (config, application, host, reqType, payload = {}) {
|
|
|
44
47
|
headers: getHeaders(config, application, reqType)
|
|
45
48
|
}
|
|
46
49
|
const data = JSON.stringify({
|
|
47
|
-
api_version: '
|
|
50
|
+
api_version: 'v2',
|
|
51
|
+
naming_schema_version: config.spanAttributeSchema ? config.spanAttributeSchema : '',
|
|
48
52
|
request_type: reqType,
|
|
49
53
|
tracer_time: Math.floor(Date.now() / 1000),
|
|
50
54
|
runtime_id: config.tags['runtime-id'],
|
|
@@ -54,8 +58,46 @@ function sendData (config, application, host, reqType, payload = {}) {
|
|
|
54
58
|
host
|
|
55
59
|
})
|
|
56
60
|
|
|
57
|
-
request(data, options, () => {
|
|
58
|
-
|
|
61
|
+
request(data, options, (error) => {
|
|
62
|
+
if (error && process.env.DD_API_KEY && config.site) {
|
|
63
|
+
if (agentTelemetry) {
|
|
64
|
+
log.warn('Agent telemetry failed, started agentless telemetry')
|
|
65
|
+
agentTelemetry = false
|
|
66
|
+
}
|
|
67
|
+
// figure out which data center to send to
|
|
68
|
+
let backendUrl
|
|
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
|
+
}
|
|
81
|
+
const backendHeader = { ...options.headers, 'DD-API-KEY': process.env.DD_API_KEY }
|
|
82
|
+
const backendOptions = {
|
|
83
|
+
...options,
|
|
84
|
+
url: backendUrl,
|
|
85
|
+
headers: backendHeader
|
|
86
|
+
}
|
|
87
|
+
if (backendUrl) {
|
|
88
|
+
request(data, backendOptions, (error) => { log.error(error) })
|
|
89
|
+
} else {
|
|
90
|
+
log.error('Invalid Telemetry URL')
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!error && !agentTelemetry) {
|
|
95
|
+
agentTelemetry = true
|
|
96
|
+
log.info('Started agent telemetry')
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// call the callback function so that we can track the error and payload
|
|
100
|
+
cb(error, { payload, reqType })
|
|
59
101
|
})
|
|
60
102
|
}
|
|
61
103
|
|
|
@@ -31,8 +31,10 @@ class DatadogTracer extends Tracer {
|
|
|
31
31
|
|
|
32
32
|
// todo[piochelepiotr] These two methods are not related to the tracer, but to data streams monitoring.
|
|
33
33
|
// They should be moved outside of the tracer in the future.
|
|
34
|
-
setCheckpoint (edgeTags) {
|
|
35
|
-
const ctx = this._dataStreamsProcessor.setCheckpoint(
|
|
34
|
+
setCheckpoint (edgeTags, span, payloadSize = 0) {
|
|
35
|
+
const ctx = this._dataStreamsProcessor.setCheckpoint(
|
|
36
|
+
edgeTags, span, DataStreamsContext.getDataStreamsContext(), payloadSize
|
|
37
|
+
)
|
|
36
38
|
DataStreamsContext.setDataStreamsContext(ctx)
|
|
37
39
|
return ctx
|
|
38
40
|
}
|
|
@@ -44,6 +46,10 @@ class DatadogTracer extends Tracer {
|
|
|
44
46
|
return ctx
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
setOffset (offsetData) {
|
|
50
|
+
return this._dataStreamsProcessor.setOffset(offsetData)
|
|
51
|
+
}
|
|
52
|
+
|
|
47
53
|
trace (name, options, fn) {
|
|
48
54
|
options = Object.assign({
|
|
49
55
|
childOf: this.scope().active()
|
|
@@ -80,7 +80,9 @@ async function assertVersions () {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
async function assertInstrumentation (instrumentation, external) {
|
|
83
|
-
const versions =
|
|
83
|
+
const versions = process.env.PACKAGE_VERSION_RANGE ? [process.env.PACKAGE_VERSION_RANGE]
|
|
84
|
+
: [].concat(instrumentation.versions || [])
|
|
85
|
+
|
|
84
86
|
for (const version of versions) {
|
|
85
87
|
if (version) {
|
|
86
88
|
await assertModules(instrumentation.name, semver.coerce(version).version, external)
|
|
@@ -130,8 +132,14 @@ async function assertPackage (name, version, dependency, external) {
|
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
if (!external) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
if (name === 'aerospike') {
|
|
136
|
+
pkg.installConfig = {
|
|
137
|
+
'hoistingLimits': 'workspaces'
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
pkg.workspaces = {
|
|
141
|
+
nohoist: ['**/**']
|
|
142
|
+
}
|
|
135
143
|
}
|
|
136
144
|
}
|
|
137
145
|
fs.writeFileSync(filename(name, version, 'package.json'), JSON.stringify(pkg, null, 2) + '\n')
|