dd-trace 2.12.2 → 2.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +2 -0
- package/ext/tags.d.ts +2 -1
- package/ext/tags.js +2 -1
- package/index.d.ts +43 -20
- package/package.json +5 -3
- package/packages/datadog-core/src/storage/async_resource.js +19 -1
- package/packages/datadog-instrumentations/index.js +1 -52
- package/packages/datadog-instrumentations/src/crypto.js +30 -0
- package/packages/datadog-instrumentations/src/cucumber.js +15 -0
- package/packages/datadog-instrumentations/src/fs.js +11 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +70 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +5 -34
- package/packages/datadog-instrumentations/src/helpers/instrumentations.js +7 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +59 -0
- package/packages/datadog-instrumentations/src/http/server.js +1 -1
- package/packages/datadog-instrumentations/src/jest.js +33 -11
- package/packages/datadog-instrumentations/src/net.js +13 -0
- package/packages/datadog-plugin-cucumber/src/index.js +4 -0
- package/packages/datadog-plugin-fs/src/index.js +72 -38
- package/packages/datadog-plugin-jest/src/index.js +25 -4
- package/packages/datadog-plugin-mocha/src/index.js +2 -2
- package/packages/datadog-plugin-mongodb-core/src/index.js +32 -8
- package/packages/datadog-plugin-oracledb/src/index.js +12 -4
- package/packages/dd-trace/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +3 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/index.js +20 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +48 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +24 -0
- package/packages/dd-trace/src/appsec/iast/iast-context.js +50 -0
- package/packages/dd-trace/src/appsec/iast/index.js +59 -0
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +94 -0
- package/packages/dd-trace/src/appsec/iast/path-line.js +70 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +113 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +50 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +53 -8
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +23 -24
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +220 -0
- package/packages/dd-trace/src/config.js +89 -10
- package/packages/dd-trace/src/constants.js +9 -1
- package/packages/dd-trace/src/encode/0.4.js +51 -58
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +13 -34
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +84 -0
- package/packages/dd-trace/src/encode/span-stats.js +155 -0
- package/packages/dd-trace/src/exporters/agent/index.js +25 -7
- package/packages/dd-trace/src/exporters/agent/writer.js +7 -4
- package/packages/dd-trace/src/{profiling/exporters → exporters/common}/form-data.js +0 -0
- package/packages/dd-trace/src/exporters/common/request.js +25 -10
- package/packages/dd-trace/src/exporters/common/writer.js +9 -6
- package/packages/dd-trace/src/exporters/span-stats/index.js +20 -0
- package/packages/dd-trace/src/exporters/span-stats/writer.js +54 -0
- package/packages/dd-trace/src/format.js +2 -0
- package/packages/dd-trace/src/id.js +16 -13
- package/packages/dd-trace/src/iitm.js +11 -0
- package/packages/dd-trace/src/index.js +10 -0
- package/packages/dd-trace/src/noop/proxy.js +87 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +77 -6
- package/packages/dd-trace/src/opentracing/tracer.js +1 -1
- package/packages/dd-trace/src/plugin_manager.js +107 -65
- package/packages/dd-trace/src/plugins/index.js +58 -45
- package/packages/dd-trace/src/plugins/log_plugin.js +16 -9
- package/packages/dd-trace/src/plugins/util/ci.js +34 -9
- package/packages/dd-trace/src/plugins/util/git.js +52 -2
- package/packages/dd-trace/src/plugins/util/ip_blocklist.js +25 -0
- package/packages/dd-trace/src/plugins/util/tags.js +4 -1
- package/packages/dd-trace/src/plugins/util/web.js +99 -2
- package/packages/dd-trace/src/priority_sampler.js +36 -1
- package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
- package/packages/dd-trace/src/proxy.js +23 -89
- package/packages/dd-trace/src/ritm.js +10 -1
- package/packages/dd-trace/src/span_processor.js +7 -1
- package/packages/dd-trace/src/span_stats.js +210 -0
- package/packages/dd-trace/src/startup-log.js +8 -19
- package/packages/dd-trace/src/telemetry/dependencies.js +83 -0
- package/packages/dd-trace/src/{telemetry.js → telemetry/index.js} +11 -79
- package/packages/dd-trace/src/telemetry/send-data.js +35 -0
- package/scripts/install_plugin_modules.js +17 -26
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { AgentEncoder } = require('./0.4')
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
MAX_NAME_LENGTH,
|
|
7
|
+
MAX_SERVICE_LENGTH,
|
|
8
|
+
MAX_RESOURCE_NAME_LENGTH,
|
|
9
|
+
MAX_TYPE_LENGTH,
|
|
10
|
+
DEFAULT_SPAN_NAME,
|
|
11
|
+
DEFAULT_SERVICE_NAME
|
|
12
|
+
} = require('./tags-processors')
|
|
13
|
+
|
|
14
|
+
function truncate (value, maxLength, suffix = '') {
|
|
15
|
+
if (!value) {
|
|
16
|
+
return value
|
|
17
|
+
}
|
|
18
|
+
if (value.length > maxLength) {
|
|
19
|
+
return `${value.slice(0, maxLength)}${suffix}`
|
|
20
|
+
}
|
|
21
|
+
return value
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
class SpanStatsEncoder extends AgentEncoder {
|
|
25
|
+
_encodeBool (bytes, value) {
|
|
26
|
+
this._encodeByte(bytes, value ? 0xc3 : 0xc2)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
makePayload () {
|
|
30
|
+
const traceSize = this._traceBytes.length
|
|
31
|
+
const buffer = Buffer.allocUnsafe(traceSize)
|
|
32
|
+
this._traceBytes.copy(buffer, 0, traceSize)
|
|
33
|
+
this._reset()
|
|
34
|
+
return buffer
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
_encodeMapPrefix (bytes, length) {
|
|
38
|
+
const offset = bytes.length
|
|
39
|
+
|
|
40
|
+
bytes.reserve(1)
|
|
41
|
+
bytes.length += 1
|
|
42
|
+
|
|
43
|
+
bytes.buffer[offset] = 0x80 + length
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_encodeBuffer (bytes, buffer) {
|
|
47
|
+
const length = buffer.length
|
|
48
|
+
const offset = bytes.length
|
|
49
|
+
|
|
50
|
+
bytes.reserve(5)
|
|
51
|
+
bytes.length += 5
|
|
52
|
+
|
|
53
|
+
bytes.buffer[offset] = 0xc6
|
|
54
|
+
bytes.buffer[offset + 1] = length >> 24
|
|
55
|
+
bytes.buffer[offset + 2] = length >> 16
|
|
56
|
+
bytes.buffer[offset + 3] = length >> 8
|
|
57
|
+
bytes.buffer[offset + 4] = length
|
|
58
|
+
|
|
59
|
+
buffer.copy(bytes.buffer, offset + 5)
|
|
60
|
+
bytes.length += length
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_encodeStat (bytes, stat) {
|
|
64
|
+
this._encodeMapPrefix(bytes, 12)
|
|
65
|
+
|
|
66
|
+
this._encodeString(bytes, 'Service')
|
|
67
|
+
const service = stat.Service || DEFAULT_SERVICE_NAME
|
|
68
|
+
this._encodeString(bytes, truncate(service, MAX_SERVICE_LENGTH))
|
|
69
|
+
|
|
70
|
+
this._encodeString(bytes, 'Name')
|
|
71
|
+
const name = stat.Name || DEFAULT_SPAN_NAME
|
|
72
|
+
this._encodeString(bytes, truncate(name, MAX_NAME_LENGTH))
|
|
73
|
+
|
|
74
|
+
this._encodeString(bytes, 'Resource')
|
|
75
|
+
this._encodeString(bytes, truncate(stat.Resource, MAX_RESOURCE_NAME_LENGTH, '...'))
|
|
76
|
+
|
|
77
|
+
this._encodeString(bytes, 'HTTPStatusCode')
|
|
78
|
+
this._encodeInteger(bytes, stat.HTTPStatusCode)
|
|
79
|
+
|
|
80
|
+
this._encodeString(bytes, 'Type')
|
|
81
|
+
this._encodeString(bytes, truncate(stat.Type, MAX_TYPE_LENGTH))
|
|
82
|
+
|
|
83
|
+
this._encodeString(bytes, 'Hits')
|
|
84
|
+
this._encodeLong(bytes, stat.Hits)
|
|
85
|
+
|
|
86
|
+
this._encodeString(bytes, 'Errors')
|
|
87
|
+
this._encodeLong(bytes, stat.Errors)
|
|
88
|
+
|
|
89
|
+
this._encodeString(bytes, 'Duration')
|
|
90
|
+
this._encodeLong(bytes, stat.Duration)
|
|
91
|
+
|
|
92
|
+
this._encodeString(bytes, 'OkSummary')
|
|
93
|
+
this._encodeBuffer(bytes, stat.OkSummary)
|
|
94
|
+
|
|
95
|
+
this._encodeString(bytes, 'ErrorSummary')
|
|
96
|
+
this._encodeBuffer(bytes, stat.ErrorSummary)
|
|
97
|
+
|
|
98
|
+
this._encodeString(bytes, 'Synthetics')
|
|
99
|
+
this._encodeBool(bytes, stat.Synthetics)
|
|
100
|
+
|
|
101
|
+
this._encodeString(bytes, 'TopLevelHits')
|
|
102
|
+
this._encodeLong(bytes, stat.TopLevelHits)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
_encodeBucket (bytes, bucket) {
|
|
106
|
+
this._encodeMapPrefix(bytes, 3)
|
|
107
|
+
|
|
108
|
+
this._encodeString(bytes, 'Start')
|
|
109
|
+
this._encodeLong(bytes, bucket.Start)
|
|
110
|
+
|
|
111
|
+
this._encodeString(bytes, 'Duration')
|
|
112
|
+
this._encodeLong(bytes, bucket.Duration)
|
|
113
|
+
|
|
114
|
+
this._encodeString(bytes, 'Stats')
|
|
115
|
+
this._encodeArrayPrefix(bytes, bucket.Stats)
|
|
116
|
+
for (const stat of bucket.Stats) {
|
|
117
|
+
this._encodeStat(bytes, stat)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
_encode (bytes, stats) {
|
|
122
|
+
this._encodeMapPrefix(bytes, 8)
|
|
123
|
+
|
|
124
|
+
this._encodeString(bytes, 'Hostname')
|
|
125
|
+
this._encodeString(bytes, stats.Hostname)
|
|
126
|
+
|
|
127
|
+
this._encodeString(bytes, 'Env')
|
|
128
|
+
this._encodeString(bytes, stats.Env)
|
|
129
|
+
|
|
130
|
+
this._encodeString(bytes, 'Version')
|
|
131
|
+
this._encodeString(bytes, stats.Version)
|
|
132
|
+
|
|
133
|
+
this._encodeString(bytes, 'Stats')
|
|
134
|
+
this._encodeArrayPrefix(bytes, stats.Stats)
|
|
135
|
+
for (const bucket of stats.Stats) {
|
|
136
|
+
this._encodeBucket(bytes, bucket)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
this._encodeString(bytes, 'Lang')
|
|
140
|
+
this._encodeString(bytes, stats.Lang)
|
|
141
|
+
|
|
142
|
+
this._encodeString(bytes, 'TracerVersion')
|
|
143
|
+
this._encodeString(bytes, stats.TracerVersion)
|
|
144
|
+
|
|
145
|
+
this._encodeString(bytes, 'RuntimeID')
|
|
146
|
+
this._encodeString(bytes, stats.RuntimeID)
|
|
147
|
+
|
|
148
|
+
this._encodeString(bytes, 'Sequence')
|
|
149
|
+
this._encodeLong(bytes, stats.Sequence)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
module.exports = {
|
|
154
|
+
SpanStatsEncoder
|
|
155
|
+
}
|
|
@@ -3,17 +3,28 @@
|
|
|
3
3
|
const URL = require('url').URL
|
|
4
4
|
const log = require('../../log')
|
|
5
5
|
const Writer = require('./writer')
|
|
6
|
-
const Scheduler = require('../scheduler')
|
|
7
6
|
|
|
8
7
|
class AgentExporter {
|
|
9
|
-
constructor (
|
|
8
|
+
constructor (config, prioritySampler) {
|
|
9
|
+
this._config = config
|
|
10
|
+
const { url, hostname, port, lookup, protocolVersion, stats = {} } = config
|
|
10
11
|
this._url = url || new URL(`http://${hostname || 'localhost'}:${port}`)
|
|
11
|
-
this._writer = new Writer({ url: this._url, prioritySampler, lookup, protocolVersion })
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
const headers = {}
|
|
14
|
+
if (stats.enabled) {
|
|
15
|
+
headers['Datadog-Client-Computed-Stats'] = 'yes'
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
|
|
18
|
+
this._writer = new Writer({
|
|
19
|
+
url: this._url,
|
|
20
|
+
prioritySampler,
|
|
21
|
+
lookup,
|
|
22
|
+
protocolVersion,
|
|
23
|
+
headers
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
this._timer = undefined
|
|
27
|
+
process.once('beforeExit', () => this._writer.flush())
|
|
17
28
|
}
|
|
18
29
|
|
|
19
30
|
setUrl (url) {
|
|
@@ -29,8 +40,15 @@ class AgentExporter {
|
|
|
29
40
|
export (spans) {
|
|
30
41
|
this._writer.append(spans)
|
|
31
42
|
|
|
32
|
-
|
|
43
|
+
const { flushInterval } = this._config
|
|
44
|
+
|
|
45
|
+
if (flushInterval === 0) {
|
|
33
46
|
this._writer.flush()
|
|
47
|
+
} else if (flushInterval > 0 && !this._timer) {
|
|
48
|
+
this._timer = setTimeout(() => {
|
|
49
|
+
this._writer.flush()
|
|
50
|
+
this._timer = clearTimeout(this._timer)
|
|
51
|
+
}, flushInterval).unref()
|
|
34
52
|
}
|
|
35
53
|
}
|
|
36
54
|
}
|
|
@@ -10,7 +10,7 @@ const BaseWriter = require('../common/writer')
|
|
|
10
10
|
const METRIC_PREFIX = 'datadog.tracer.node.exporter.agent'
|
|
11
11
|
|
|
12
12
|
class Writer extends BaseWriter {
|
|
13
|
-
constructor ({ prioritySampler, lookup, protocolVersion }) {
|
|
13
|
+
constructor ({ prioritySampler, lookup, protocolVersion, headers }) {
|
|
14
14
|
super(...arguments)
|
|
15
15
|
const AgentEncoder = getEncoder(protocolVersion)
|
|
16
16
|
|
|
@@ -18,12 +18,14 @@ class Writer extends BaseWriter {
|
|
|
18
18
|
this._lookup = lookup
|
|
19
19
|
this._protocolVersion = protocolVersion
|
|
20
20
|
this._encoder = new AgentEncoder(this)
|
|
21
|
+
this._headers = headers
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
_sendPayload (data, count, done) {
|
|
24
25
|
metrics.increment(`${METRIC_PREFIX}.requests`, true)
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
const { _headers, _lookup, _protocolVersion, _url } = this
|
|
28
|
+
makeRequest(_protocolVersion, data, count, _url, _headers, _lookup, true, (err, res, status) => {
|
|
27
29
|
if (status) {
|
|
28
30
|
metrics.increment(`${METRIC_PREFIX}.responses`, true)
|
|
29
31
|
metrics.increment(`${METRIC_PREFIX}.responses.by.status`, `status:${status}`, true)
|
|
@@ -73,11 +75,12 @@ function getEncoder (protocolVersion) {
|
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
function makeRequest (version, data, count, url, lookup, needsStartupLog, cb) {
|
|
78
|
+
function makeRequest (version, data, count, url, headers, lookup, needsStartupLog, cb) {
|
|
77
79
|
const options = {
|
|
78
80
|
path: `/v${version}/traces`,
|
|
79
81
|
method: 'PUT',
|
|
80
82
|
headers: {
|
|
83
|
+
...headers,
|
|
81
84
|
'Content-Type': 'application/msgpack',
|
|
82
85
|
'Datadog-Meta-Tracer-Version': tracerVersion,
|
|
83
86
|
'X-Datadog-Trace-Count': String(count)
|
|
@@ -99,7 +102,7 @@ function makeRequest (version, data, count, url, lookup, needsStartupLog, cb) {
|
|
|
99
102
|
|
|
100
103
|
log.debug(() => `Request to the agent: ${JSON.stringify(options)}`)
|
|
101
104
|
|
|
102
|
-
request(data, options,
|
|
105
|
+
request(data, options, (err, res, status) => {
|
|
103
106
|
if (needsStartupLog) {
|
|
104
107
|
// Note that logging will only happen once, regardless of how many times this is called.
|
|
105
108
|
startupLog({
|
|
File without changes
|
|
@@ -3,10 +3,12 @@
|
|
|
3
3
|
// TODO: Add test with slow or unresponsive agent.
|
|
4
4
|
// TODO: Add telemetry for things like dropped requests, errors, etc.
|
|
5
5
|
|
|
6
|
+
const { Readable } = require('stream')
|
|
6
7
|
const http = require('http')
|
|
7
8
|
const https = require('https')
|
|
8
9
|
const docker = require('./docker')
|
|
9
10
|
const { storage } = require('../../../../datadog-core')
|
|
11
|
+
const log = require('../../log')
|
|
10
12
|
|
|
11
13
|
const keepAlive = true
|
|
12
14
|
const maxTotalSockets = 1
|
|
@@ -17,26 +19,28 @@ const containerId = docker.id()
|
|
|
17
19
|
|
|
18
20
|
let activeRequests = 0
|
|
19
21
|
|
|
20
|
-
function request (data, options,
|
|
22
|
+
function request (data, options, callback) {
|
|
21
23
|
if (!options.headers) {
|
|
22
24
|
options.headers = {}
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
const isReadable = data instanceof Readable
|
|
28
|
+
|
|
25
29
|
// The timeout should be kept low to avoid excessive queueing.
|
|
26
30
|
const timeout = options.timeout || 2000
|
|
27
31
|
const isSecure = options.protocol === 'https:'
|
|
28
32
|
const client = isSecure ? https : http
|
|
29
33
|
const dataArray = [].concat(data)
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
if (!isReadable) {
|
|
36
|
+
options.headers['Content-Length'] = byteLength(dataArray)
|
|
37
|
+
}
|
|
32
38
|
|
|
33
39
|
if (containerId) {
|
|
34
40
|
options.headers['Datadog-Container-ID'] = containerId
|
|
35
41
|
}
|
|
36
42
|
|
|
37
|
-
|
|
38
|
-
options.agent = isSecure ? httpsAgent : httpAgent
|
|
39
|
-
}
|
|
43
|
+
options.agent = isSecure ? httpsAgent : httpAgent
|
|
40
44
|
|
|
41
45
|
const onResponse = res => {
|
|
42
46
|
let responseData = ''
|
|
@@ -59,7 +63,10 @@ function request (data, options, keepAlive, callback) {
|
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
const makeRequest = onError => {
|
|
62
|
-
if (!request.writable)
|
|
66
|
+
if (!request.writable) {
|
|
67
|
+
log.debug('Maximum number of active requests reached: payload is discarded.')
|
|
68
|
+
return callback(null)
|
|
69
|
+
}
|
|
63
70
|
|
|
64
71
|
activeRequests++
|
|
65
72
|
|
|
@@ -74,15 +81,23 @@ function request (data, options, keepAlive, callback) {
|
|
|
74
81
|
onError(err)
|
|
75
82
|
})
|
|
76
83
|
|
|
77
|
-
dataArray.forEach(buffer => req.write(buffer))
|
|
78
|
-
|
|
79
84
|
req.setTimeout(timeout, req.abort)
|
|
80
|
-
|
|
85
|
+
|
|
86
|
+
if (isReadable) {
|
|
87
|
+
data.pipe(req) // TODO: Validate whether this is actually retriable.
|
|
88
|
+
} else {
|
|
89
|
+
dataArray.forEach(buffer => req.write(buffer))
|
|
90
|
+
req.end()
|
|
91
|
+
}
|
|
81
92
|
|
|
82
93
|
storage.enterWith(store)
|
|
83
94
|
}
|
|
84
95
|
|
|
85
|
-
|
|
96
|
+
// TODO: Figure out why setTimeout is needed to avoid losing the async context
|
|
97
|
+
// in the retry request before socket.connect() is called.
|
|
98
|
+
// TODO: Test that this doesn't trace itself on retry when the diagnostics
|
|
99
|
+
// channel events are available in the agent exporter.
|
|
100
|
+
makeRequest(() => setTimeout(() => makeRequest(callback)))
|
|
86
101
|
}
|
|
87
102
|
|
|
88
103
|
function byteLength (data) {
|
|
@@ -23,16 +23,19 @@ class Writer {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
append (
|
|
27
|
-
if (!request.writable)
|
|
26
|
+
append (payload) {
|
|
27
|
+
if (!request.writable) {
|
|
28
|
+
log.debug(() => `Maximum number of active requests reached. Payload discarded: ${JSON.stringify(payload)}`)
|
|
29
|
+
return
|
|
30
|
+
}
|
|
28
31
|
|
|
29
|
-
log.debug(() => `Encoding
|
|
32
|
+
log.debug(() => `Encoding payload: ${JSON.stringify(payload)}`)
|
|
30
33
|
|
|
31
|
-
this._encode(
|
|
34
|
+
this._encode(payload)
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
_encode (
|
|
35
|
-
this._encoder.encode(
|
|
37
|
+
_encode (payload) {
|
|
38
|
+
this._encoder.encode(payload)
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
setUrl (url) {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const { URL } = require('url')
|
|
2
|
+
|
|
3
|
+
const { Writer } = require('./writer')
|
|
4
|
+
|
|
5
|
+
class SpanStatsExporter {
|
|
6
|
+
constructor (config) {
|
|
7
|
+
const { hostname = '127.0.0.1', port = 8126, tags, url } = config
|
|
8
|
+
this._url = url || new URL(`http://${hostname || 'localhost'}:${port}`)
|
|
9
|
+
this._writer = new Writer({ url: this._url, tags })
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export (payload) {
|
|
13
|
+
this._writer.append(payload)
|
|
14
|
+
this._writer.flush()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = {
|
|
19
|
+
SpanStatsExporter
|
|
20
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
const { SpanStatsEncoder } = require('../../encode/span-stats')
|
|
3
|
+
|
|
4
|
+
const pkg = require('../../../../../package.json')
|
|
5
|
+
|
|
6
|
+
const BaseWriter = require('../common/writer')
|
|
7
|
+
const request = require('../common/request')
|
|
8
|
+
const log = require('../../log')
|
|
9
|
+
|
|
10
|
+
class Writer extends BaseWriter {
|
|
11
|
+
constructor ({ url }) {
|
|
12
|
+
super(...arguments)
|
|
13
|
+
this._url = url
|
|
14
|
+
this._encoder = new SpanStatsEncoder(this)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
_sendPayload (data, _, done) {
|
|
18
|
+
makeRequest(data, this._url, (err, res) => {
|
|
19
|
+
if (err) {
|
|
20
|
+
log.error(err)
|
|
21
|
+
done()
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
log.debug(`Response from the intake: ${res}`)
|
|
25
|
+
done()
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function makeRequest (data, url, cb) {
|
|
31
|
+
const options = {
|
|
32
|
+
path: '/v0.6/stats',
|
|
33
|
+
method: 'PUT',
|
|
34
|
+
headers: {
|
|
35
|
+
'Datadog-Meta-Lang': 'javascript',
|
|
36
|
+
'Datadog-Meta-Tracer-Version': pkg.version,
|
|
37
|
+
'Content-Type': 'application/msgpack'
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
options.protocol = url.protocol
|
|
42
|
+
options.hostname = url.hostname
|
|
43
|
+
options.port = url.port
|
|
44
|
+
|
|
45
|
+
log.debug(() => `Request to the intake: ${JSON.stringify(options)}`)
|
|
46
|
+
|
|
47
|
+
request(data, options, (err, res) => {
|
|
48
|
+
cb(err, res)
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = {
|
|
53
|
+
Writer
|
|
54
|
+
}
|
|
@@ -12,6 +12,7 @@ const SAMPLING_AGENT_DECISION = constants.SAMPLING_AGENT_DECISION
|
|
|
12
12
|
const MEASURED = tags.MEASURED
|
|
13
13
|
const ORIGIN_KEY = constants.ORIGIN_KEY
|
|
14
14
|
const HOSTNAME_KEY = constants.HOSTNAME_KEY
|
|
15
|
+
const TOP_LEVEL_KEY = constants.TOP_LEVEL_KEY
|
|
15
16
|
|
|
16
17
|
const map = {
|
|
17
18
|
'service.name': 'service',
|
|
@@ -110,6 +111,7 @@ function extractRootTags (trace, span) {
|
|
|
110
111
|
addTag({}, trace.metrics, SAMPLING_RULE_DECISION, context._trace[SAMPLING_RULE_DECISION])
|
|
111
112
|
addTag({}, trace.metrics, SAMPLING_LIMIT_DECISION, context._trace[SAMPLING_LIMIT_DECISION])
|
|
112
113
|
addTag({}, trace.metrics, SAMPLING_AGENT_DECISION, context._trace[SAMPLING_AGENT_DECISION])
|
|
114
|
+
addTag({}, trace.metrics, TOP_LEVEL_KEY, 1)
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
function extractChunkTags (trace, span) {
|
|
@@ -14,17 +14,17 @@ let batch = 0
|
|
|
14
14
|
|
|
15
15
|
// Internal representation of a trace or span ID.
|
|
16
16
|
class Identifier {
|
|
17
|
-
constructor (value, radix) {
|
|
17
|
+
constructor (value, radix = 16) {
|
|
18
18
|
this._isUint64BE = true // msgpack-lite compatibility
|
|
19
|
-
this._buffer =
|
|
20
|
-
?
|
|
21
|
-
:
|
|
19
|
+
this._buffer = radix === 16
|
|
20
|
+
? createBuffer(value)
|
|
21
|
+
: fromString(value, radix)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
toString (radix) {
|
|
25
|
-
return
|
|
26
|
-
?
|
|
27
|
-
:
|
|
24
|
+
toString (radix = 16) {
|
|
25
|
+
return radix === 16
|
|
26
|
+
? toHexString(this._buffer)
|
|
27
|
+
: toNumberString(this._buffer, radix)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
toBuffer () {
|
|
@@ -49,10 +49,13 @@ function createBuffer (value) {
|
|
|
49
49
|
if (value === '0') return zeroId
|
|
50
50
|
if (!value) return pseudoRandom()
|
|
51
51
|
|
|
52
|
-
const size = Math.ceil(value.length /
|
|
53
|
-
const
|
|
52
|
+
const size = Math.ceil(value.length / 16) * 16
|
|
53
|
+
const bytes = size / 2
|
|
54
|
+
const buffer = new Array(bytes)
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
value = value.padStart(size, '0')
|
|
57
|
+
|
|
58
|
+
for (let i = 0; i < bytes; i++) {
|
|
56
59
|
buffer[i] = parseInt(value.substring(i * 2, i * 2 + 2), 16)
|
|
57
60
|
}
|
|
58
61
|
|
|
@@ -100,8 +103,8 @@ function fromString (str, raddix) {
|
|
|
100
103
|
|
|
101
104
|
// Convert a buffer to a numerical string.
|
|
102
105
|
function toNumberString (buffer, radix) {
|
|
103
|
-
let high = readInt32(buffer,
|
|
104
|
-
let low = readInt32(buffer, 4)
|
|
106
|
+
let high = readInt32(buffer, buffer.length - 8)
|
|
107
|
+
let low = readInt32(buffer, buffer.length - 4)
|
|
105
108
|
let str = ''
|
|
106
109
|
|
|
107
110
|
radix = radix || 10
|
|
@@ -2,8 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
const semver = require('semver')
|
|
4
4
|
const logger = require('./log')
|
|
5
|
+
const { addHook } = require('import-in-the-middle')
|
|
6
|
+
const dc = require('diagnostics_channel')
|
|
5
7
|
|
|
6
8
|
if (semver.satisfies(process.versions.node, '^12.20.0 || >=14.13.1')) {
|
|
9
|
+
const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart')
|
|
10
|
+
addHook((name, namespace) => {
|
|
11
|
+
if (moduleLoadStartChannel.hasSubscribers) {
|
|
12
|
+
moduleLoadStartChannel.publish({
|
|
13
|
+
filename: name,
|
|
14
|
+
module: namespace
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
})
|
|
7
18
|
module.exports = require('import-in-the-middle')
|
|
8
19
|
} else {
|
|
9
20
|
logger.warn('ESM is not fully supported by this version of Node.js, ' +
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { isFalse } = require('./util')
|
|
4
|
+
|
|
5
|
+
// Global `jest` is only present in Jest workers.
|
|
6
|
+
const inJestWorker = typeof jest !== 'undefined'
|
|
7
|
+
|
|
8
|
+
module.exports = isFalse(process.env.DD_TRACE_ENABLED) || inJestWorker
|
|
9
|
+
? require('./noop/proxy')
|
|
10
|
+
: require('./proxy')
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const NoopTracer = require('./tracer')
|
|
4
|
+
|
|
5
|
+
const noop = new NoopTracer()
|
|
6
|
+
|
|
7
|
+
class Tracer {
|
|
8
|
+
constructor () {
|
|
9
|
+
this._tracer = noop
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
init () {
|
|
13
|
+
return this
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
use () {
|
|
17
|
+
return this
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
trace (name, options, fn) {
|
|
21
|
+
if (!fn) {
|
|
22
|
+
fn = options
|
|
23
|
+
options = {}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (typeof fn !== 'function') return
|
|
27
|
+
|
|
28
|
+
options = options || {}
|
|
29
|
+
|
|
30
|
+
return this._tracer.trace(name, options, fn)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
wrap (name, options, fn) {
|
|
34
|
+
if (!fn) {
|
|
35
|
+
fn = options
|
|
36
|
+
options = {}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (typeof fn !== 'function') return fn
|
|
40
|
+
|
|
41
|
+
options = options || {}
|
|
42
|
+
|
|
43
|
+
return this._tracer.wrap(name, options, fn)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setUrl () {
|
|
47
|
+
this._tracer.setUrl.apply(this._tracer, arguments)
|
|
48
|
+
return this
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
startSpan () {
|
|
52
|
+
return this._tracer.startSpan.apply(this._tracer, arguments)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
inject () {
|
|
56
|
+
return this._tracer.inject.apply(this._tracer, arguments)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
extract () {
|
|
60
|
+
return this._tracer.extract.apply(this._tracer, arguments)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
scope () {
|
|
64
|
+
return this._tracer.scope.apply(this._tracer, arguments)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
currentSpan () {
|
|
68
|
+
return this._tracer.currentSpan.apply(this._tracer, arguments)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
bind (callback) {
|
|
72
|
+
return callback
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
bindEmitter () {}
|
|
76
|
+
|
|
77
|
+
getRumData () {
|
|
78
|
+
return this._tracer.getRumData.apply(this._tracer, arguments)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setUser () {
|
|
82
|
+
this._tracer.setUser.apply(this._tracer, arguments)
|
|
83
|
+
return this
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = Tracer
|