dd-trace 3.3.1 → 3.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +8 -0
- package/README.md +108 -43
- package/ci/init.js +6 -1
- package/ext/exporters.d.ts +2 -1
- package/ext/exporters.js +2 -1
- package/index.d.ts +129 -36
- package/package.json +18 -9
- package/packages/datadog-instrumentations/src/body-parser.js +26 -0
- package/packages/datadog-instrumentations/src/cassandra-driver.js +7 -7
- package/packages/datadog-instrumentations/src/child-process.js +30 -0
- package/packages/datadog-instrumentations/src/connect.js +15 -15
- package/packages/datadog-instrumentations/src/cucumber.js +1 -3
- package/packages/datadog-instrumentations/src/elasticsearch.js +51 -47
- package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +9 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +5 -0
- package/packages/datadog-instrumentations/src/http/server.js +20 -12
- package/packages/datadog-instrumentations/src/http2/server.js +67 -1
- package/packages/datadog-instrumentations/src/jest.js +182 -25
- package/packages/datadog-instrumentations/src/koa.js +32 -32
- package/packages/datadog-instrumentations/src/ldapjs.js +91 -0
- package/packages/datadog-instrumentations/src/mariadb.js +63 -0
- package/packages/datadog-instrumentations/src/memcached.js +1 -4
- package/packages/datadog-instrumentations/src/mocha.js +135 -24
- package/packages/datadog-instrumentations/src/next.js +10 -2
- package/packages/datadog-instrumentations/src/opensearch.js +10 -0
- package/packages/datadog-instrumentations/src/oracledb.js +8 -8
- package/packages/datadog-instrumentations/src/pg.js +7 -3
- package/packages/datadog-instrumentations/src/qs.js +24 -0
- package/packages/datadog-instrumentations/src/redis.js +12 -3
- package/packages/datadog-instrumentations/src/restify.js +5 -1
- package/packages/datadog-instrumentations/src/rhea.js +29 -15
- package/packages/datadog-instrumentations/src/router.js +23 -23
- package/packages/datadog-plugin-amqp10/src/consumer.js +32 -0
- package/packages/datadog-plugin-amqp10/src/index.js +11 -101
- package/packages/datadog-plugin-amqp10/src/producer.js +34 -0
- package/packages/datadog-plugin-amqp10/src/util.js +15 -0
- package/packages/datadog-plugin-amqplib/src/client.js +38 -0
- package/packages/datadog-plugin-amqplib/src/consumer.js +40 -0
- package/packages/datadog-plugin-amqplib/src/index.js +14 -102
- package/packages/datadog-plugin-amqplib/src/producer.js +37 -0
- package/packages/datadog-plugin-amqplib/src/util.js +14 -0
- package/packages/datadog-plugin-cassandra-driver/src/index.js +22 -60
- package/packages/datadog-plugin-cucumber/src/index.js +14 -33
- package/packages/datadog-plugin-cypress/src/plugin.js +2 -1
- package/packages/datadog-plugin-dns/src/index.js +16 -91
- package/packages/datadog-plugin-dns/src/lookup.js +40 -0
- package/packages/datadog-plugin-dns/src/lookup_service.js +24 -0
- package/packages/datadog-plugin-dns/src/resolve.js +24 -0
- package/packages/datadog-plugin-dns/src/reverse.js +21 -0
- package/packages/datadog-plugin-elasticsearch/src/index.js +24 -60
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +24 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +41 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +14 -99
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +33 -0
- package/packages/datadog-plugin-graphql/src/execute.js +73 -0
- package/packages/datadog-plugin-graphql/src/index.js +14 -176
- package/packages/datadog-plugin-graphql/src/parse.js +32 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +70 -76
- package/packages/datadog-plugin-graphql/src/validate.js +28 -0
- package/packages/datadog-plugin-grpc/src/client.js +46 -55
- package/packages/datadog-plugin-grpc/src/index.js +7 -24
- package/packages/datadog-plugin-grpc/src/server.js +50 -52
- package/packages/datadog-plugin-grpc/src/util.js +15 -14
- package/packages/datadog-plugin-http/src/client.js +15 -5
- package/packages/datadog-plugin-http/src/index.js +7 -22
- package/packages/datadog-plugin-http/src/server.js +19 -3
- package/packages/datadog-plugin-http2/src/client.js +20 -1
- package/packages/datadog-plugin-http2/src/index.js +8 -26
- package/packages/datadog-plugin-http2/src/server.js +44 -0
- package/packages/datadog-plugin-jest/src/index.js +41 -65
- package/packages/datadog-plugin-kafkajs/src/consumer.js +42 -0
- package/packages/datadog-plugin-kafkajs/src/index.js +11 -87
- package/packages/datadog-plugin-kafkajs/src/producer.js +31 -0
- package/packages/datadog-plugin-mariadb/src/index.js +10 -0
- package/packages/datadog-plugin-memcached/src/index.js +17 -52
- package/packages/datadog-plugin-mocha/src/index.js +40 -60
- package/packages/datadog-plugin-moleculer/src/client.js +22 -36
- package/packages/datadog-plugin-moleculer/src/index.js +8 -26
- package/packages/datadog-plugin-moleculer/src/server.js +18 -30
- package/packages/datadog-plugin-mongodb-core/src/index.js +23 -51
- package/packages/datadog-plugin-mysql/src/index.js +23 -52
- package/packages/datadog-plugin-mysql2/src/index.js +1 -3
- package/packages/datadog-plugin-net/src/index.js +4 -0
- package/packages/datadog-plugin-net/src/ipc.js +21 -0
- package/packages/datadog-plugin-net/src/tcp.js +46 -0
- package/packages/datadog-plugin-next/src/index.js +3 -0
- package/packages/datadog-plugin-opensearch/src/index.js +11 -0
- package/packages/datadog-plugin-oracledb/src/index.js +29 -55
- package/packages/datadog-plugin-pg/src/index.js +27 -51
- package/packages/datadog-plugin-redis/src/index.js +29 -60
- package/packages/datadog-plugin-rhea/src/consumer.js +55 -0
- package/packages/datadog-plugin-rhea/src/index.js +11 -96
- package/packages/datadog-plugin-rhea/src/producer.js +45 -0
- package/packages/datadog-plugin-router/src/index.js +13 -2
- package/packages/datadog-plugin-sharedb/src/index.js +22 -39
- package/packages/datadog-plugin-tedious/src/index.js +20 -41
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/blocking.js +44 -0
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +8 -6
- package/packages/dd-trace/src/appsec/gateway/engine/engine.js +1 -1
- package/packages/dd-trace/src/appsec/gateway/engine/index.js +7 -2
- package/packages/dd-trace/src/appsec/gateway/engine/runner.js +0 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +4 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +11 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/injection-analyzer.js +19 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/ldap-injection-analyzer.js +11 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +13 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +43 -5
- package/packages/dd-trace/src/appsec/iast/iast-context.js +3 -1
- package/packages/dd-trace/src/appsec/iast/index.js +24 -8
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +20 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +17 -6
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +17 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +16 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +18 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +98 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/origin-types.js +4 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +38 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +67 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +103 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +98 -30
- package/packages/dd-trace/src/appsec/index.js +79 -25
- package/packages/dd-trace/src/{plugins/util → appsec}/ip_blocklist.js +0 -0
- package/packages/dd-trace/src/appsec/ip_extractor.js +98 -0
- package/packages/dd-trace/src/appsec/recommended.json +134 -53
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -0
- package/packages/dd-trace/src/appsec/remote_config/index.js +56 -0
- package/packages/dd-trace/src/appsec/remote_config/manager.js +264 -0
- package/packages/dd-trace/src/{exporters → appsec/remote_config}/scheduler.js +9 -9
- package/packages/dd-trace/src/appsec/rule_manager.js +61 -1
- package/packages/dd-trace/src/appsec/templates/blocked.html +99 -0
- package/packages/dd-trace/src/appsec/templates/blocked.json +8 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +66 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +9 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +19 -51
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +10 -5
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +202 -0
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +51 -62
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +89 -0
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +82 -0
- package/packages/dd-trace/src/config.js +119 -35
- package/packages/dd-trace/src/constants.js +9 -1
- package/packages/dd-trace/src/dogstatsd.js +42 -10
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +10 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +0 -1
- package/packages/dd-trace/src/exporter.js +3 -0
- package/packages/dd-trace/src/exporters/agent/index.js +10 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +2 -9
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +82 -0
- package/packages/dd-trace/src/exporters/common/request.js +51 -1
- package/packages/dd-trace/src/exporters/span-stats/index.js +6 -2
- package/packages/dd-trace/src/format.js +29 -10
- package/packages/dd-trace/src/lambda/handler.js +72 -0
- package/packages/dd-trace/src/lambda/index.js +5 -0
- package/packages/dd-trace/src/lambda/runtime/errors.js +20 -0
- package/packages/dd-trace/src/lambda/runtime/patch.js +74 -0
- package/packages/dd-trace/src/lambda/runtime/ritm.js +138 -0
- package/packages/dd-trace/src/metrics.js +15 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -5
- package/packages/dd-trace/src/opentracing/span.js +2 -1
- package/packages/dd-trace/src/opentracing/span_context.js +9 -0
- package/packages/dd-trace/src/plugin_manager.js +11 -17
- package/packages/dd-trace/src/plugins/cache.js +9 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +97 -0
- package/packages/dd-trace/src/plugins/client.js +9 -0
- package/packages/dd-trace/src/plugins/composite.js +26 -0
- package/packages/dd-trace/src/plugins/consumer.js +9 -0
- package/packages/dd-trace/src/plugins/database.js +55 -0
- package/packages/dd-trace/src/plugins/incoming.js +7 -0
- package/packages/dd-trace/src/plugins/index.js +3 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +2 -2
- package/packages/dd-trace/src/plugins/outgoing.js +31 -0
- package/packages/dd-trace/src/plugins/plugin.js +3 -0
- package/packages/dd-trace/src/plugins/producer.js +9 -0
- package/packages/dd-trace/src/plugins/server.js +9 -0
- package/packages/dd-trace/src/plugins/storage.js +21 -0
- package/packages/dd-trace/src/plugins/tracing.js +94 -0
- package/packages/dd-trace/src/plugins/util/ci.js +40 -4
- package/packages/dd-trace/src/plugins/util/git.js +58 -18
- package/packages/dd-trace/src/plugins/util/test.js +71 -8
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +14 -1
- package/packages/dd-trace/src/plugins/util/web.js +11 -114
- package/packages/dd-trace/src/priority_sampler.js +6 -2
- package/packages/dd-trace/src/profiling/config.js +11 -6
- package/packages/dd-trace/src/profiling/exporters/agent.js +4 -0
- package/packages/dd-trace/src/profiling/index.js +2 -2
- package/packages/dd-trace/src/profiling/profiler.js +43 -7
- package/packages/dd-trace/src/proxy.js +8 -16
- package/packages/dd-trace/src/ritm.js +25 -14
- package/packages/dd-trace/src/span_processor.js +17 -0
- package/packages/dd-trace/src/span_sampler.js +77 -0
- package/packages/dd-trace/src/span_stats.js +2 -2
- package/packages/dd-trace/src/telemetry/dependencies.js +21 -7
- package/packages/dd-trace/src/telemetry/index.js +7 -1
- package/packages/dd-trace/src/telemetry/send-data.js +3 -1
- package/packages/dd-trace/src/tracer.js +10 -5
- package/packages/dd-trace/src/util.js +43 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const coalesce = require('koalas')
|
|
4
4
|
const os = require('os')
|
|
5
|
-
const { URL } = require('url')
|
|
5
|
+
const { URL, format } = require('url')
|
|
6
6
|
const { AgentExporter } = require('./exporters/agent')
|
|
7
7
|
const { FileExporter } = require('./exporters/file')
|
|
8
8
|
const { ConsoleLogger } = require('./loggers/console')
|
|
@@ -33,6 +33,7 @@ class Config {
|
|
|
33
33
|
const service = options.service || DD_SERVICE || 'node'
|
|
34
34
|
const host = os.hostname()
|
|
35
35
|
const version = coalesce(options.version, DD_VERSION)
|
|
36
|
+
const functionname = process.env.AWS_LAMBDA_FUNCTION_NAME
|
|
36
37
|
// Must be longer than one minute so pad with five seconds
|
|
37
38
|
const flushInterval = coalesce(options.interval, 65 * 1000)
|
|
38
39
|
const uploadTimeout = coalesce(options.uploadTimeout,
|
|
@@ -46,12 +47,13 @@ class Config {
|
|
|
46
47
|
this.service = service
|
|
47
48
|
this.env = env
|
|
48
49
|
this.host = host
|
|
50
|
+
this.functionname = functionname
|
|
49
51
|
|
|
50
52
|
this.version = version
|
|
51
53
|
this.tags = Object.assign(
|
|
52
54
|
tagger.parse(DD_TAGS),
|
|
53
55
|
tagger.parse(options.tags),
|
|
54
|
-
tagger.parse({ env, host, service, version })
|
|
56
|
+
tagger.parse({ env, host, service, version, functionname })
|
|
55
57
|
)
|
|
56
58
|
this.logger = ensureLogger(options.logger)
|
|
57
59
|
this.flushInterval = flushInterval
|
|
@@ -59,10 +61,13 @@ class Config {
|
|
|
59
61
|
this.sourceMap = sourceMap
|
|
60
62
|
this.endpointCollection = endpointCollection
|
|
61
63
|
|
|
62
|
-
const hostname = coalesce(options.hostname, DD_AGENT_HOST
|
|
63
|
-
const port = coalesce(options.port, DD_TRACE_AGENT_PORT
|
|
64
|
-
this.url = new URL(coalesce(options.url, DD_TRACE_AGENT_URL,
|
|
65
|
-
|
|
64
|
+
const hostname = coalesce(options.hostname, DD_AGENT_HOST) || 'localhost'
|
|
65
|
+
const port = coalesce(options.port, DD_TRACE_AGENT_PORT) || 8126
|
|
66
|
+
this.url = new URL(coalesce(options.url, DD_TRACE_AGENT_URL, format({
|
|
67
|
+
protocol: 'http:',
|
|
68
|
+
hostname,
|
|
69
|
+
port
|
|
70
|
+
})))
|
|
66
71
|
|
|
67
72
|
this.exporters = ensureExporters(options.exporters || [
|
|
68
73
|
new AgentExporter(this)
|
|
@@ -6,11 +6,14 @@ const { request } = require('http')
|
|
|
6
6
|
// TODO: avoid using dd-trace internals. Make this a separate module?
|
|
7
7
|
const docker = require('../../exporters/common/docker')
|
|
8
8
|
const FormData = require('../../exporters/common/form-data')
|
|
9
|
+
const { storage } = require('../../../../datadog-core')
|
|
9
10
|
const version = require('../../../../../package.json').version
|
|
10
11
|
|
|
11
12
|
const containerId = docker.id()
|
|
12
13
|
|
|
13
14
|
function sendRequest (options, form, callback) {
|
|
15
|
+
const store = storage.getStore()
|
|
16
|
+
storage.enterWith({ noop: true })
|
|
14
17
|
const req = request(options, res => {
|
|
15
18
|
if (res.statusCode >= 400) {
|
|
16
19
|
const error = new Error(`HTTP Error ${res.statusCode}`)
|
|
@@ -22,6 +25,7 @@ function sendRequest (options, form, callback) {
|
|
|
22
25
|
})
|
|
23
26
|
req.on('error', callback)
|
|
24
27
|
if (form) form.pipe(req)
|
|
28
|
+
storage.enterWith(store)
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
function getBody (stream, callback) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { Profiler } = require('./profiler')
|
|
3
|
+
const { Profiler, ServerlessProfiler } = require('./profiler')
|
|
4
4
|
const CpuProfiler = require('./profilers/cpu')
|
|
5
5
|
const WallProfiler = require('./profilers/wall')
|
|
6
6
|
const SpaceProfiler = require('./profilers/space')
|
|
@@ -8,7 +8,7 @@ const { AgentExporter } = require('./exporters/agent')
|
|
|
8
8
|
const { FileExporter } = require('./exporters/file')
|
|
9
9
|
const { ConsoleLogger } = require('./loggers/console')
|
|
10
10
|
|
|
11
|
-
const profiler = new Profiler()
|
|
11
|
+
const profiler = process.env.AWS_LAMBDA_FUNCTION_NAME ? new ServerlessProfiler() : new Profiler()
|
|
12
12
|
|
|
13
13
|
module.exports = {
|
|
14
14
|
profiler,
|
|
@@ -5,7 +5,6 @@ const { Config } = require('./config')
|
|
|
5
5
|
|
|
6
6
|
function maybeSourceMap (sourceMap) {
|
|
7
7
|
if (!sourceMap) return
|
|
8
|
-
|
|
9
8
|
const { SourceMapper } = require('@datadog/pprof')
|
|
10
9
|
return SourceMapper.create([
|
|
11
10
|
process.cwd()
|
|
@@ -20,6 +19,7 @@ class Profiler extends EventEmitter {
|
|
|
20
19
|
this._config = undefined
|
|
21
20
|
this._timer = undefined
|
|
22
21
|
this._lastStart = undefined
|
|
22
|
+
this._timeoutInterval = undefined
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
start (options) {
|
|
@@ -35,23 +35,35 @@ class Profiler extends EventEmitter {
|
|
|
35
35
|
|
|
36
36
|
this._logger = config.logger
|
|
37
37
|
this._enabled = true
|
|
38
|
+
this._setInterval()
|
|
38
39
|
|
|
40
|
+
// Log errors if the source map finder fails, but don't prevent the rest
|
|
41
|
+
// of the profiler from running without source maps.
|
|
42
|
+
let mapper
|
|
39
43
|
try {
|
|
40
|
-
|
|
44
|
+
mapper = await maybeSourceMap(config.sourceMap)
|
|
45
|
+
} catch (err) {
|
|
46
|
+
this._logger.error(err)
|
|
47
|
+
}
|
|
41
48
|
|
|
49
|
+
try {
|
|
42
50
|
for (const profiler of config.profilers) {
|
|
43
51
|
// TODO: move this out of Profiler when restoring sourcemap support
|
|
44
52
|
profiler.start({ mapper })
|
|
45
53
|
this._logger.debug(`Started ${profiler.type} profiler`)
|
|
46
54
|
}
|
|
47
55
|
|
|
48
|
-
this._capture(
|
|
56
|
+
this._capture(this._timeoutInterval)
|
|
49
57
|
} catch (e) {
|
|
50
58
|
this._logger.error(e)
|
|
51
59
|
this.stop()
|
|
52
60
|
}
|
|
53
61
|
}
|
|
54
62
|
|
|
63
|
+
_setInterval () {
|
|
64
|
+
this._timeoutInterval = this._config.flushInterval
|
|
65
|
+
}
|
|
66
|
+
|
|
55
67
|
stop () {
|
|
56
68
|
if (!this._enabled) return
|
|
57
69
|
|
|
@@ -71,8 +83,7 @@ class Profiler extends EventEmitter {
|
|
|
71
83
|
_capture (timeout) {
|
|
72
84
|
if (!this._enabled) return
|
|
73
85
|
this._lastStart = new Date()
|
|
74
|
-
|
|
75
|
-
if (!this._timer || timeout !== this._config.flushInterval) {
|
|
86
|
+
if (!this._timer || timeout !== this._timeoutInterval) {
|
|
76
87
|
this._timer = setTimeout(() => this._collect(), timeout)
|
|
77
88
|
this._timer.unref()
|
|
78
89
|
} else {
|
|
@@ -99,7 +110,7 @@ class Profiler extends EventEmitter {
|
|
|
99
110
|
})
|
|
100
111
|
}
|
|
101
112
|
|
|
102
|
-
this._capture(this.
|
|
113
|
+
this._capture(this._timeoutInterval)
|
|
103
114
|
await this._submit(profiles, start, end)
|
|
104
115
|
this._logger.debug('Submitted profiles')
|
|
105
116
|
} catch (err) {
|
|
@@ -126,4 +137,29 @@ class Profiler extends EventEmitter {
|
|
|
126
137
|
}
|
|
127
138
|
}
|
|
128
139
|
|
|
129
|
-
|
|
140
|
+
class ServerlessProfiler extends Profiler {
|
|
141
|
+
constructor () {
|
|
142
|
+
super()
|
|
143
|
+
this._profiledIntervals = 0
|
|
144
|
+
this._interval = 1
|
|
145
|
+
this._flushAfterIntervals = undefined
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
_setInterval () {
|
|
149
|
+
this._timeoutInterval = this._interval * 1000
|
|
150
|
+
this._flushAfterIntervals = this._config.flushInterval / 1000
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async _collect () {
|
|
154
|
+
if (this._profiledIntervals >= this._flushAfterIntervals) {
|
|
155
|
+
this._profiledIntervals = 0
|
|
156
|
+
await super._collect()
|
|
157
|
+
} else {
|
|
158
|
+
this._profiledIntervals += 1
|
|
159
|
+
this._capture(this._timeoutInterval)
|
|
160
|
+
// Don't submit profile until 65 (flushAfterIntervals) intervals have elapsed
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = { Profiler, ServerlessProfiler }
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
|
|
3
2
|
const NoopProxy = require('./noop/proxy')
|
|
4
3
|
const DatadogTracer = require('./tracer')
|
|
5
4
|
const Config = require('./config')
|
|
@@ -8,7 +7,7 @@ const log = require('./log')
|
|
|
8
7
|
const { setStartupLogPluginManager } = require('./startup-log')
|
|
9
8
|
const telemetry = require('./telemetry')
|
|
10
9
|
const PluginManager = require('./plugin_manager')
|
|
11
|
-
const
|
|
10
|
+
const remoteConfig = require('./appsec/remote_config')
|
|
12
11
|
|
|
13
12
|
class Tracer extends NoopProxy {
|
|
14
13
|
constructor () {
|
|
@@ -26,8 +25,9 @@ class Tracer extends NoopProxy {
|
|
|
26
25
|
try {
|
|
27
26
|
const config = new Config(options) // TODO: support dynamic config
|
|
28
27
|
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
if (config.remoteConfig.enabled && !config.isCiVisibility) {
|
|
29
|
+
remoteConfig.enable(config)
|
|
30
|
+
}
|
|
31
31
|
|
|
32
32
|
if (config.profiling.enabled) {
|
|
33
33
|
// do not stop tracer initialization if the profiler fails to be imported
|
|
@@ -48,25 +48,17 @@ class Tracer extends NoopProxy {
|
|
|
48
48
|
if (config.appsec.enabled) {
|
|
49
49
|
require('./appsec').enable(config)
|
|
50
50
|
}
|
|
51
|
+
|
|
52
|
+
this._tracer = new DatadogTracer(config)
|
|
53
|
+
|
|
51
54
|
if (config.iast.enabled) {
|
|
52
|
-
require('./appsec/iast').enable(config)
|
|
55
|
+
require('./appsec/iast').enable(config, this._tracer)
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
this._tracer = new DatadogTracer(config)
|
|
56
58
|
this._pluginManager.configure(config)
|
|
57
59
|
setStartupLogPluginManager(this._pluginManager)
|
|
58
60
|
telemetry.start(config, this._pluginManager)
|
|
59
61
|
}
|
|
60
|
-
|
|
61
|
-
if (config.isGitUploadEnabled) {
|
|
62
|
-
sendGitMetadata(config.site, (err) => {
|
|
63
|
-
if (err) {
|
|
64
|
-
log.error(`Error uploading git metadata: ${err}`)
|
|
65
|
-
} else {
|
|
66
|
-
log.debug('Successfully uploaded git metadata')
|
|
67
|
-
}
|
|
68
|
-
})
|
|
69
|
-
}
|
|
70
62
|
} catch (e) {
|
|
71
63
|
log.error(e)
|
|
72
64
|
}
|
|
@@ -16,6 +16,8 @@ let cache = Object.create(null)
|
|
|
16
16
|
let patching = Object.create(null)
|
|
17
17
|
let patchedRequire = null
|
|
18
18
|
const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart')
|
|
19
|
+
const moduleLoadEndChannel = dc.channel('dd-trace:moduleLoadEnd')
|
|
20
|
+
|
|
19
21
|
function Hook (modules, options, onrequire) {
|
|
20
22
|
if (!(this instanceof Hook)) return new Hook(modules, options, onrequire)
|
|
21
23
|
if (typeof modules === 'function') {
|
|
@@ -52,7 +54,6 @@ function Hook (modules, options, onrequire) {
|
|
|
52
54
|
const filename = Module._resolveFilename(request, this)
|
|
53
55
|
const core = filename.indexOf(path.sep) === -1
|
|
54
56
|
let name, basedir, hooks
|
|
55
|
-
|
|
56
57
|
// return known patched modules immediately
|
|
57
58
|
if (cache[filename]) {
|
|
58
59
|
// require.cache was potentially altered externally
|
|
@@ -66,33 +67,43 @@ function Hook (modules, options, onrequire) {
|
|
|
66
67
|
// Check if this module has a patcher in-progress already.
|
|
67
68
|
// Otherwise, mark this module as patching in-progress.
|
|
68
69
|
const patched = patching[filename]
|
|
69
|
-
if (
|
|
70
|
+
if (patched) {
|
|
71
|
+
// If it's already patched, just return it as-is.
|
|
72
|
+
return origRequire.apply(this, arguments)
|
|
73
|
+
} else {
|
|
70
74
|
patching[filename] = true
|
|
71
75
|
}
|
|
72
76
|
|
|
73
|
-
const
|
|
77
|
+
const payload = {
|
|
78
|
+
filename,
|
|
79
|
+
request
|
|
80
|
+
}
|
|
74
81
|
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
if (moduleLoadStartChannel.hasSubscribers) {
|
|
83
|
+
moduleLoadStartChannel.publish(payload)
|
|
84
|
+
}
|
|
85
|
+
const exports = origRequire.apply(this, arguments)
|
|
86
|
+
payload.module = exports
|
|
87
|
+
if (moduleLoadEndChannel.hasSubscribers) {
|
|
88
|
+
moduleLoadEndChannel.publish(payload)
|
|
89
|
+
}
|
|
77
90
|
|
|
78
91
|
// The module has already been loaded,
|
|
79
92
|
// so the patching mark can be cleaned up.
|
|
80
93
|
delete patching[filename]
|
|
81
94
|
|
|
82
|
-
if (moduleLoadStartChannel.hasSubscribers) {
|
|
83
|
-
moduleLoadStartChannel.publish({
|
|
84
|
-
filename,
|
|
85
|
-
module: exports,
|
|
86
|
-
request
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
|
|
90
95
|
if (core) {
|
|
91
96
|
hooks = moduleHooks[filename]
|
|
92
97
|
if (!hooks) return exports // abort if module name isn't on whitelist
|
|
93
98
|
name = filename
|
|
94
99
|
} else {
|
|
95
|
-
const
|
|
100
|
+
const inAWSLambda = process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined
|
|
101
|
+
const hasLambdaHandler = process.env.DD_LAMBDA_HANDLER !== undefined
|
|
102
|
+
const segments = filename.split(path.sep)
|
|
103
|
+
const filenameFromNodeModule = segments.lastIndexOf('node_modules') !== -1
|
|
104
|
+
// decide how to assign the stat
|
|
105
|
+
// first case will only happen when patching an AWS Lambda Handler
|
|
106
|
+
const stat = inAWSLambda && hasLambdaHandler && !filenameFromNodeModule ? { name: filename } : parse(filename)
|
|
96
107
|
if (!stat) return exports // abort if filename could not be parsed
|
|
97
108
|
name = stat.name
|
|
98
109
|
basedir = stat.basedir
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const log = require('./log')
|
|
4
4
|
const format = require('./format')
|
|
5
|
+
const SpanSampler = require('./span_sampler')
|
|
5
6
|
|
|
6
7
|
const { SpanStatsProcessor } = require('./span_stats')
|
|
7
8
|
|
|
@@ -13,8 +14,10 @@ class SpanProcessor {
|
|
|
13
14
|
this._exporter = exporter
|
|
14
15
|
this._prioritySampler = prioritySampler
|
|
15
16
|
this._config = config
|
|
17
|
+
this._killAll = false
|
|
16
18
|
|
|
17
19
|
this._stats = new SpanStatsProcessor(config)
|
|
20
|
+
this._spanSampler = new SpanSampler(config)
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
process (span) {
|
|
@@ -25,8 +28,10 @@ class SpanProcessor {
|
|
|
25
28
|
const { flushMinSpans } = this._config
|
|
26
29
|
const { started, finished } = trace
|
|
27
30
|
|
|
31
|
+
if (trace.record === false) return
|
|
28
32
|
if (started.length === finished.length || finished.length >= flushMinSpans) {
|
|
29
33
|
this._prioritySampler.sample(spanContext)
|
|
34
|
+
this._spanSampler.sample(spanContext)
|
|
30
35
|
|
|
31
36
|
for (const span of started) {
|
|
32
37
|
if (span._duration !== undefined) {
|
|
@@ -44,6 +49,18 @@ class SpanProcessor {
|
|
|
44
49
|
|
|
45
50
|
this._erase(trace, active)
|
|
46
51
|
}
|
|
52
|
+
|
|
53
|
+
if (this._killAll) {
|
|
54
|
+
started.map(startedSpan => {
|
|
55
|
+
if (!startedSpan._finished) {
|
|
56
|
+
startedSpan.finish()
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
killAll () {
|
|
63
|
+
this._killAll = true
|
|
47
64
|
}
|
|
48
65
|
|
|
49
66
|
_erase (trace, active) {
|
|
@@ -0,0 +1,77 @@
|
|
|
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
|
+
|
|
6
|
+
class SpanSampler {
|
|
7
|
+
constructor ({ spanSamplingRules = [] }) {
|
|
8
|
+
this._rules = spanSamplingRules
|
|
9
|
+
this._limiters = {}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
sample (spanContext) {
|
|
13
|
+
const decision = spanContext._sampling.priority
|
|
14
|
+
if (decision === USER_KEEP || decision === AUTO_KEEP) return
|
|
15
|
+
|
|
16
|
+
const { started } = spanContext._trace
|
|
17
|
+
for (const span of started) {
|
|
18
|
+
const service = span.tracer()._service
|
|
19
|
+
const name = span._name
|
|
20
|
+
const rule = findRule(this._rules, service, name)
|
|
21
|
+
if (!rule) continue
|
|
22
|
+
|
|
23
|
+
const sampleRate = getSampleRate(rule.sampleRate)
|
|
24
|
+
const maxPerSecond = getMaxPerSecond(rule.maxPerSecond)
|
|
25
|
+
const sampled = sample(sampleRate)
|
|
26
|
+
if (!sampled) continue
|
|
27
|
+
|
|
28
|
+
const key = `${service}:${name}`
|
|
29
|
+
const limiter = getLimiter(this._limiters, key, maxPerSecond)
|
|
30
|
+
if (limiter.isAllowed()) {
|
|
31
|
+
span.context()._sampling.spanSampling = {
|
|
32
|
+
sampleRate,
|
|
33
|
+
maxPerSecond
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function findRule (rules, service, name) {
|
|
41
|
+
for (const rule of rules) {
|
|
42
|
+
const servicePattern = getService(rule.service)
|
|
43
|
+
const namePattern = getName(rule.name)
|
|
44
|
+
if (globMatch(servicePattern, service) && globMatch(namePattern, name)) {
|
|
45
|
+
return rule
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getLimiter (list, key, maxPerSecond) {
|
|
51
|
+
if (typeof list[key] === 'undefined') {
|
|
52
|
+
list[key] = new RateLimiter(maxPerSecond)
|
|
53
|
+
}
|
|
54
|
+
return list[key]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function sample (sampleRate) {
|
|
58
|
+
return Math.random() < sampleRate
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getService (service) {
|
|
62
|
+
return service || '*'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getName (name) {
|
|
66
|
+
return name || '*'
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function getSampleRate (sampleRate) {
|
|
70
|
+
return sampleRate || 1.0
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function getMaxPerSecond (maxPerSecond) {
|
|
74
|
+
return maxPerSecond || Infinity
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = SpanSampler
|
|
@@ -65,8 +65,8 @@ class SpanAggStats {
|
|
|
65
65
|
TopLevelHits: this.topLevelHits,
|
|
66
66
|
Errors: this.errors,
|
|
67
67
|
Duration: this.duration,
|
|
68
|
-
OkSummary: this.okDistribution.toProto(),
|
|
69
|
-
ErrorSummary: this.errorDistribution.toProto()
|
|
68
|
+
OkSummary: this.okDistribution.toProto(), // TODO: custom proto encoding
|
|
69
|
+
ErrorSummary: this.errorDistribution.toProto() // TODO: custom proto encoding
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
}
|
|
@@ -7,7 +7,7 @@ const { sendData } = require('./send-data')
|
|
|
7
7
|
const dc = require('diagnostics_channel')
|
|
8
8
|
const { fileURLToPath } = require('url')
|
|
9
9
|
|
|
10
|
-
const savedDependencies =
|
|
10
|
+
const savedDependencies = new Set()
|
|
11
11
|
const detectedDependencyNames = new Set()
|
|
12
12
|
const FILE_URI_START = `file://`
|
|
13
13
|
const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart')
|
|
@@ -18,10 +18,14 @@ function waitAndSend (config, application, host) {
|
|
|
18
18
|
if (!immediate) {
|
|
19
19
|
immediate = setImmediate(() => {
|
|
20
20
|
immediate = null
|
|
21
|
-
if (savedDependencies.
|
|
22
|
-
const dependencies = savedDependencies.splice(0, 1000)
|
|
21
|
+
if (savedDependencies.size > 0) {
|
|
22
|
+
const dependencies = Array.from(savedDependencies.values()).splice(0, 1000).map(pair => {
|
|
23
|
+
savedDependencies.delete(pair)
|
|
24
|
+
const [name, version] = pair.split(' ')
|
|
25
|
+
return { name, version }
|
|
26
|
+
})
|
|
23
27
|
sendData(config, application, host, 'app-dependencies-loaded', { dependencies })
|
|
24
|
-
if (savedDependencies.
|
|
28
|
+
if (savedDependencies.size > 0) {
|
|
25
29
|
waitAndSend(config, application, host)
|
|
26
30
|
}
|
|
27
31
|
}
|
|
@@ -49,7 +53,7 @@ function onModuleLoad (data) {
|
|
|
49
53
|
if (basedir) {
|
|
50
54
|
try {
|
|
51
55
|
const { version } = requirePackageJson(basedir, module)
|
|
52
|
-
savedDependencies.
|
|
56
|
+
savedDependencies.add(`${name} ${version}`)
|
|
53
57
|
waitAndSend(config, application, host)
|
|
54
58
|
} catch (e) {
|
|
55
59
|
// can not read the package.json, do nothing
|
|
@@ -67,7 +71,17 @@ function start (_config, _application, _host) {
|
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
function isDependency (filename, request) {
|
|
70
|
-
|
|
74
|
+
const isDependencyWithSlash = isDependencyWithSeparator(filename, request, '/')
|
|
75
|
+
if (isDependencyWithSlash && process.platform === 'win32') {
|
|
76
|
+
return isDependencyWithSeparator(filename, request, path.sep)
|
|
77
|
+
}
|
|
78
|
+
return isDependencyWithSlash
|
|
79
|
+
}
|
|
80
|
+
function isDependencyWithSeparator (filename, request, sep) {
|
|
81
|
+
return request.indexOf(`..${sep}`) !== 0 &&
|
|
82
|
+
request.indexOf(`.${sep}`) !== 0 &&
|
|
83
|
+
request.indexOf(sep) !== 0 &&
|
|
84
|
+
request.indexOf(`:${sep}`) !== 1
|
|
71
85
|
}
|
|
72
86
|
|
|
73
87
|
function stop () {
|
|
@@ -75,7 +89,7 @@ function stop () {
|
|
|
75
89
|
application = null
|
|
76
90
|
host = null
|
|
77
91
|
detectedDependencyNames.clear()
|
|
78
|
-
savedDependencies.
|
|
92
|
+
savedDependencies.clear()
|
|
79
93
|
if (moduleLoadStartChannel.hasSubscribers) {
|
|
80
94
|
moduleLoadStartChannel.unsubscribe(onModuleLoad)
|
|
81
95
|
}
|
|
@@ -6,6 +6,10 @@ const os = require('os')
|
|
|
6
6
|
const dependencies = require('./dependencies')
|
|
7
7
|
const { sendData } = require('./send-data')
|
|
8
8
|
|
|
9
|
+
const HEARTBEAT_INTERVAL = process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL
|
|
10
|
+
? Number(process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL) * 1000
|
|
11
|
+
: 60000
|
|
12
|
+
|
|
9
13
|
let config
|
|
10
14
|
let pluginManager
|
|
11
15
|
|
|
@@ -88,7 +92,9 @@ function start (aConfig, thePluginManager) {
|
|
|
88
92
|
host = createHostObject()
|
|
89
93
|
dependencies.start(config, application, host)
|
|
90
94
|
sendData(config, application, host, 'app-started', appStarted())
|
|
91
|
-
interval = setInterval(() =>
|
|
95
|
+
interval = setInterval(() => {
|
|
96
|
+
sendData(config, application, host, 'app-heartbeat')
|
|
97
|
+
}, HEARTBEAT_INTERVAL)
|
|
92
98
|
interval.unref()
|
|
93
99
|
process.on('beforeExit', onBeforeExit)
|
|
94
100
|
}
|
|
@@ -6,6 +6,7 @@ const Scope = require('./scope')
|
|
|
6
6
|
const { storage } = require('../../datadog-core')
|
|
7
7
|
const { isError } = require('./util')
|
|
8
8
|
const { setStartupLogConfig } = require('./startup-log')
|
|
9
|
+
const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
|
|
9
10
|
|
|
10
11
|
const SPAN_TYPE = tags.SPAN_TYPE
|
|
11
12
|
const RESOURCE_NAME = tags.RESOURCE_NAME
|
|
@@ -44,11 +45,15 @@ class DatadogTracer extends Tracer {
|
|
|
44
45
|
const result = this.scope().activate(span, () => fn(span))
|
|
45
46
|
|
|
46
47
|
if (result && typeof result.then === 'function') {
|
|
47
|
-
result.then(
|
|
48
|
-
|
|
48
|
+
return result.then(
|
|
49
|
+
value => {
|
|
50
|
+
span.finish()
|
|
51
|
+
return value
|
|
52
|
+
},
|
|
49
53
|
err => {
|
|
50
54
|
addError(span, err)
|
|
51
55
|
span.finish()
|
|
56
|
+
throw err
|
|
52
57
|
}
|
|
53
58
|
)
|
|
54
59
|
} else {
|
|
@@ -139,9 +144,9 @@ class DatadogTracer extends Tracer {
|
|
|
139
144
|
function addError (span, error) {
|
|
140
145
|
if (isError(error)) {
|
|
141
146
|
span.addTags({
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
[ERROR_TYPE]: error.name,
|
|
148
|
+
[ERROR_MESSAGE]: error.message,
|
|
149
|
+
[ERROR_STACK]: error.stack
|
|
145
150
|
})
|
|
146
151
|
}
|
|
147
152
|
}
|
|
@@ -20,8 +20,50 @@ function isError (value) {
|
|
|
20
20
|
return false
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
// Matches a glob pattern to a given subject string
|
|
24
|
+
function globMatch (pattern, subject) {
|
|
25
|
+
let px = 0 // [p]attern inde[x]
|
|
26
|
+
let sx = 0 // [s]ubject inde[x]
|
|
27
|
+
let nextPx = 0
|
|
28
|
+
let nextSx = 0
|
|
29
|
+
while (px < pattern.length || sx < subject.length) {
|
|
30
|
+
if (px < pattern.length) {
|
|
31
|
+
const c = pattern[px]
|
|
32
|
+
switch (c) {
|
|
33
|
+
default: // ordinary character
|
|
34
|
+
if (sx < subject.length && subject[sx] === c) {
|
|
35
|
+
px++
|
|
36
|
+
sx++
|
|
37
|
+
continue
|
|
38
|
+
}
|
|
39
|
+
break
|
|
40
|
+
case '?':
|
|
41
|
+
if (sx < subject.length) {
|
|
42
|
+
px++
|
|
43
|
+
sx++
|
|
44
|
+
continue
|
|
45
|
+
}
|
|
46
|
+
break
|
|
47
|
+
case '*':
|
|
48
|
+
nextPx = px
|
|
49
|
+
nextSx = sx + 1
|
|
50
|
+
px++
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (nextSx > 0 && nextSx <= subject.length) {
|
|
55
|
+
px = nextPx
|
|
56
|
+
sx = nextSx
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
return false
|
|
60
|
+
}
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
|
|
23
64
|
module.exports = {
|
|
24
65
|
isTrue,
|
|
25
66
|
isFalse,
|
|
26
|
-
isError
|
|
67
|
+
isError,
|
|
68
|
+
globMatch
|
|
27
69
|
}
|