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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const lookup = require('dns').lookup // cache to avoid instrumentation
|
|
4
|
+
const request = require('./exporters/common/request')
|
|
4
5
|
const dgram = require('dgram')
|
|
5
6
|
const isIP = require('net').isIP
|
|
6
7
|
const log = require('./log')
|
|
@@ -11,6 +12,13 @@ class Client {
|
|
|
11
12
|
constructor (options) {
|
|
12
13
|
options = options || {}
|
|
13
14
|
|
|
15
|
+
if (options.metricsProxyUrl) {
|
|
16
|
+
this._httpOptions = {
|
|
17
|
+
url: options.metricsProxyUrl.toString(),
|
|
18
|
+
path: '/dogstatsd/v2/proxy'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
this._host = options.host || 'localhost'
|
|
15
23
|
this._family = isIP(this._host)
|
|
16
24
|
this._port = options.port || 8125
|
|
@@ -38,26 +46,50 @@ class Client {
|
|
|
38
46
|
|
|
39
47
|
this._queue = []
|
|
40
48
|
|
|
49
|
+
if (this._httpOptions) {
|
|
50
|
+
this._sendHttp(queue)
|
|
51
|
+
} else {
|
|
52
|
+
this._sendUdp(queue)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_sendHttp (queue) {
|
|
57
|
+
const buffer = Buffer.concat(queue)
|
|
58
|
+
request(buffer, this._httpOptions, (err) => {
|
|
59
|
+
if (err) {
|
|
60
|
+
log.error('HTTP error from agent: ' + err.stack)
|
|
61
|
+
if (err.status) {
|
|
62
|
+
// Inside this if-block, we have connectivity to the agent, but
|
|
63
|
+
// we're not getting a 200 from the proxy endpoint. If it's a 404,
|
|
64
|
+
// then we know we'll never have the endpoint, so just clear out the
|
|
65
|
+
// options. Either way, we can give UDP a try.
|
|
66
|
+
if (err.status === 404) {
|
|
67
|
+
this._httpOptions = null
|
|
68
|
+
}
|
|
69
|
+
this._sendUdp(queue)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
_sendUdp (queue) {
|
|
41
76
|
if (this._family !== 0) {
|
|
42
|
-
this.
|
|
77
|
+
this._sendUdpFromQueue(queue, this._host, this._family)
|
|
43
78
|
} else {
|
|
44
79
|
lookup(this._host, (err, address, family) => {
|
|
45
80
|
if (err) return log.error(err)
|
|
46
|
-
this.
|
|
81
|
+
this._sendUdpFromQueue(queue, address, family)
|
|
47
82
|
})
|
|
48
83
|
}
|
|
49
84
|
}
|
|
50
85
|
|
|
51
|
-
|
|
86
|
+
_sendUdpFromQueue (queue, address, family) {
|
|
52
87
|
const socket = family === 6 ? this._udp6 : this._udp4
|
|
53
88
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
_sendAll (queue, address, family) {
|
|
60
|
-
queue.forEach((buffer) => this._send(address, family, buffer))
|
|
89
|
+
queue.forEach((buffer) => {
|
|
90
|
+
log.debug(`Sending to DogStatsD: ${buffer}`)
|
|
91
|
+
socket.send(buffer, 0, buffer.length, this._port, address)
|
|
92
|
+
})
|
|
61
93
|
}
|
|
62
94
|
|
|
63
95
|
_add (stat, value, type, tags) {
|
|
@@ -197,8 +197,16 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
_encode (bytes, trace) {
|
|
200
|
-
|
|
201
|
-
|
|
200
|
+
const rawEvents = trace.map(formatSpan)
|
|
201
|
+
|
|
202
|
+
const testSessionEvents = rawEvents.filter(
|
|
203
|
+
event => event.type === 'test_session_end' || event.type === 'test_suite_end'
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
const isTestSessionTrace = !!testSessionEvents.length
|
|
207
|
+
const events = isTestSessionTrace ? testSessionEvents : rawEvents
|
|
208
|
+
|
|
209
|
+
this._eventCount += events.length
|
|
202
210
|
|
|
203
211
|
for (const event of events) {
|
|
204
212
|
this._encodeEvent(bytes, event)
|
|
@@ -12,7 +12,6 @@ const MAXIMUM_NUM_COVERAGE_FILES = 100
|
|
|
12
12
|
class CoverageCIVisibilityEncoder extends AgentEncoder {
|
|
13
13
|
constructor () {
|
|
14
14
|
super(...arguments)
|
|
15
|
-
this.codeCoverageBuffers = []
|
|
16
15
|
this._coverageBytes = new Chunk()
|
|
17
16
|
this.form = new FormData()
|
|
18
17
|
this.fileIndex = 1
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const AgentExporter = require('./exporters/agent')
|
|
4
4
|
const LogExporter = require('./exporters/log')
|
|
5
5
|
const AgentlessCiVisibilityExporter = require('./ci-visibility/exporters/agentless')
|
|
6
|
+
const AgentProxyCiVisibilityExporter = require('./ci-visibility/exporters/agent-proxy')
|
|
6
7
|
const exporters = require('../../../ext/exporters')
|
|
7
8
|
const fs = require('fs')
|
|
8
9
|
const constants = require('./constants')
|
|
@@ -18,6 +19,8 @@ module.exports = name => {
|
|
|
18
19
|
return AgentExporter
|
|
19
20
|
case exporters.DATADOG:
|
|
20
21
|
return AgentlessCiVisibilityExporter
|
|
22
|
+
case exporters.AGENT_PROXY:
|
|
23
|
+
return AgentProxyCiVisibilityExporter
|
|
21
24
|
default:
|
|
22
25
|
return inAWSLambda && !usingLambdaExtension ? LogExporter : AgentExporter
|
|
23
26
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const URL = require('url')
|
|
3
|
+
const { URL, format } = require('url')
|
|
4
4
|
const log = require('../../log')
|
|
5
5
|
const Writer = require('./writer')
|
|
6
6
|
|
|
@@ -8,7 +8,11 @@ class AgentExporter {
|
|
|
8
8
|
constructor (config, prioritySampler) {
|
|
9
9
|
this._config = config
|
|
10
10
|
const { url, hostname, port, lookup, protocolVersion, stats = {} } = config
|
|
11
|
-
this._url = url || new URL(
|
|
11
|
+
this._url = url || new URL(format({
|
|
12
|
+
protocol: 'http:',
|
|
13
|
+
hostname: hostname || 'localhost',
|
|
14
|
+
port
|
|
15
|
+
}))
|
|
12
16
|
|
|
13
17
|
const headers = {}
|
|
14
18
|
if (stats.enabled) {
|
|
@@ -51,6 +55,10 @@ class AgentExporter {
|
|
|
51
55
|
}, flushInterval).unref()
|
|
52
56
|
}
|
|
53
57
|
}
|
|
58
|
+
|
|
59
|
+
flush (done = () => {}) {
|
|
60
|
+
this._writer.flush(done)
|
|
61
|
+
}
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
module.exports = AgentExporter
|
|
@@ -85,21 +85,14 @@ function makeRequest (version, data, count, url, headers, lookup, needsStartupLo
|
|
|
85
85
|
'Datadog-Meta-Tracer-Version': tracerVersion,
|
|
86
86
|
'X-Datadog-Trace-Count': String(count)
|
|
87
87
|
},
|
|
88
|
-
lookup
|
|
88
|
+
lookup,
|
|
89
|
+
url
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
setHeader(options.headers, 'Datadog-Meta-Lang', 'nodejs')
|
|
92
93
|
setHeader(options.headers, 'Datadog-Meta-Lang-Version', process.version)
|
|
93
94
|
setHeader(options.headers, 'Datadog-Meta-Lang-Interpreter', process.jsEngine || 'v8')
|
|
94
95
|
|
|
95
|
-
if (url.protocol === 'unix:') {
|
|
96
|
-
options.socketPath = url.pathname
|
|
97
|
-
} else {
|
|
98
|
-
options.protocol = url.protocol
|
|
99
|
-
options.hostname = url.hostname
|
|
100
|
-
options.port = url.port
|
|
101
|
-
}
|
|
102
|
-
|
|
103
96
|
log.debug(() => `Request to the agent: ${JSON.stringify(options)}`)
|
|
104
97
|
|
|
105
98
|
request(data, options, (err, res, status) => {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
const { URL, format } = require('url')
|
|
2
|
+
|
|
3
|
+
const request = require('./request')
|
|
4
|
+
|
|
5
|
+
function fetchAgentInfo (url, callback) {
|
|
6
|
+
request('', {
|
|
7
|
+
path: '/info',
|
|
8
|
+
url
|
|
9
|
+
}, (err, res) => {
|
|
10
|
+
if (err) {
|
|
11
|
+
return callback(err)
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const response = JSON.parse(res)
|
|
15
|
+
return callback(null, response)
|
|
16
|
+
} catch (e) {
|
|
17
|
+
return callback(e)
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Exporter that exposes a way to query /info endpoint from the agent and gives you the response.
|
|
24
|
+
* While this._writer is not initialized, exported traces are stored as is.
|
|
25
|
+
*/
|
|
26
|
+
class AgentInfoExporter {
|
|
27
|
+
constructor (tracerConfig) {
|
|
28
|
+
this._config = tracerConfig
|
|
29
|
+
const { url, hostname, port } = this._config
|
|
30
|
+
this._url = url || new URL(format({
|
|
31
|
+
protocol: 'http:',
|
|
32
|
+
hostname: hostname || 'localhost',
|
|
33
|
+
port
|
|
34
|
+
}))
|
|
35
|
+
this._traceBuffer = []
|
|
36
|
+
this._isInitialized = false
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
getAgentInfo (onReceivedInfo) {
|
|
40
|
+
fetchAgentInfo(this._url, onReceivedInfo)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export (trace) {
|
|
44
|
+
if (!this._isInitialized) {
|
|
45
|
+
this._traceBuffer.push(trace)
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
this._export(trace)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_export (payload, writer = this._writer, timerKey = '_timer') {
|
|
52
|
+
writer.append(payload)
|
|
53
|
+
|
|
54
|
+
const { flushInterval } = this._config
|
|
55
|
+
|
|
56
|
+
if (flushInterval === 0) {
|
|
57
|
+
writer.flush()
|
|
58
|
+
} else if (flushInterval > 0 && !this[timerKey]) {
|
|
59
|
+
this[timerKey] = setTimeout(() => {
|
|
60
|
+
writer.flush()
|
|
61
|
+
this[timerKey] = clearTimeout(this[timerKey])
|
|
62
|
+
}, flushInterval).unref()
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getUncodedTraces () {
|
|
67
|
+
return this._traceBuffer
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
exportUncodedTraces () {
|
|
71
|
+
this.getUncodedTraces().forEach(uncodedTrace => {
|
|
72
|
+
this.export(uncodedTrace)
|
|
73
|
+
})
|
|
74
|
+
this.resetUncodedTraces()
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
resetUncodedTraces () {
|
|
78
|
+
this._traceBuffer = []
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = AgentInfoExporter
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
const { Readable } = require('stream')
|
|
7
7
|
const http = require('http')
|
|
8
8
|
const https = require('https')
|
|
9
|
+
const { parse: urlParse } = require('url')
|
|
9
10
|
const docker = require('./docker')
|
|
10
11
|
const { storage } = require('../../../../datadog-core')
|
|
11
12
|
const log = require('../../log')
|
|
@@ -19,11 +20,54 @@ const containerId = docker.id()
|
|
|
19
20
|
|
|
20
21
|
let activeRequests = 0
|
|
21
22
|
|
|
23
|
+
// TODO: Replace with `url.urlToHttpOptions` when supported by all versions
|
|
24
|
+
function urlToOptions (url) {
|
|
25
|
+
const agent = url.agent || http.globalAgent
|
|
26
|
+
const options = {
|
|
27
|
+
protocol: url.protocol || agent.protocol,
|
|
28
|
+
hostname: typeof url.hostname === 'string' && url.hostname.startsWith('[')
|
|
29
|
+
? url.hostname.slice(1, -1)
|
|
30
|
+
: url.hostname ||
|
|
31
|
+
url.host ||
|
|
32
|
+
'localhost',
|
|
33
|
+
hash: url.hash,
|
|
34
|
+
search: url.search,
|
|
35
|
+
pathname: url.pathname,
|
|
36
|
+
path: `${url.pathname || ''}${url.search || ''}`,
|
|
37
|
+
href: url.href
|
|
38
|
+
}
|
|
39
|
+
if (url.port !== '') {
|
|
40
|
+
options.port = Number(url.port)
|
|
41
|
+
}
|
|
42
|
+
if (url.username || url.password) {
|
|
43
|
+
options.auth = `${url.username}:${url.password}`
|
|
44
|
+
}
|
|
45
|
+
return options
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function fromUrlString (url) {
|
|
49
|
+
return typeof urlToHttpOptions === 'function'
|
|
50
|
+
? urlToOptions(new URL(url))
|
|
51
|
+
: urlParse(url)
|
|
52
|
+
}
|
|
53
|
+
|
|
22
54
|
function request (data, options, callback) {
|
|
23
55
|
if (!options.headers) {
|
|
24
56
|
options.headers = {}
|
|
25
57
|
}
|
|
26
58
|
|
|
59
|
+
if (options.url) {
|
|
60
|
+
const url = typeof options.url === 'object' ? options.url : fromUrlString(options.url)
|
|
61
|
+
if (url.protocol === 'unix:') {
|
|
62
|
+
options.socketPath = url.pathname
|
|
63
|
+
} else {
|
|
64
|
+
if (!options.path) options.path = url.path
|
|
65
|
+
options.protocol = url.protocol
|
|
66
|
+
options.hostname = url.hostname
|
|
67
|
+
options.port = url.port
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
27
71
|
const isReadable = data instanceof Readable
|
|
28
72
|
|
|
29
73
|
// The timeout should be kept low to avoid excessive queueing.
|
|
@@ -54,7 +98,13 @@ function request (data, options, callback) {
|
|
|
54
98
|
if (res.statusCode >= 200 && res.statusCode <= 299) {
|
|
55
99
|
callback(null, responseData, res.statusCode)
|
|
56
100
|
} else {
|
|
57
|
-
const
|
|
101
|
+
const fullUrl = `${options.url || options.hostname || `localhost:${options.port}`}${options.path}`
|
|
102
|
+
// eslint-disable-next-line
|
|
103
|
+
let errorMessage = `Error from ${fullUrl}: ${res.statusCode} ${http.STATUS_CODES[res.statusCode]}.`
|
|
104
|
+
if (responseData) {
|
|
105
|
+
errorMessage += ` Response from the endpoint: "${responseData}"`
|
|
106
|
+
}
|
|
107
|
+
const error = new Error(errorMessage)
|
|
58
108
|
error.status = res.statusCode
|
|
59
109
|
|
|
60
110
|
callback(error, null, res.statusCode)
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
const { URL } = require('url')
|
|
1
|
+
const { URL, format } = require('url')
|
|
2
2
|
|
|
3
3
|
const { Writer } = require('./writer')
|
|
4
4
|
|
|
5
5
|
class SpanStatsExporter {
|
|
6
6
|
constructor (config) {
|
|
7
7
|
const { hostname = '127.0.0.1', port = 8126, tags, url } = config
|
|
8
|
-
this._url = url || new URL(
|
|
8
|
+
this._url = url || new URL(format({
|
|
9
|
+
protocol: 'http:',
|
|
10
|
+
hostname: hostname || 'localhost',
|
|
11
|
+
port
|
|
12
|
+
}))
|
|
9
13
|
this._writer = new Writer({ url: this._url, tags })
|
|
10
14
|
}
|
|
11
15
|
|
|
@@ -9,10 +9,18 @@ const SAMPLING_PRIORITY_KEY = constants.SAMPLING_PRIORITY_KEY
|
|
|
9
9
|
const SAMPLING_RULE_DECISION = constants.SAMPLING_RULE_DECISION
|
|
10
10
|
const SAMPLING_LIMIT_DECISION = constants.SAMPLING_LIMIT_DECISION
|
|
11
11
|
const SAMPLING_AGENT_DECISION = constants.SAMPLING_AGENT_DECISION
|
|
12
|
+
const SPAN_SAMPLING_MECHANISM = constants.SPAN_SAMPLING_MECHANISM
|
|
13
|
+
const SPAN_SAMPLING_RULE_RATE = constants.SPAN_SAMPLING_RULE_RATE
|
|
14
|
+
const SPAN_SAMPLING_MAX_PER_SECOND = constants.SPAN_SAMPLING_MAX_PER_SECOND
|
|
15
|
+
const SAMPLING_MECHANISM_SPAN = constants.SAMPLING_MECHANISM_SPAN
|
|
12
16
|
const MEASURED = tags.MEASURED
|
|
13
17
|
const ORIGIN_KEY = constants.ORIGIN_KEY
|
|
14
18
|
const HOSTNAME_KEY = constants.HOSTNAME_KEY
|
|
15
19
|
const TOP_LEVEL_KEY = constants.TOP_LEVEL_KEY
|
|
20
|
+
const PROCESS_ID = constants.PROCESS_ID
|
|
21
|
+
const ERROR_MESSAGE = constants.ERROR_MESSAGE
|
|
22
|
+
const ERROR_STACK = constants.ERROR_STACK
|
|
23
|
+
const ERROR_TYPE = constants.ERROR_TYPE
|
|
16
24
|
|
|
17
25
|
const map = {
|
|
18
26
|
'service.name': 'service',
|
|
@@ -47,6 +55,13 @@ function formatSpan (span) {
|
|
|
47
55
|
}
|
|
48
56
|
}
|
|
49
57
|
|
|
58
|
+
function setSingleSpanIngestionTags (span, options) {
|
|
59
|
+
if (!options) return
|
|
60
|
+
addTag({}, span.metrics, SPAN_SAMPLING_MECHANISM, SAMPLING_MECHANISM_SPAN)
|
|
61
|
+
addTag({}, span.metrics, SPAN_SAMPLING_RULE_RATE, options.sampleRate)
|
|
62
|
+
addTag({}, span.metrics, SPAN_SAMPLING_MAX_PER_SECOND, options.maxPerSecond)
|
|
63
|
+
}
|
|
64
|
+
|
|
50
65
|
function extractTags (trace, span) {
|
|
51
66
|
const context = span.context()
|
|
52
67
|
const origin = context._trace.origin
|
|
@@ -78,9 +93,9 @@ function extractTags (trace, span) {
|
|
|
78
93
|
extractError(trace, tags[tag])
|
|
79
94
|
}
|
|
80
95
|
break
|
|
81
|
-
case
|
|
82
|
-
case
|
|
83
|
-
case
|
|
96
|
+
case ERROR_TYPE:
|
|
97
|
+
case ERROR_MESSAGE:
|
|
98
|
+
case ERROR_STACK:
|
|
84
99
|
// HACK: remove when implemented in the backend
|
|
85
100
|
if (context._name !== 'fs.operation') {
|
|
86
101
|
trace.error = 1
|
|
@@ -92,10 +107,10 @@ function extractTags (trace, span) {
|
|
|
92
107
|
}
|
|
93
108
|
}
|
|
94
109
|
|
|
95
|
-
|
|
96
|
-
addTag(trace.meta, trace.metrics, 'language', 'javascript')
|
|
97
|
-
}
|
|
110
|
+
setSingleSpanIngestionTags(trace, context._sampling.spanSampling)
|
|
98
111
|
|
|
112
|
+
addTag(trace.meta, trace.metrics, 'language', 'javascript')
|
|
113
|
+
addTag(trace.meta, trace.metrics, PROCESS_ID, process.pid)
|
|
99
114
|
addTag(trace.meta, trace.metrics, SAMPLING_PRIORITY_KEY, priority)
|
|
100
115
|
addTag(trace.meta, trace.metrics, ORIGIN_KEY, origin)
|
|
101
116
|
addTag(trace.meta, trace.metrics, HOSTNAME_KEY, hostname)
|
|
@@ -131,9 +146,9 @@ function extractError (trace, error) {
|
|
|
131
146
|
trace.error = 1
|
|
132
147
|
|
|
133
148
|
if (isError(error)) {
|
|
134
|
-
addTag(trace.meta, trace.metrics,
|
|
135
|
-
addTag(trace.meta, trace.metrics,
|
|
136
|
-
addTag(trace.meta, trace.metrics,
|
|
149
|
+
addTag(trace.meta, trace.metrics, ERROR_MESSAGE, error.message)
|
|
150
|
+
addTag(trace.meta, trace.metrics, ERROR_TYPE, error.name)
|
|
151
|
+
addTag(trace.meta, trace.metrics, ERROR_STACK, error.stack)
|
|
137
152
|
}
|
|
138
153
|
}
|
|
139
154
|
|
|
@@ -160,7 +175,7 @@ function addTag (meta, metrics, key, value, nested) {
|
|
|
160
175
|
metrics[key] = value.toString()
|
|
161
176
|
} else if (!Array.isArray(value) && !nested) {
|
|
162
177
|
for (const prop in value) {
|
|
163
|
-
if (!value
|
|
178
|
+
if (!hasOwn(value, prop)) continue
|
|
164
179
|
|
|
165
180
|
addTag(meta, metrics, `${key}.${prop}`, value[prop], true)
|
|
166
181
|
}
|
|
@@ -170,6 +185,10 @@ function addTag (meta, metrics, key, value, nested) {
|
|
|
170
185
|
}
|
|
171
186
|
}
|
|
172
187
|
|
|
188
|
+
function hasOwn (object, prop) {
|
|
189
|
+
return Object.prototype.hasOwnProperty.call(object, prop)
|
|
190
|
+
}
|
|
191
|
+
|
|
173
192
|
function isNodeBuffer (obj) {
|
|
174
193
|
return obj.constructor && obj.constructor.name === 'Buffer' &&
|
|
175
194
|
typeof obj.readInt8 === 'function' &&
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { channel } = require('../../../datadog-instrumentations/src/helpers/instrument')
|
|
4
|
+
const { ERROR_MESSAGE, ERROR_TYPE } = require('../constants')
|
|
5
|
+
const { ImpendingTimeout } = require('./runtime/errors')
|
|
6
|
+
|
|
7
|
+
const globalTracer = global._ddtrace
|
|
8
|
+
const tracer = globalTracer._tracer
|
|
9
|
+
const timeoutChannel = channel('apm:aws:lambda:timeout')
|
|
10
|
+
// Always crash the flushes when a message is received
|
|
11
|
+
// from this channel.
|
|
12
|
+
timeoutChannel.subscribe(_ => {
|
|
13
|
+
crashFlush()
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
let __lambdaTimeout
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Publishes to the `apm:aws:lambda:timeout` channel when
|
|
20
|
+
* the AWS Lambda run time is about to end.
|
|
21
|
+
*
|
|
22
|
+
* @param {*} context AWS Lambda context object.
|
|
23
|
+
*/
|
|
24
|
+
function checkTimeout (context) {
|
|
25
|
+
let remainingTimeInMillis = context.getRemainingTimeInMillis()
|
|
26
|
+
const apmFlushDeadline = parseInt(process.env.DD_APM_FLUSH_DEADLINE)
|
|
27
|
+
if (apmFlushDeadline && apmFlushDeadline <= remainingTimeInMillis) {
|
|
28
|
+
remainingTimeInMillis = apmFlushDeadline
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
__lambdaTimeout = setTimeout(() => {
|
|
32
|
+
timeoutChannel.publish(undefined)
|
|
33
|
+
}, remainingTimeInMillis - 50)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Grabs the current span, adds an error for an impending timeout.
|
|
38
|
+
*
|
|
39
|
+
* After that, it calls `killAll` on the tracer processor
|
|
40
|
+
* in order to kill remaining unfinished spans.
|
|
41
|
+
*
|
|
42
|
+
* Once that is done, it finishes the last span.
|
|
43
|
+
*/
|
|
44
|
+
function crashFlush () {
|
|
45
|
+
const activeSpan = tracer.scope().active()
|
|
46
|
+
const error = new ImpendingTimeout('Datadog detected an impending timeout')
|
|
47
|
+
activeSpan.addTags({
|
|
48
|
+
[ERROR_MESSAGE]: error.message,
|
|
49
|
+
[ERROR_TYPE]: error.name
|
|
50
|
+
})
|
|
51
|
+
tracer._processor.killAll()
|
|
52
|
+
activeSpan.finish()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Patches your AWS Lambda handler function to add some tracing support.
|
|
57
|
+
*
|
|
58
|
+
* @param {*} lambdaHandler a Lambda handler function.
|
|
59
|
+
*/
|
|
60
|
+
exports.datadog = function datadog (lambdaHandler) {
|
|
61
|
+
return (...args) => {
|
|
62
|
+
const context = args[1]
|
|
63
|
+
const patched = lambdaHandler.apply(this, args)
|
|
64
|
+
checkTimeout(context)
|
|
65
|
+
|
|
66
|
+
if (patched) {
|
|
67
|
+
// clear the timeout as soon as a result is returned
|
|
68
|
+
patched.then(_ => clearTimeout(__lambdaTimeout))
|
|
69
|
+
}
|
|
70
|
+
return patched
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
*
|
|
4
|
+
* Defines custom error types throwable by the runtime.
|
|
5
|
+
*/
|
|
6
|
+
'use strict'
|
|
7
|
+
|
|
8
|
+
class ExtendedError extends Error {
|
|
9
|
+
constructor (reason) {
|
|
10
|
+
super(reason)
|
|
11
|
+
Object.setPrototypeOf(this, new.target.prototype)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class ImpendingTimeout extends ExtendedError {}
|
|
16
|
+
ImpendingTimeout.prototype.name = 'Impending Timeout'
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
ImpendingTimeout
|
|
20
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const path = require('path')
|
|
4
|
+
|
|
5
|
+
const { _extractModuleNameAndHandlerPath, _extractModuleRootAndHandler, _getLambdaFilePath } = require('./ritm')
|
|
6
|
+
const { datadog } = require('../handler')
|
|
7
|
+
const { addHook } = require('../../../../datadog-instrumentations/src/helpers/instrument')
|
|
8
|
+
const shimmer = require('../../../../datadog-shimmer')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Patches a Datadog Lambda module by calling `patchDatadogLambdaHandler`
|
|
12
|
+
* with the handler name `datadog`.
|
|
13
|
+
*
|
|
14
|
+
* @param {*} datadogLambdaModule node module to be patched.
|
|
15
|
+
* @returns a Datadog Lambda module with the `datadog` function from
|
|
16
|
+
* `datadog-lambda-js` patched.
|
|
17
|
+
*/
|
|
18
|
+
const patchDatadogLambdaModule = (datadogLambdaModule) => {
|
|
19
|
+
shimmer.wrap(datadogLambdaModule, 'datadog', patchDatadogLambdaHandler)
|
|
20
|
+
|
|
21
|
+
return datadogLambdaModule
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Patches a Datadog Lambda handler in order to do
|
|
26
|
+
* Datadog instrumentation by getting the Lambda handler from its
|
|
27
|
+
* arguments.
|
|
28
|
+
*
|
|
29
|
+
* @param {*} datadogHandler the Datadog Lambda handler to destructure.
|
|
30
|
+
* @returns the datadogHandler with its arguments patched.
|
|
31
|
+
*/
|
|
32
|
+
function patchDatadogLambdaHandler (datadogHandler) {
|
|
33
|
+
return (userHandler) => {
|
|
34
|
+
return datadogHandler(datadog(userHandler))
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Patches a Lambda module on the given handler path.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} handlerPath path of the handler to be patched.
|
|
42
|
+
* @returns a module with the given handler path patched.
|
|
43
|
+
*/
|
|
44
|
+
const patchLambdaModule = (handlerPath) => (lambdaModule) => {
|
|
45
|
+
shimmer.wrap(lambdaModule, handlerPath, patchLambdaHandler)
|
|
46
|
+
|
|
47
|
+
return lambdaModule
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Patches a Lambda handler in order to do Datadog instrumentation.
|
|
52
|
+
*
|
|
53
|
+
* @param {*} lambdaHandler the Lambda handler to be patched.
|
|
54
|
+
* @returns a function which patches the given Lambda handler.
|
|
55
|
+
*/
|
|
56
|
+
function patchLambdaHandler (lambdaHandler) {
|
|
57
|
+
return datadog(lambdaHandler)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const lambdaTaskRoot = process.env.LAMBDA_TASK_ROOT
|
|
61
|
+
const originalLambdaHandler = process.env.DD_LAMBDA_HANDLER
|
|
62
|
+
|
|
63
|
+
if (originalLambdaHandler !== undefined) {
|
|
64
|
+
const [moduleRoot, moduleAndHandler] = _extractModuleRootAndHandler(originalLambdaHandler)
|
|
65
|
+
const [_module, handlerPath] = _extractModuleNameAndHandlerPath(moduleAndHandler)
|
|
66
|
+
|
|
67
|
+
const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, _module)
|
|
68
|
+
const lambdaFilePath = _getLambdaFilePath(lambdaStylePath)
|
|
69
|
+
|
|
70
|
+
addHook({ name: lambdaFilePath }, patchLambdaModule(handlerPath))
|
|
71
|
+
} else {
|
|
72
|
+
// Instrumentation is done manually.
|
|
73
|
+
addHook({ name: 'datadog-lambda-js' }, patchDatadogLambdaModule)
|
|
74
|
+
}
|