dd-trace 4.18.0 → 5.6.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/CONTRIBUTING.md +98 -0
- package/LICENSE-3rdparty.csv +4 -5
- package/MIGRATING.md +15 -0
- package/README.md +20 -140
- package/ci/cypress/after-run.js +1 -0
- package/ci/cypress/after-spec.js +1 -0
- package/ci/init.js +1 -4
- 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 +1523 -1460
- package/package.json +19 -19
- package/packages/datadog-core/src/storage/async_resource.js +1 -1
- package/packages/datadog-core/src/utils/src/get.js +11 -0
- package/packages/datadog-core/src/utils/src/has.js +14 -0
- package/packages/datadog-core/src/utils/src/kebabcase.js +16 -0
- package/packages/datadog-core/src/utils/src/pick.js +11 -0
- package/packages/datadog-core/src/utils/src/set.js +16 -0
- package/packages/datadog-core/src/utils/src/uniq.js +5 -0
- package/packages/datadog-esbuild/index.js +1 -20
- package/packages/datadog-instrumentations/src/aerospike.js +47 -0
- package/packages/datadog-instrumentations/src/amqplib.js +2 -2
- 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/child_process.js +150 -0
- package/packages/datadog-instrumentations/src/couchbase.js +5 -4
- package/packages/datadog-instrumentations/src/crypto.js +2 -1
- package/packages/datadog-instrumentations/src/cucumber.js +163 -46
- package/packages/datadog-instrumentations/src/dns.js +2 -1
- package/packages/datadog-instrumentations/src/express.js +20 -0
- package/packages/datadog-instrumentations/src/graphql.js +18 -4
- package/packages/datadog-instrumentations/src/grpc/client.js +56 -36
- package/packages/datadog-instrumentations/src/grpc/server.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/instrument.js +9 -4
- package/packages/datadog-instrumentations/src/helpers/register.js +19 -3
- package/packages/datadog-instrumentations/src/http/client.js +12 -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 +239 -52
- package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
- package/packages/datadog-instrumentations/src/mocha.js +154 -18
- package/packages/datadog-instrumentations/src/mongodb-core.js +34 -3
- package/packages/datadog-instrumentations/src/mongoose.js +23 -10
- package/packages/datadog-instrumentations/src/mquery.js +65 -0
- package/packages/datadog-instrumentations/src/net.js +10 -2
- package/packages/datadog-instrumentations/src/next.js +35 -9
- package/packages/datadog-instrumentations/src/playwright.js +110 -16
- 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-amqplib/src/consumer.js +14 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +13 -1
- package/packages/datadog-plugin-aws-sdk/src/base.js +3 -2
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +163 -27
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +46 -8
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +129 -22
- package/packages/datadog-plugin-child_process/src/index.js +91 -0
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +125 -0
- package/packages/datadog-plugin-cucumber/src/index.js +70 -13
- package/packages/datadog-plugin-cypress/src/after-run.js +3 -0
- package/packages/datadog-plugin-cypress/src/after-spec.js +3 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +625 -0
- package/packages/datadog-plugin-cypress/src/plugin.js +6 -454
- package/packages/datadog-plugin-cypress/src/support.js +50 -3
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -0
- package/packages/datadog-plugin-graphql/src/index.js +1 -6
- package/packages/datadog-plugin-graphql/src/resolve.js +28 -18
- package/packages/datadog-plugin-grpc/src/client.js +16 -2
- package/packages/datadog-plugin-grpc/src/util.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +19 -2
- package/packages/datadog-plugin-jest/src/index.js +118 -12
- package/packages/datadog-plugin-jest/src/util.js +38 -16
- package/packages/datadog-plugin-kafkajs/src/consumer.js +76 -6
- package/packages/datadog-plugin-kafkajs/src/producer.js +64 -8
- package/packages/datadog-plugin-mocha/src/index.js +87 -17
- package/packages/datadog-plugin-next/src/index.js +40 -14
- package/packages/datadog-plugin-playwright/src/index.js +71 -8
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -1
- package/packages/datadog-plugin-rhea/src/producer.js +10 -0
- package/packages/dd-trace/src/appsec/activation.js +29 -0
- package/packages/dd-trace/src/appsec/addresses.js +5 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +61 -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 +7 -3
- package/packages/dd-trace/src/appsec/graphql.js +146 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +22 -17
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +7 -28
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +10 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-randomness-analyzer.js +19 -0
- package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +90 -0
- package/packages/dd-trace/src/appsec/iast/context/kafka-ctx-plugin.js +14 -0
- package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +13 -2
- package/packages/dd-trace/src/appsec/iast/index.js +15 -5
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +1 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +2 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +10 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +53 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +10 -46
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +13 -9
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +47 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +19 -6
- package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +3 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +41 -3
- 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-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +2 -0
- package/packages/dd-trace/src/appsec/index.js +49 -33
- package/packages/dd-trace/src/appsec/recommended.json +1763 -106
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +42 -16
- package/packages/dd-trace/src/appsec/remote_config/manager.js +9 -8
- package/packages/dd-trace/src/appsec/reporter.js +51 -34
- package/packages/dd-trace/src/appsec/rule_manager.js +11 -8
- 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/{intelligent-test-runner/get-itr-configuration.js → early-flake-detection/get-known-tests.js} +17 -22
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +25 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +2 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +95 -37
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +134 -61
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +37 -4
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +131 -0
- package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
- package/packages/dd-trace/src/config.js +561 -470
- package/packages/dd-trace/src/data_streams_context.js +1 -1
- package/packages/dd-trace/src/datastreams/pathway.js +58 -1
- package/packages/dd-trace/src/datastreams/processor.js +196 -27
- package/packages/dd-trace/src/datastreams/writer.js +11 -5
- package/packages/dd-trace/src/dogstatsd.js +3 -5
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -6
- 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/exporters/common/request.js +21 -3
- package/packages/dd-trace/src/format.js +30 -2
- 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/noop/span.js +1 -0
- package/packages/dd-trace/src/opentelemetry/span.js +104 -4
- package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +16 -7
- package/packages/dd-trace/src/opentracing/span.js +48 -4
- package/packages/dd-trace/src/opentracing/span_context.js +15 -6
- package/packages/dd-trace/src/opentracing/tracer.js +4 -3
- package/packages/dd-trace/src/plugin_manager.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +78 -19
- package/packages/dd-trace/src/plugins/database.js +1 -1
- package/packages/dd-trace/src/plugins/index.js +7 -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 +104 -22
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
- package/packages/dd-trace/src/plugins/util/test.js +60 -10
- 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/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/priority_sampler.js +30 -38
- package/packages/dd-trace/src/profiler.js +5 -3
- package/packages/dd-trace/src/profiling/config.js +77 -24
- package/packages/dd-trace/src/profiling/exporters/agent.js +77 -31
- package/packages/dd-trace/src/profiling/exporters/file.js +2 -1
- package/packages/dd-trace/src/profiling/profiler.js +33 -22
- package/packages/dd-trace/src/profiling/profilers/events.js +270 -0
- package/packages/dd-trace/src/profiling/profilers/shared.js +45 -0
- package/packages/dd-trace/src/profiling/profilers/space.js +18 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +146 -70
- package/packages/dd-trace/src/proxy.js +56 -24
- package/packages/dd-trace/src/ritm.js +1 -1
- package/packages/dd-trace/src/sampling_rule.js +130 -0
- 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 +9 -1
- package/packages/dd-trace/src/span_sampler.js +6 -64
- 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 +182 -53
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +65 -7
- package/packages/dd-trace/src/tracer.js +12 -5
- package/register.js +4 -0
- package/scripts/install_plugin_modules.js +11 -3
- package/scripts/st.js +105 -0
- package/packages/datadog-instrumentations/src/child-process.js +0 -30
- package/packages/dd-trace/src/plugins/util/exec.js +0 -13
- package/packages/diagnostics_channel/index.js +0 -3
- package/packages/diagnostics_channel/src/index.js +0 -121
|
@@ -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,
|
|
@@ -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,11 +1,10 @@
|
|
|
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
9
|
const logs = require('./logs')
|
|
11
10
|
|
|
@@ -17,11 +16,54 @@ let pluginManager
|
|
|
17
16
|
|
|
18
17
|
let application
|
|
19
18
|
let host
|
|
20
|
-
let interval
|
|
21
19
|
let heartbeatTimeout
|
|
22
20
|
let heartbeatInterval
|
|
21
|
+
let extendedInterval
|
|
22
|
+
let integrations
|
|
23
|
+
let configWithOrigin = []
|
|
24
|
+
let retryData = null
|
|
25
|
+
const extendedHeartbeatPayload = {}
|
|
26
|
+
|
|
23
27
|
const sentIntegrations = new Set()
|
|
24
28
|
|
|
29
|
+
function getRetryData () {
|
|
30
|
+
return retryData
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function updateRetryData (error, retryObj) {
|
|
34
|
+
if (error) {
|
|
35
|
+
if (retryObj.reqType === 'message-batch') {
|
|
36
|
+
const payload = retryObj.payload[0].payload
|
|
37
|
+
const reqType = retryObj.payload[0].request_type
|
|
38
|
+
retryData = { payload: payload, reqType: reqType }
|
|
39
|
+
|
|
40
|
+
// Since this payload failed twice it now gets save in to the extended heartbeat
|
|
41
|
+
const failedPayload = retryObj.payload[1].payload
|
|
42
|
+
const failedReqType = retryObj.payload[1].request_type
|
|
43
|
+
|
|
44
|
+
// save away the dependencies and integration request for extended heartbeat.
|
|
45
|
+
if (failedReqType === 'app-integrations-change') {
|
|
46
|
+
if (extendedHeartbeatPayload['integrations']) {
|
|
47
|
+
extendedHeartbeatPayload['integrations'].push(failedPayload)
|
|
48
|
+
} else {
|
|
49
|
+
extendedHeartbeatPayload['integrations'] = [failedPayload]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (failedReqType === 'app-dependencies-loaded') {
|
|
53
|
+
if (extendedHeartbeatPayload['dependencies']) {
|
|
54
|
+
extendedHeartbeatPayload['dependencies'].push(failedPayload)
|
|
55
|
+
} else {
|
|
56
|
+
extendedHeartbeatPayload['dependencies'] = [failedPayload]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
retryData = retryObj
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
retryData = null
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
25
67
|
function getIntegrations () {
|
|
26
68
|
const newIntegrations = []
|
|
27
69
|
for (const pluginName in pluginManager._pluginsByName) {
|
|
@@ -38,43 +80,66 @@ function getIntegrations () {
|
|
|
38
80
|
return newIntegrations
|
|
39
81
|
}
|
|
40
82
|
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
83
|
+
function getProducts (config) {
|
|
84
|
+
const products = {
|
|
85
|
+
appsec: {
|
|
86
|
+
enabled: config.appsec.enabled
|
|
87
|
+
},
|
|
88
|
+
profiler: {
|
|
89
|
+
version: tracerVersion,
|
|
90
|
+
enabled: config.profiling.enabled
|
|
91
|
+
}
|
|
45
92
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
93
|
+
if (errors.profilingError) {
|
|
94
|
+
products.profiler.error = errors.profilingError
|
|
95
|
+
errors.profilingError = {}
|
|
96
|
+
}
|
|
97
|
+
return products
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function getInstallSignature (config) {
|
|
101
|
+
const { installSignature: sig } = config
|
|
102
|
+
if (sig && (sig.id || sig.time || sig.type)) {
|
|
103
|
+
return {
|
|
104
|
+
install_id: sig.id,
|
|
105
|
+
install_time: sig.time,
|
|
106
|
+
install_type: sig.type
|
|
52
107
|
}
|
|
53
108
|
}
|
|
54
|
-
return result
|
|
55
109
|
}
|
|
56
110
|
|
|
57
|
-
function appStarted () {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
111
|
+
function appStarted (config) {
|
|
112
|
+
const app = {
|
|
113
|
+
products: getProducts(config),
|
|
114
|
+
configuration: configWithOrigin
|
|
115
|
+
}
|
|
116
|
+
const installSignature = getInstallSignature(config)
|
|
117
|
+
if (installSignature) {
|
|
118
|
+
app.install_signature = installSignature
|
|
63
119
|
}
|
|
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
|
|
64
126
|
}
|
|
65
127
|
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
128
|
+
function appClosing () {
|
|
129
|
+
if (!config?.telemetry?.enabled) {
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
const { reqType, payload } = createPayload('app-closing')
|
|
133
|
+
sendData(config, application, host, reqType, payload)
|
|
134
|
+
// we flush before shutting down. Only in CI Visibility
|
|
135
|
+
if (config.isCiVisibility) {
|
|
136
|
+
metricsManager.send(config, application, host)
|
|
137
|
+
}
|
|
73
138
|
}
|
|
74
139
|
|
|
75
140
|
function onBeforeExit () {
|
|
76
141
|
process.removeListener('beforeExit', onBeforeExit)
|
|
77
|
-
|
|
142
|
+
appClosing()
|
|
78
143
|
}
|
|
79
144
|
|
|
80
145
|
function createAppObject (config) {
|
|
@@ -121,14 +186,53 @@ function getTelemetryData () {
|
|
|
121
186
|
return { config, application, host, heartbeatInterval }
|
|
122
187
|
}
|
|
123
188
|
|
|
189
|
+
function createBatchPayload (payload) {
|
|
190
|
+
const batchPayload = []
|
|
191
|
+
payload.map(item => {
|
|
192
|
+
batchPayload.push({
|
|
193
|
+
request_type: item.reqType,
|
|
194
|
+
payload: item.payload
|
|
195
|
+
})
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
return batchPayload
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function createPayload (currReqType, currPayload = {}) {
|
|
202
|
+
if (getRetryData()) {
|
|
203
|
+
const payload = { reqType: currReqType, payload: currPayload }
|
|
204
|
+
const batchPayload = createBatchPayload([payload, retryData])
|
|
205
|
+
return { 'reqType': 'message-batch', 'payload': batchPayload }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return { 'reqType': currReqType, 'payload': currPayload }
|
|
209
|
+
}
|
|
210
|
+
|
|
124
211
|
function heartbeat (config, application, host) {
|
|
125
212
|
heartbeatTimeout = setTimeout(() => {
|
|
126
|
-
|
|
213
|
+
metricsManager.send(config, application, host)
|
|
214
|
+
logs.send(config, application, host)
|
|
215
|
+
|
|
216
|
+
const { reqType, payload } = createPayload('app-heartbeat')
|
|
217
|
+
sendData(config, application, host, reqType, payload, updateRetryData)
|
|
127
218
|
heartbeat(config, application, host)
|
|
128
219
|
}, heartbeatInterval).unref()
|
|
129
220
|
return heartbeatTimeout
|
|
130
221
|
}
|
|
131
222
|
|
|
223
|
+
function extendedHeartbeat (config) {
|
|
224
|
+
extendedInterval = setInterval(() => {
|
|
225
|
+
const appPayload = appStarted(config)
|
|
226
|
+
const payload = {
|
|
227
|
+
...appPayload,
|
|
228
|
+
...extendedHeartbeatPayload
|
|
229
|
+
}
|
|
230
|
+
sendData(config, application, host, 'app-extended-heartbeat', payload)
|
|
231
|
+
Object.keys(extendedHeartbeatPayload).forEach(key => delete extendedHeartbeatPayload[key])
|
|
232
|
+
}, 1000 * 60 * 60 * 24).unref()
|
|
233
|
+
return extendedInterval
|
|
234
|
+
}
|
|
235
|
+
|
|
132
236
|
function start (aConfig, thePluginManager) {
|
|
133
237
|
if (!aConfig.telemetry.enabled) {
|
|
134
238
|
return
|
|
@@ -138,19 +242,23 @@ function start (aConfig, thePluginManager) {
|
|
|
138
242
|
application = createAppObject(config)
|
|
139
243
|
host = createHostObject()
|
|
140
244
|
heartbeatInterval = config.telemetry.heartbeatInterval
|
|
245
|
+
integrations = getIntegrations()
|
|
141
246
|
|
|
142
|
-
dependencies.start(config, application, host)
|
|
247
|
+
dependencies.start(config, application, host, getRetryData, updateRetryData)
|
|
143
248
|
logs.start(config)
|
|
144
249
|
|
|
145
|
-
sendData(config, application, host, 'app-started', appStarted())
|
|
250
|
+
sendData(config, application, host, 'app-started', appStarted(config))
|
|
251
|
+
|
|
252
|
+
if (integrations.length > 0) {
|
|
253
|
+
sendData(config, application, host, 'app-integrations-change',
|
|
254
|
+
{ integrations }, updateRetryData)
|
|
255
|
+
}
|
|
256
|
+
|
|
146
257
|
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
258
|
|
|
259
|
+
extendedHeartbeat(config)
|
|
260
|
+
|
|
261
|
+
process.on('beforeExit', onBeforeExit)
|
|
154
262
|
telemetryStartChannel.publish(getTelemetryData())
|
|
155
263
|
}
|
|
156
264
|
|
|
@@ -158,7 +266,7 @@ function stop () {
|
|
|
158
266
|
if (!config) {
|
|
159
267
|
return
|
|
160
268
|
}
|
|
161
|
-
clearInterval(
|
|
269
|
+
clearInterval(extendedInterval)
|
|
162
270
|
clearTimeout(heartbeatTimeout)
|
|
163
271
|
process.removeListener('beforeExit', onBeforeExit)
|
|
164
272
|
|
|
@@ -175,39 +283,60 @@ function updateIntegrations () {
|
|
|
175
283
|
if (integrations.length === 0) {
|
|
176
284
|
return
|
|
177
285
|
}
|
|
178
|
-
|
|
286
|
+
|
|
287
|
+
const { reqType, payload } = createPayload('app-integrations-change', { integrations })
|
|
288
|
+
|
|
289
|
+
sendData(config, application, host, reqType, payload, updateRetryData)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function formatMapForTelemetry (map) {
|
|
293
|
+
// format from an object to a string map in order for
|
|
294
|
+
// telemetry intake to accept the configuration
|
|
295
|
+
return map
|
|
296
|
+
? Object.entries(map).map(([key, value]) => `${key}:${value}`).join(',')
|
|
297
|
+
: ''
|
|
179
298
|
}
|
|
180
299
|
|
|
181
300
|
function updateConfig (changes, config) {
|
|
182
301
|
if (!config.telemetry.enabled) return
|
|
183
302
|
if (changes.length === 0) return
|
|
184
303
|
|
|
185
|
-
// Hack to make system tests happy until we ship telemetry v2
|
|
186
|
-
if (process.env.DD_INTERNAL_TELEMETRY_V2_ENABLED !== '1') return
|
|
187
|
-
|
|
188
304
|
const application = createAppObject(config)
|
|
189
305
|
const host = createHostObject()
|
|
190
306
|
|
|
191
307
|
const names = {
|
|
192
308
|
sampleRate: 'DD_TRACE_SAMPLE_RATE',
|
|
193
309
|
logInjection: 'DD_LOG_INJECTION',
|
|
194
|
-
headerTags: 'DD_TRACE_HEADER_TAGS'
|
|
310
|
+
headerTags: 'DD_TRACE_HEADER_TAGS',
|
|
311
|
+
tags: 'DD_TAGS'
|
|
195
312
|
}
|
|
196
313
|
|
|
197
|
-
const configuration =
|
|
198
|
-
name: names[change.name],
|
|
199
|
-
value: Array.isArray(change.value) ? change.value.join(',') : change.value,
|
|
200
|
-
origin: change.origin
|
|
201
|
-
}))
|
|
314
|
+
const configuration = []
|
|
202
315
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
316
|
+
for (const change of changes) {
|
|
317
|
+
const name = names[change.name] || change.name
|
|
318
|
+
const { origin, value } = change
|
|
319
|
+
const entry = { name, value, origin }
|
|
320
|
+
|
|
321
|
+
if (Array.isArray(value)) entry.value = value.join(',')
|
|
322
|
+
if (entry.name === 'DD_TAGS') entry.value = formatMapForTelemetry(entry.value)
|
|
323
|
+
if (entry.name === 'url' && entry.value) entry.value = entry.value.toString()
|
|
324
|
+
if (entry.name === 'peerServiceMapping' || entry.name === 'tags') entry.value = formatMapForTelemetry(entry.value)
|
|
325
|
+
|
|
326
|
+
configuration.push(entry)
|
|
327
|
+
}
|
|
328
|
+
if (!configWithOrigin.length) {
|
|
329
|
+
configWithOrigin = configuration
|
|
330
|
+
} else {
|
|
331
|
+
const { reqType, payload } = createPayload('app-client-configuration-change', { configuration })
|
|
332
|
+
sendData(config, application, host, reqType, payload, updateRetryData)
|
|
333
|
+
}
|
|
206
334
|
}
|
|
207
335
|
|
|
208
336
|
module.exports = {
|
|
209
337
|
start,
|
|
210
338
|
stop,
|
|
211
339
|
updateIntegrations,
|
|
212
|
-
updateConfig
|
|
340
|
+
updateConfig,
|
|
341
|
+
appClosing
|
|
213
342
|
}
|
|
@@ -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
|
|
|
@@ -54,7 +54,7 @@ function send (config, application, host) {
|
|
|
54
54
|
|
|
55
55
|
const logs = logCollector.drain()
|
|
56
56
|
if (logs) {
|
|
57
|
-
sendData(config, application, host, 'logs', logs)
|
|
57
|
+
sendData(config, application, host, 'logs', { logs })
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|