dd-trace 5.38.0 → 5.40.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 +1 -0
- package/index.d.ts +30 -21
- package/package.json +4 -2
- package/packages/datadog-instrumentations/src/apollo-server-core.js +1 -1
- package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
- package/packages/datadog-instrumentations/src/express-session.js +41 -0
- package/packages/datadog-instrumentations/src/fetch.js +27 -6
- package/packages/datadog-instrumentations/src/helpers/fetch.js +6 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/jest.js +16 -10
- package/packages/datadog-instrumentations/src/mocha/main.js +2 -1
- package/packages/datadog-instrumentations/src/nyc.js +2 -1
- package/packages/datadog-instrumentations/src/vitest.js +4 -2
- package/packages/datadog-plugin-amqplib/src/consumer.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +1 -2
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/base.js +5 -1
- package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +9 -8
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -4
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -2
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -2
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -2
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/consumer.js +5 -2
- package/packages/datadog-plugin-kafkajs/src/producer.js +4 -3
- package/packages/datadog-plugin-mongodb-core/src/index.js +10 -13
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
- package/packages/datadog-plugin-rhea/src/producer.js +1 -2
- package/packages/datadog-shimmer/src/shimmer.js +95 -95
- package/packages/dd-trace/src/appsec/addresses.js +1 -0
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/iast-context.js +2 -2
- package/packages/dd-trace/src/appsec/iast/index.js +0 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -2
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +3 -5
- package/packages/dd-trace/src/appsec/index.js +23 -1
- package/packages/dd-trace/src/appsec/reporter.js +3 -8
- package/packages/dd-trace/src/appsec/rule_manager.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/set_user.js +9 -5
- package/packages/dd-trace/src/appsec/sdk/track_event.js +2 -4
- package/packages/dd-trace/src/appsec/telemetry/common.js +24 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +126 -0
- package/packages/dd-trace/src/appsec/telemetry/rasp.js +35 -0
- package/packages/dd-trace/src/appsec/telemetry/user.js +24 -0
- package/packages/dd-trace/src/appsec/telemetry/waf.js +92 -0
- package/packages/dd-trace/src/appsec/user_tracking.js +2 -4
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +16 -4
- package/packages/dd-trace/src/config.js +31 -14
- package/packages/dd-trace/src/constants.js +1 -1
- package/packages/dd-trace/src/{data_streams.js → datastreams/checkpointer.js} +1 -1
- package/packages/dd-trace/src/{data_streams_context.js → datastreams/context.js} +2 -2
- package/packages/dd-trace/src/datastreams/index.js +104 -0
- package/packages/dd-trace/src/datastreams/manager.js +27 -0
- package/packages/dd-trace/src/datastreams/processor.js +1 -44
- package/packages/dd-trace/src/datastreams/size.js +53 -0
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +22 -15
- package/packages/dd-trace/src/dogstatsd.js +23 -4
- package/packages/dd-trace/src/exporters/agent/index.js +2 -2
- package/packages/dd-trace/src/flare/index.js +3 -0
- package/packages/dd-trace/src/noop/dogstatsd.js +6 -0
- package/packages/dd-trace/src/opentelemetry/tracer.js +45 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +11 -47
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +1 -1
- package/packages/dd-trace/src/opentracing/span.js +12 -2
- package/packages/dd-trace/src/payload-tagging/config/aws.json +8 -0
- package/packages/dd-trace/src/plugin_manager.js +4 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +2 -2
- package/packages/dd-trace/src/priority_sampler.js +5 -3
- package/packages/dd-trace/src/profiling/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +15 -4
- package/packages/dd-trace/src/proxy.js +41 -22
- package/packages/dd-trace/src/{appsec/remote_config → remote_config}/capabilities.js +1 -0
- package/packages/dd-trace/src/{appsec/remote_config → remote_config}/index.js +8 -5
- package/packages/dd-trace/src/{appsec/remote_config → remote_config}/manager.js +5 -5
- package/packages/dd-trace/src/runtime_metrics/index.js +34 -0
- package/packages/dd-trace/src/{runtime_metrics.js → runtime_metrics/runtime_metrics.js} +4 -4
- package/packages/dd-trace/src/serverless.js +10 -1
- package/packages/dd-trace/src/service-naming/index.js +12 -4
- package/packages/dd-trace/src/span_processor.js +7 -4
- package/packages/dd-trace/src/span_stats.js +1 -2
- package/packages/dd-trace/src/standalone/index.js +70 -0
- package/packages/dd-trace/src/standalone/product.js +24 -0
- package/packages/dd-trace/src/standalone/tracesource.js +22 -0
- package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +47 -0
- package/packages/dd-trace/src/telemetry/index.js +16 -387
- package/packages/dd-trace/src/telemetry/telemetry.js +394 -0
- package/packages/dd-trace/src/tracer.js +7 -15
- package/packages/dd-trace/src/appsec/standalone.js +0 -130
- package/packages/dd-trace/src/appsec/telemetry.js +0 -218
- package/packages/dd-trace/src/service-naming/schemas/index.js +0 -6
- /package/packages/dd-trace/src/{appsec/remote_config → remote_config}/apply_states.js +0 -0
- /package/packages/dd-trace/src/{appsec/remote_config → remote_config}/scheduler.js +0 -0
|
@@ -5,7 +5,7 @@ const { LogCollapsingLowestDenseDDSketch } = require('@datadog/sketches-js')
|
|
|
5
5
|
const { DsmPathwayCodec } = require('./pathway')
|
|
6
6
|
const { DataStreamsWriter } = require('./writer')
|
|
7
7
|
const { computePathwayHash } = require('./pathway')
|
|
8
|
-
const {
|
|
8
|
+
const { getAmqpMessageSize, getHeadersSize, getMessageSize, getSizeOrZero } = require('./size')
|
|
9
9
|
const { PATHWAY_HASH } = require('../../../../ext/tags')
|
|
10
10
|
const { SchemaBuilder } = require('./schemas/schema_builder')
|
|
11
11
|
const { SchemaSampler } = require('./schemas/schema_sampler')
|
|
@@ -115,49 +115,6 @@ class StatsBucket {
|
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
function getSizeOrZero (obj) {
|
|
119
|
-
if (typeof obj === 'string') {
|
|
120
|
-
return Buffer.from(obj, 'utf-8').length
|
|
121
|
-
}
|
|
122
|
-
if (types.isArrayBuffer(obj)) {
|
|
123
|
-
return obj.byteLength
|
|
124
|
-
}
|
|
125
|
-
if (Buffer.isBuffer(obj)) {
|
|
126
|
-
return obj.length
|
|
127
|
-
}
|
|
128
|
-
if (Array.isArray(obj) && obj.length > 0) {
|
|
129
|
-
if (typeof obj[0] === 'number') return Buffer.from(obj).length
|
|
130
|
-
let payloadSize = 0
|
|
131
|
-
obj.forEach(item => {
|
|
132
|
-
payloadSize += getSizeOrZero(item)
|
|
133
|
-
})
|
|
134
|
-
return payloadSize
|
|
135
|
-
}
|
|
136
|
-
if (obj !== null && typeof obj === 'object') {
|
|
137
|
-
try {
|
|
138
|
-
return getHeadersSize(obj)
|
|
139
|
-
} catch {
|
|
140
|
-
// pass
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return 0
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function getHeadersSize (headers) {
|
|
147
|
-
if (headers === undefined) return 0
|
|
148
|
-
return Object.entries(headers).reduce((prev, [key, val]) => getSizeOrZero(key) + getSizeOrZero(val) + prev, 0)
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function getMessageSize (message) {
|
|
152
|
-
const { key, value, headers } = message
|
|
153
|
-
return getSizeOrZero(key) + getSizeOrZero(value) + getHeadersSize(headers)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function getAmqpMessageSize (message) {
|
|
157
|
-
const { headers, content } = message
|
|
158
|
-
return getSizeOrZero(content) + getHeadersSize(headers)
|
|
159
|
-
}
|
|
160
|
-
|
|
161
118
|
class TimeBuckets extends Map {
|
|
162
119
|
forTime (time) {
|
|
163
120
|
if (!this.has(time)) {
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { types } = require('util')
|
|
4
|
+
|
|
5
|
+
function getSizeOrZero (obj) {
|
|
6
|
+
if (typeof obj === 'string') {
|
|
7
|
+
return Buffer.from(obj, 'utf-8').length
|
|
8
|
+
}
|
|
9
|
+
if (types.isArrayBuffer(obj)) {
|
|
10
|
+
return obj.byteLength
|
|
11
|
+
}
|
|
12
|
+
if (Buffer.isBuffer(obj)) {
|
|
13
|
+
return obj.length
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(obj) && obj.length > 0) {
|
|
16
|
+
if (typeof obj[0] === 'number') return Buffer.from(obj).length
|
|
17
|
+
let payloadSize = 0
|
|
18
|
+
obj.forEach(item => {
|
|
19
|
+
payloadSize += getSizeOrZero(item)
|
|
20
|
+
})
|
|
21
|
+
return payloadSize
|
|
22
|
+
}
|
|
23
|
+
if (obj !== null && typeof obj === 'object') {
|
|
24
|
+
try {
|
|
25
|
+
return getHeadersSize(obj)
|
|
26
|
+
} catch {
|
|
27
|
+
// pass
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return 0
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getHeadersSize (headers) {
|
|
34
|
+
if (headers === undefined) return 0
|
|
35
|
+
return Object.entries(headers).reduce((prev, [key, val]) => getSizeOrZero(key) + getSizeOrZero(val) + prev, 0)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function getMessageSize (message) {
|
|
39
|
+
const { key, value, headers } = message
|
|
40
|
+
return getSizeOrZero(key) + getSizeOrZero(value) + getHeadersSize(headers)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function getAmqpMessageSize (message) {
|
|
44
|
+
const { headers, content } = message
|
|
45
|
+
return getSizeOrZero(content) + getHeadersSize(headers)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
getMessageSize,
|
|
50
|
+
getHeadersSize,
|
|
51
|
+
getSizeOrZero,
|
|
52
|
+
getAmqpMessageSize
|
|
53
|
+
}
|
|
@@ -76,12 +76,12 @@ async function removeBreakpoint ({ id }) {
|
|
|
76
76
|
if (breakpoints.size === 0) return stop() // return instead of await to reduce number of promises created
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
function start () {
|
|
80
80
|
sessionStarted = true
|
|
81
81
|
return session.post('Debugger.enable') // return instead of await to reduce number of promises created
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
function stop () {
|
|
85
85
|
sessionStarted = false
|
|
86
86
|
return session.post('Debugger.disable') // return instead of await to reduce number of promises created
|
|
87
87
|
}
|
|
@@ -63,7 +63,7 @@ async function traverseGetPropertiesResult (props, opts, depth) {
|
|
|
63
63
|
return props
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
function getObjectProperties (subtype, objectId, opts, depth) {
|
|
67
67
|
if (ITERABLE_SUBTYPES.has(subtype)) {
|
|
68
68
|
return getIterable(objectId, opts, depth)
|
|
69
69
|
} else if (subtype === 'promise') {
|
|
@@ -4,10 +4,11 @@ const { join, dirname } = require('path')
|
|
|
4
4
|
const { readFileSync } = require('fs')
|
|
5
5
|
const { readFile } = require('fs/promises')
|
|
6
6
|
const { SourceMapConsumer } = require('source-map')
|
|
7
|
+
const { NODE_MAJOR } = require('../../../../../version')
|
|
7
8
|
|
|
8
9
|
const cache = new Map()
|
|
9
10
|
let cacheTimer = null
|
|
10
|
-
let
|
|
11
|
+
let cacheTime = null
|
|
11
12
|
|
|
12
13
|
const self = module.exports = {
|
|
13
14
|
async loadSourceMap (dir, url) {
|
|
@@ -34,28 +35,34 @@ const self = module.exports = {
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
// This is a workaround for, what seems like a bug in Node.js core, that seems to trigger when, among other things, a
|
|
40
|
-
// lot of timers are being created very rapidly. This makes the call to `setTimeout` throw an error from within
|
|
41
|
-
// `AsyncLocalStorage._propagate` with the following error message:
|
|
38
|
+
// The version check inside this function is to guard against a bug Node.js version 18, in which calls to `setTimeout`
|
|
39
|
+
// might throw an uncatchable error from within `AsyncLocalStorage._propagate` with the following error message:
|
|
42
40
|
//
|
|
43
41
|
// TypeError: Cannot read properties of undefined (reading 'Symbol(kResourceStore)')
|
|
44
42
|
//
|
|
45
43
|
// Source: https://github.com/nodejs/node/blob/v18.20.6/lib/async_hooks.js#L312
|
|
46
44
|
function cacheIt (key, value) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
if (NODE_MAJOR < 20) return value
|
|
46
|
+
cacheTime = Date.now()
|
|
47
|
+
setCacheTTL()
|
|
48
|
+
cache.set(key, value)
|
|
49
|
+
return value
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function setCacheTTL () {
|
|
53
|
+
if (cacheTimer !== null) return
|
|
54
|
+
|
|
55
|
+
cacheTimer = setTimeout(function () {
|
|
56
|
+
cacheTimer = null
|
|
57
|
+
if (Date.now() - cacheTime < 2_500) {
|
|
58
|
+
// If the last cache entry was added recently, keep the cache alive
|
|
59
|
+
setCacheTTL()
|
|
60
|
+
} else {
|
|
51
61
|
// Optimize for app boot, where a lot of reads might happen
|
|
52
62
|
// Clear cache a few seconds after it was last used
|
|
53
63
|
cache.clear()
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
cache.set(key, value)
|
|
58
|
-
return value
|
|
64
|
+
}
|
|
65
|
+
}, 5_000).unref()
|
|
59
66
|
}
|
|
60
67
|
|
|
61
68
|
function loadInlineSourceMap (data) {
|
|
@@ -14,6 +14,10 @@ const TYPE_GAUGE = 'g'
|
|
|
14
14
|
const TYPE_DISTRIBUTION = 'd'
|
|
15
15
|
const TYPE_HISTOGRAM = 'h'
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* @import { DogStatsD } from "../../../index.d.ts"
|
|
19
|
+
* @implements {DogStatsD}
|
|
20
|
+
*/
|
|
17
21
|
class DogStatsDClient {
|
|
18
22
|
constructor (options = {}) {
|
|
19
23
|
if (options.metricsProxyUrl) {
|
|
@@ -39,6 +43,10 @@ class DogStatsDClient {
|
|
|
39
43
|
this._add(stat, value, TYPE_COUNTER, tags)
|
|
40
44
|
}
|
|
41
45
|
|
|
46
|
+
decrement (stat, value, tags) {
|
|
47
|
+
this._add(stat, -value, TYPE_COUNTER, tags)
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
gauge (stat, value, tags) {
|
|
43
51
|
this._add(stat, value, TYPE_GAUGE, tags)
|
|
44
52
|
}
|
|
@@ -77,7 +85,7 @@ class DogStatsDClient {
|
|
|
77
85
|
// we're not getting a 200 from the proxy endpoint. If it's a 404,
|
|
78
86
|
// then we know we'll never have the endpoint, so just clear out the
|
|
79
87
|
// options. Either way, we can give UDP a try.
|
|
80
|
-
this._httpOptions =
|
|
88
|
+
this._httpOptions = undefined
|
|
81
89
|
}
|
|
82
90
|
this._sendUdp(queue)
|
|
83
91
|
}
|
|
@@ -185,11 +193,22 @@ class DogStatsDClient {
|
|
|
185
193
|
}
|
|
186
194
|
}
|
|
187
195
|
|
|
188
|
-
|
|
196
|
+
/**
|
|
197
|
+
* This is a simplified user-facing proxy to the underlying DogStatsDClient instance
|
|
198
|
+
*
|
|
199
|
+
* @implements {DogStatsD}
|
|
200
|
+
*/
|
|
189
201
|
class CustomMetrics {
|
|
190
202
|
constructor (config) {
|
|
191
203
|
const clientConfig = DogStatsDClient.generateClientConfig(config)
|
|
192
204
|
this.dogstatsd = new DogStatsDClient(clientConfig)
|
|
205
|
+
|
|
206
|
+
const flush = this.flush.bind(this)
|
|
207
|
+
|
|
208
|
+
// TODO(bengl) this magic number should be configurable
|
|
209
|
+
setInterval(flush, 10 * 1000).unref()
|
|
210
|
+
|
|
211
|
+
process.once('beforeExit', flush)
|
|
193
212
|
}
|
|
194
213
|
|
|
195
214
|
increment (stat, value = 1, tags) {
|
|
@@ -201,9 +220,9 @@ class CustomMetrics {
|
|
|
201
220
|
}
|
|
202
221
|
|
|
203
222
|
decrement (stat, value = 1, tags) {
|
|
204
|
-
return this.dogstatsd.
|
|
223
|
+
return this.dogstatsd.decrement(
|
|
205
224
|
stat,
|
|
206
|
-
value
|
|
225
|
+
value,
|
|
207
226
|
CustomMetrics.tagTranslator(tags)
|
|
208
227
|
)
|
|
209
228
|
}
|
|
@@ -7,7 +7,7 @@ const Writer = require('./writer')
|
|
|
7
7
|
class AgentExporter {
|
|
8
8
|
constructor (config, prioritySampler) {
|
|
9
9
|
this._config = config
|
|
10
|
-
const { url, hostname, port, lookup, protocolVersion, stats = {},
|
|
10
|
+
const { url, hostname, port, lookup, protocolVersion, stats = {}, apmTracingEnabled } = config
|
|
11
11
|
this._url = url || new URL(format({
|
|
12
12
|
protocol: 'http:',
|
|
13
13
|
hostname: hostname || 'localhost',
|
|
@@ -15,7 +15,7 @@ class AgentExporter {
|
|
|
15
15
|
}))
|
|
16
16
|
|
|
17
17
|
const headers = {}
|
|
18
|
-
if (stats.enabled ||
|
|
18
|
+
if (stats.enabled || apmTracingEnabled === false) {
|
|
19
19
|
headers['Datadog-Client-Computed-Stats'] = 'yes'
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -6,8 +6,10 @@ const { sanitizeAttributes } = require('@opentelemetry/core')
|
|
|
6
6
|
const Sampler = require('./sampler')
|
|
7
7
|
const Span = require('./span')
|
|
8
8
|
const id = require('../id')
|
|
9
|
+
const log = require('../log')
|
|
9
10
|
const SpanContext = require('./span_context')
|
|
10
11
|
const TextMapPropagator = require('../opentracing/propagation/text_map')
|
|
12
|
+
const TraceState = require('../opentracing/propagation/tracestate')
|
|
11
13
|
|
|
12
14
|
class Tracer {
|
|
13
15
|
constructor (library, config, tracerProvider) {
|
|
@@ -39,7 +41,49 @@ class Tracer {
|
|
|
39
41
|
// Extracted method to create span context for a new span
|
|
40
42
|
_createSpanContextForNewSpan (context) {
|
|
41
43
|
const { traceId, spanId, traceFlags, traceState } = context
|
|
42
|
-
return
|
|
44
|
+
return this._convertOtelContextToDatadog(traceId, spanId, traceFlags, traceState)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
_convertOtelContextToDatadog (traceId, spanId, traceFlag, ts, meta = {}) {
|
|
48
|
+
const origin = null
|
|
49
|
+
let samplingPriority = traceFlag
|
|
50
|
+
|
|
51
|
+
ts = ts?.traceparent || null
|
|
52
|
+
|
|
53
|
+
if (ts) {
|
|
54
|
+
// Use TraceState.fromString to parse the tracestate header
|
|
55
|
+
const traceState = TraceState.fromString(ts)
|
|
56
|
+
let ddTraceStateData = null
|
|
57
|
+
|
|
58
|
+
// Extract Datadog specific trace state data
|
|
59
|
+
traceState.forVendor('dd', (state) => {
|
|
60
|
+
ddTraceStateData = state
|
|
61
|
+
return state // You might need to adjust this part based on actual logic needed
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
if (ddTraceStateData) {
|
|
65
|
+
// Assuming ddTraceStateData is now a Map or similar structure containing Datadog trace state data
|
|
66
|
+
// Extract values as needed, similar to the original logic
|
|
67
|
+
const samplingPriorityTs = ddTraceStateData.get('s')
|
|
68
|
+
const origin = ddTraceStateData.get('o')
|
|
69
|
+
// Convert Map to object for meta
|
|
70
|
+
const otherPropagatedTags = Object.fromEntries(ddTraceStateData.entries())
|
|
71
|
+
|
|
72
|
+
// Update meta and samplingPriority based on extracted values
|
|
73
|
+
Object.assign(meta, otherPropagatedTags)
|
|
74
|
+
samplingPriority = TextMapPropagator._getSamplingPriority(traceFlag, parseInt(samplingPriorityTs, 10), origin)
|
|
75
|
+
} else {
|
|
76
|
+
log.debug(`no dd list member in tracestate from incoming request: ${ts}`)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const spanContext = new SpanContext({
|
|
81
|
+
traceId: id(traceId, 16), spanId: id(), tags: meta, parentId: id(spanId, 16)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
spanContext._sampling = { priority: samplingPriority }
|
|
85
|
+
spanContext._trace = { origin }
|
|
86
|
+
return spanContext
|
|
43
87
|
}
|
|
44
88
|
|
|
45
89
|
startSpan (name, options = {}, context = api.context.active()) {
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const pick = require('../../../../datadog-core/src/utils/src/pick')
|
|
4
4
|
const id = require('../../id')
|
|
5
5
|
const DatadogSpanContext = require('../span_context')
|
|
6
|
-
const OtelSpanContext = require('../../opentelemetry/span_context')
|
|
7
6
|
const log = require('../../log')
|
|
8
7
|
const TraceState = require('./tracestate')
|
|
9
8
|
const tags = require('../../../../../ext/tags')
|
|
@@ -33,11 +32,13 @@ const b3HeaderExpr = /^(([0-9a-f]{16}){1,2}-[0-9a-f]{16}(-[01d](-[0-9a-f]{16})?)
|
|
|
33
32
|
const baggageExpr = new RegExp(`^${baggagePrefix}(.+)$`)
|
|
34
33
|
const tagKeyExpr = /^_dd\.p\.[\x21-\x2b\x2d-\x7e]+$/ // ASCII minus spaces and commas
|
|
35
34
|
const tagValueExpr = /^[\x20-\x2b\x2d-\x7e]*$/ // ASCII minus commas
|
|
36
|
-
const ddKeys = [traceKey, spanKey, samplingKey, originKey]
|
|
37
|
-
const b3Keys = [b3TraceKey, b3SpanKey, b3ParentKey, b3SampledKey, b3FlagsKey, b3HeaderKey]
|
|
38
|
-
const logKeys = ddKeys.concat(b3Keys)
|
|
39
35
|
const traceparentExpr = /^([a-f0-9]{2})-([a-f0-9]{32})-([a-f0-9]{16})-([a-f0-9]{2})(-.*)?$/i
|
|
40
36
|
const traceparentKey = 'traceparent'
|
|
37
|
+
const tracestateKey = 'tracestate'
|
|
38
|
+
const ddKeys = [traceKey, spanKey, samplingKey, originKey]
|
|
39
|
+
const b3Keys = [b3TraceKey, b3SpanKey, b3ParentKey, b3SampledKey, b3FlagsKey, b3HeaderKey]
|
|
40
|
+
const w3cKeys = [traceparentKey, tracestateKey]
|
|
41
|
+
const logKeys = ddKeys.concat(b3Keys, w3cKeys)
|
|
41
42
|
// Origin value in tracestate replaces '~', ',' and ';' with '_"
|
|
42
43
|
const tracestateOriginFilter = /[^\x20-\x2b\x2d-\x3a\x3c-\x7d]/g
|
|
43
44
|
// Tag keys in tracestate replace ' ', ',' and '=' with '_'
|
|
@@ -78,7 +79,12 @@ class TextMapPropagator {
|
|
|
78
79
|
extractCh.publish({ spanContext, carrier })
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
log.debug(() =>
|
|
82
|
+
log.debug(() => {
|
|
83
|
+
const keys = JSON.stringify(pick(carrier, logKeys))
|
|
84
|
+
const styles = this._config.tracePropagationStyle.extract.join(', ')
|
|
85
|
+
|
|
86
|
+
return `Extract from carrier (${styles}): ${keys}.`
|
|
87
|
+
})
|
|
82
88
|
|
|
83
89
|
return spanContext
|
|
84
90
|
}
|
|
@@ -708,48 +714,6 @@ class TextMapPropagator {
|
|
|
708
714
|
return spanContext._traceId.toString(16)
|
|
709
715
|
}
|
|
710
716
|
|
|
711
|
-
static _convertOtelContextToDatadog (traceId, spanId, traceFlag, ts, meta = {}) {
|
|
712
|
-
const origin = null
|
|
713
|
-
let samplingPriority = traceFlag
|
|
714
|
-
|
|
715
|
-
ts = ts?.traceparent || null
|
|
716
|
-
|
|
717
|
-
if (ts) {
|
|
718
|
-
// Use TraceState.fromString to parse the tracestate header
|
|
719
|
-
const traceState = TraceState.fromString(ts)
|
|
720
|
-
let ddTraceStateData = null
|
|
721
|
-
|
|
722
|
-
// Extract Datadog specific trace state data
|
|
723
|
-
traceState.forVendor('dd', (state) => {
|
|
724
|
-
ddTraceStateData = state
|
|
725
|
-
return state // You might need to adjust this part based on actual logic needed
|
|
726
|
-
})
|
|
727
|
-
|
|
728
|
-
if (ddTraceStateData) {
|
|
729
|
-
// Assuming ddTraceStateData is now a Map or similar structure containing Datadog trace state data
|
|
730
|
-
// Extract values as needed, similar to the original logic
|
|
731
|
-
const samplingPriorityTs = ddTraceStateData.get('s')
|
|
732
|
-
const origin = ddTraceStateData.get('o')
|
|
733
|
-
// Convert Map to object for meta
|
|
734
|
-
const otherPropagatedTags = Object.fromEntries(ddTraceStateData.entries())
|
|
735
|
-
|
|
736
|
-
// Update meta and samplingPriority based on extracted values
|
|
737
|
-
Object.assign(meta, otherPropagatedTags)
|
|
738
|
-
samplingPriority = TextMapPropagator._getSamplingPriority(traceFlag, parseInt(samplingPriorityTs, 10), origin)
|
|
739
|
-
} else {
|
|
740
|
-
log.debug(`no dd list member in tracestate from incoming request: ${ts}`)
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
const spanContext = new OtelSpanContext({
|
|
745
|
-
traceId: id(traceId, 16), spanId: id(), tags: meta, parentId: id(spanId, 16)
|
|
746
|
-
})
|
|
747
|
-
|
|
748
|
-
spanContext._sampling = { priority: samplingPriority }
|
|
749
|
-
spanContext._trace = { origin }
|
|
750
|
-
return spanContext
|
|
751
|
-
}
|
|
752
|
-
|
|
753
717
|
static _getSamplingPriority (traceparentSampled, tracestateSamplingPriority, origin = null) {
|
|
754
718
|
const fromRumWithoutPriority = !tracestateSamplingPriority && origin === 'rum'
|
|
755
719
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const pick = require('../../../../datadog-core/src/utils/src/pick')
|
|
2
2
|
const log = require('../../log')
|
|
3
3
|
|
|
4
|
-
const { DsmPathwayCodec } = require('../../datastreams
|
|
4
|
+
const { DsmPathwayCodec } = require('../../datastreams')
|
|
5
5
|
|
|
6
6
|
const base64Key = 'dd-pathway-ctx-base64'
|
|
7
7
|
const logKeys = [base64Key]
|
|
@@ -13,7 +13,6 @@ const log = require('../log')
|
|
|
13
13
|
const { storage } = require('../../../datadog-core')
|
|
14
14
|
const telemetryMetrics = require('../telemetry/metrics')
|
|
15
15
|
const { channel } = require('dc-polyfill')
|
|
16
|
-
const spanleak = require('../spanleak')
|
|
17
16
|
const util = require('util')
|
|
18
17
|
|
|
19
18
|
const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
|
|
@@ -99,7 +98,18 @@ class DatadogSpan {
|
|
|
99
98
|
|
|
100
99
|
unfinishedRegistry.register(this, operationName, this)
|
|
101
100
|
}
|
|
102
|
-
|
|
101
|
+
|
|
102
|
+
// Nullish operator is used here because both `tracer` and `tracer._config`
|
|
103
|
+
// can be null and there are tests passing invalid values to the `Span`
|
|
104
|
+
// constructor which still succeed today. Part of the problem is that `Span`
|
|
105
|
+
// stores only the tracer and not the config, so anything that needs the
|
|
106
|
+
// config has to read it from the tracer stored on the span, including
|
|
107
|
+
// even `Span` itself in this case.
|
|
108
|
+
//
|
|
109
|
+
// TODO: Refactor Tracer/Span + tests to avoid having to do nullish checks.
|
|
110
|
+
if (tracer?._config?.spanLeakDebug > 0) {
|
|
111
|
+
require('../spanleak').addSpan(this, operationName)
|
|
112
|
+
}
|
|
103
113
|
|
|
104
114
|
if (startCh.hasSubscribers) {
|
|
105
115
|
startCh.publish({ span: this, fields })
|
|
@@ -28,9 +28,6 @@ loadChannel.subscribe(({ name }) => {
|
|
|
28
28
|
maybeEnable(plugins[name])
|
|
29
29
|
})
|
|
30
30
|
|
|
31
|
-
// Globals
|
|
32
|
-
maybeEnable(require('../../datadog-plugin-fetch/src'))
|
|
33
|
-
|
|
34
31
|
// Always enabled
|
|
35
32
|
maybeEnable(require('../../datadog-plugin-dd-trace-api/src'))
|
|
36
33
|
|
|
@@ -106,6 +103,10 @@ module.exports = class PluginManager {
|
|
|
106
103
|
this._tracerConfig = config
|
|
107
104
|
this._tracer._nomenclature.configure(config)
|
|
108
105
|
|
|
106
|
+
if (!config._isInServerlessEnvironment?.()) {
|
|
107
|
+
maybeEnable(require('../../datadog-plugin-fetch/src'))
|
|
108
|
+
}
|
|
109
|
+
|
|
109
110
|
for (const name in pluginClasses) {
|
|
110
111
|
this.loadPlugin(name)
|
|
111
112
|
}
|
|
@@ -40,6 +40,7 @@ const {
|
|
|
40
40
|
} = require('../ci-visibility/telemetry')
|
|
41
41
|
const { CI_PROVIDER_NAME, GIT_REPOSITORY_URL, GIT_COMMIT_SHA, GIT_BRANCH, CI_WORKSPACE_PATH } = require('./util/tags')
|
|
42
42
|
const { OS_VERSION, OS_PLATFORM, OS_ARCHITECTURE, RUNTIME_NAME, RUNTIME_VERSION } = require('./util/env')
|
|
43
|
+
const getDiClient = require('../ci-visibility/dynamic-instrumentation')
|
|
43
44
|
|
|
44
45
|
module.exports = class CiPlugin extends Plugin {
|
|
45
46
|
constructor (...args) {
|
|
@@ -207,8 +208,7 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
207
208
|
}
|
|
208
209
|
|
|
209
210
|
if (config.isTestDynamicInstrumentationEnabled && !this.di) {
|
|
210
|
-
|
|
211
|
-
this.di = testVisibilityDynamicInstrumentation
|
|
211
|
+
this.di = getDiClient()
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
this.testEnvironmentMetadata = getTestEnvironmentMetadata(this.constructor.id, this.config)
|
|
@@ -116,7 +116,7 @@ class PrioritySampler {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
setPriority (span, samplingPriority,
|
|
119
|
+
setPriority (span, samplingPriority, product) {
|
|
120
120
|
if (!span || !this.validate(samplingPriority)) return
|
|
121
121
|
|
|
122
122
|
const context = this._getContext(span)
|
|
@@ -128,6 +128,8 @@ class PrioritySampler {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
context._sampling.priority = samplingPriority
|
|
131
|
+
|
|
132
|
+
const mechanism = product?.mechanism ?? SAMPLING_MECHANISM_MANUAL
|
|
131
133
|
context._sampling.mechanism = mechanism
|
|
132
134
|
|
|
133
135
|
log.trace(span, samplingPriority, mechanism)
|
|
@@ -229,8 +231,8 @@ class PrioritySampler {
|
|
|
229
231
|
}
|
|
230
232
|
}
|
|
231
233
|
|
|
232
|
-
static keepTrace (span,
|
|
233
|
-
span?._prioritySampler?.setPriority(span, USER_KEEP,
|
|
234
|
+
static keepTrace (span, product) {
|
|
235
|
+
span?._prioritySampler?.setPriority(span, USER_KEEP, product)
|
|
234
236
|
}
|
|
235
237
|
}
|
|
236
238
|
|
|
@@ -286,14 +286,25 @@ class NativeWallProfiler {
|
|
|
286
286
|
|
|
287
287
|
const labels = { ...getThreadLabels() }
|
|
288
288
|
|
|
289
|
-
const { context: { ref }, timestamp } = context
|
|
290
|
-
const { spanId, rootSpanId, webTags, endpoint } = ref ?? {}
|
|
291
|
-
|
|
292
289
|
if (this._timelineEnabled) {
|
|
293
290
|
// Incoming timestamps are in microseconds, we emit nanos.
|
|
294
|
-
labels[END_TIMESTAMP_LABEL] = timestamp * 1000n
|
|
291
|
+
labels[END_TIMESTAMP_LABEL] = context.timestamp * 1000n
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const asyncId = context.asyncId
|
|
295
|
+
if (asyncId !== undefined && asyncId !== -1) {
|
|
296
|
+
labels['async id'] = asyncId
|
|
295
297
|
}
|
|
296
298
|
|
|
299
|
+
// Native profiler doesn't set context.context for some samples, such as idle samples or when
|
|
300
|
+
// the context was otherwise unavailable when the sample was taken.
|
|
301
|
+
const ref = context.context?.ref
|
|
302
|
+
if (typeof ref !== 'object') {
|
|
303
|
+
return labels
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const { spanId, rootSpanId, webTags, endpoint } = ref
|
|
307
|
+
|
|
297
308
|
if (spanId !== undefined) {
|
|
298
309
|
labels[SPAN_ID_LABEL] = spanId
|
|
299
310
|
}
|