dd-trace 5.88.0 → 5.90.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 +0 -3
- package/ext/tags.js +2 -0
- package/index.d.ts +40 -0
- package/package.json +18 -14
- package/packages/datadog-instrumentations/src/azure-durable-functions.js +75 -0
- package/packages/datadog-instrumentations/src/cucumber.js +40 -1
- package/packages/datadog-instrumentations/src/elasticsearch.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +26 -111
- package/packages/datadog-instrumentations/src/helpers/rewriter/{compiler.js → orchestrion/compiler.js} +5 -5
- package/packages/datadog-instrumentations/src/helpers/rewriter/orchestrion/index.js +43 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/orchestrion/matcher.js +49 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/orchestrion/transformer.js +121 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/{transforms.js → orchestrion/transforms.js} +6 -6
- package/packages/datadog-instrumentations/src/jest.js +123 -43
- package/packages/datadog-instrumentations/src/mocha/main.js +10 -4
- package/packages/datadog-instrumentations/src/mocha/utils.js +6 -0
- package/packages/datadog-instrumentations/src/mocha/worker.js +10 -2
- package/packages/datadog-instrumentations/src/playwright.js +20 -2
- package/packages/datadog-instrumentations/src/prisma.js +4 -2
- package/packages/datadog-instrumentations/src/vitest.js +16 -0
- package/packages/datadog-plugin-apollo/src/gateway/execute.js +8 -0
- package/packages/datadog-plugin-apollo/src/gateway/fetch.js +5 -0
- package/packages/datadog-plugin-apollo/src/gateway/plan.js +8 -0
- package/packages/datadog-plugin-apollo/src/gateway/postprocessing.js +5 -0
- package/packages/datadog-plugin-apollo/src/gateway/request.js +4 -3
- package/packages/datadog-plugin-apollo/src/gateway/validate.js +4 -3
- package/packages/datadog-plugin-apollo/src/index.js +28 -0
- package/packages/datadog-plugin-azure-durable-functions/src/index.js +49 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +47 -6
- package/packages/datadog-plugin-cypress/src/source-map-utils.js +297 -0
- package/packages/datadog-plugin-cypress/src/support.js +4 -1
- package/packages/datadog-plugin-jest/src/index.js +6 -0
- package/packages/datadog-plugin-playwright/src/index.js +35 -8
- package/packages/dd-trace/src/aiguard/noop.js +1 -1
- package/packages/dd-trace/src/aiguard/sdk.js +18 -5
- package/packages/dd-trace/src/appsec/api_security_sampler.js +22 -1
- package/packages/dd-trace/src/appsec/index.js +11 -1
- package/packages/dd-trace/src/appsec/reporter.js +28 -11
- package/packages/dd-trace/src/appsec/waf/index.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +4 -4
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -0
- package/packages/dd-trace/src/config/index.js +3 -0
- package/packages/dd-trace/src/config/supported-configurations.json +17 -0
- package/packages/dd-trace/src/constants.js +1 -0
- package/packages/dd-trace/src/datastreams/checkpointer.js +13 -0
- package/packages/dd-trace/src/datastreams/index.js +3 -0
- package/packages/dd-trace/src/datastreams/manager.js +9 -0
- package/packages/dd-trace/src/datastreams/processor.js +126 -3
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +1 -8
- package/packages/dd-trace/src/encode/agentless-json.js +82 -23
- package/packages/dd-trace/src/exporters/agent/writer.js +7 -8
- package/packages/dd-trace/src/exporters/agentless/index.js +58 -15
- package/packages/dd-trace/src/exporters/agentless/writer.js +35 -18
- package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/anthropic.js +9 -0
- package/packages/dd-trace/src/llmobs/tagger.js +8 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +1 -0
- package/packages/dd-trace/src/pkg.js +1 -1
- package/packages/dd-trace/src/plugins/apollo.js +7 -2
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/ci.js +95 -3
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +36 -2
- package/packages/dd-trace/src/plugins/util/web.js +31 -11
- package/packages/dd-trace/src/proxy.js +2 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +7 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +4 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +4 -0
- package/packages/dd-trace/src/standalone/product.js +2 -1
- package/packages/dd-trace/src/startup-log.js +52 -18
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/@datadog/source-map/index.js +1 -1
- package/vendor/dist/@isaacs/ttlcache/index.js +1 -1
- package/vendor/dist/@opentelemetry/core/index.js +1 -1
- package/vendor/dist/@opentelemetry/resources/index.js +1 -1
- package/vendor/dist/astring/index.js +1 -1
- package/vendor/dist/crypto-randomuuid/index.js +1 -1
- package/vendor/dist/escape-string-regexp/index.js +1 -1
- package/vendor/dist/esquery/index.js +1 -1
- package/vendor/dist/ignore/index.js +1 -1
- package/vendor/dist/istanbul-lib-coverage/index.js +1 -1
- package/vendor/dist/jest-docblock/index.js +1 -1
- package/vendor/dist/jsonpath-plus/index.js +1 -1
- package/vendor/dist/limiter/index.js +1 -1
- package/vendor/dist/lodash.sortby/index.js +1 -1
- package/vendor/dist/lru-cache/index.js +1 -1
- package/vendor/dist/meriyah/index.js +1 -1
- package/vendor/dist/module-details-from-path/index.js +1 -1
- package/vendor/dist/mutexify/promise/index.js +1 -1
- package/vendor/dist/opentracing/index.js +1 -1
- package/vendor/dist/path-to-regexp/index.js +1 -1
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/vendor/dist/retry/index.js +1 -1
- package/vendor/dist/rfdc/index.js +1 -1
- package/vendor/dist/semifies/index.js +1 -1
- package/vendor/dist/shell-quote/index.js +1 -1
- package/vendor/dist/source-map/index.js +1 -1
- package/vendor/dist/source-map/lib/util/index.js +1 -1
- package/vendor/dist/tlhunter-sorted-set/index.js +1 -1
- package/vendor/dist/ttl-set/index.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/transformer.js +0 -21
|
@@ -9,20 +9,22 @@ const BaseWriter = require('../common/writer')
|
|
|
9
9
|
const { AgentlessJSONEncoder } = require('../../encode/agentless-json')
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Writer for agentless APM
|
|
13
|
-
* Sends
|
|
12
|
+
* Writer for agentless APM trace intake.
|
|
13
|
+
* Sends traces directly to the Datadog intake endpoint without an agent.
|
|
14
14
|
*/
|
|
15
15
|
class AgentlessWriter extends BaseWriter {
|
|
16
16
|
#apiKeyMissing = false
|
|
17
|
+
#urlMissing = false
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* @param {object} options - Writer options
|
|
20
21
|
* @param {URL} [options.url] - The intake URL. If not provided, constructed from site.
|
|
21
22
|
* @param {string} [options.site='datadoghq.com'] - The Datadog site
|
|
23
|
+
* @param {object} [options.metadata={}] - Metadata to pass to the encoder (hostname, env, etc.)
|
|
22
24
|
*/
|
|
23
|
-
constructor ({ url, site = 'datadoghq.com' }) {
|
|
25
|
+
constructor ({ url, site = 'datadoghq.com', metadata = {} }) {
|
|
24
26
|
super({ url })
|
|
25
|
-
this._encoder = new AgentlessJSONEncoder()
|
|
27
|
+
this._encoder = new AgentlessJSONEncoder(this, metadata)
|
|
26
28
|
|
|
27
29
|
if (!url) {
|
|
28
30
|
try {
|
|
@@ -39,17 +41,27 @@ class AgentlessWriter extends BaseWriter {
|
|
|
39
41
|
|
|
40
42
|
if (!getValueFromEnvSources('DD_API_KEY')) {
|
|
41
43
|
this.#apiKeyMissing = true
|
|
42
|
-
log.error('DD_API_KEY is required for agentless
|
|
44
|
+
log.error('DD_API_KEY is required for agentless trace intake. Set DD_API_KEY. Traces will not be sent.')
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
setUrl (url) {
|
|
49
|
+
super.setUrl(url)
|
|
50
|
+
if (url) {
|
|
51
|
+
this.#urlMissing = false
|
|
43
52
|
}
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
/**
|
|
47
|
-
* Flushes
|
|
48
|
-
* a single request.
|
|
56
|
+
* Flushes accumulated traces to the intake as a single request.
|
|
49
57
|
* @param {Function} [done] - Callback when send completes
|
|
50
58
|
*/
|
|
51
59
|
flush (done = () => {}) {
|
|
52
60
|
if (!request.writable) {
|
|
61
|
+
const count = this._encoder.count()
|
|
62
|
+
if (count > 0) {
|
|
63
|
+
log.error('Maximum number of active requests reached. Dropping %d trace(s).', count)
|
|
64
|
+
}
|
|
53
65
|
this._encoder.reset()
|
|
54
66
|
done()
|
|
55
67
|
return
|
|
@@ -76,7 +88,7 @@ class AgentlessWriter extends BaseWriter {
|
|
|
76
88
|
/**
|
|
77
89
|
* Sends the encoded payload to the intake endpoint.
|
|
78
90
|
* @param {Buffer} data - The encoded JSON payload
|
|
79
|
-
* @param {number} count - Number of
|
|
91
|
+
* @param {number} count - Number of traces in the payload
|
|
80
92
|
* @param {Function} done - Callback when complete
|
|
81
93
|
*/
|
|
82
94
|
_sendPayload (data, count, done) {
|
|
@@ -87,7 +99,11 @@ class AgentlessWriter extends BaseWriter {
|
|
|
87
99
|
}
|
|
88
100
|
|
|
89
101
|
if (!this._url) {
|
|
90
|
-
|
|
102
|
+
if (!this.#urlMissing) {
|
|
103
|
+
this.#urlMissing = true
|
|
104
|
+
log.error('No valid URL configured for agentless trace intake. Traces will not be sent.')
|
|
105
|
+
}
|
|
106
|
+
log.debug('Dropping %d trace(s) due to missing URL', count)
|
|
91
107
|
done()
|
|
92
108
|
return
|
|
93
109
|
}
|
|
@@ -96,9 +112,9 @@ class AgentlessWriter extends BaseWriter {
|
|
|
96
112
|
if (!apiKey) {
|
|
97
113
|
if (!this.#apiKeyMissing) {
|
|
98
114
|
this.#apiKeyMissing = true
|
|
99
|
-
log.error('DD_API_KEY is required for agentless
|
|
115
|
+
log.error('DD_API_KEY is required for agentless trace intake. Set DD_API_KEY. Traces will not be sent.')
|
|
100
116
|
}
|
|
101
|
-
log.debug('Dropping %d
|
|
117
|
+
log.debug('Dropping %d trace(s) due to missing DD_API_KEY', count)
|
|
102
118
|
done()
|
|
103
119
|
return
|
|
104
120
|
}
|
|
@@ -110,6 +126,7 @@ class AgentlessWriter extends BaseWriter {
|
|
|
110
126
|
headers: {
|
|
111
127
|
'Content-Type': 'application/json',
|
|
112
128
|
'dd-api-key': apiKey,
|
|
129
|
+
'X-Datadog-Trace-Count': String(count),
|
|
113
130
|
'Datadog-Meta-Lang': 'nodejs',
|
|
114
131
|
'Datadog-Meta-Lang-Version': process.version,
|
|
115
132
|
'Datadog-Meta-Lang-Interpreter': process.versions.bun ? 'JavaScriptCore' : 'v8',
|
|
@@ -137,42 +154,42 @@ class AgentlessWriter extends BaseWriter {
|
|
|
137
154
|
* Logs request errors with status-specific guidance.
|
|
138
155
|
* @param {Error} err - The error object
|
|
139
156
|
* @param {number} statusCode - HTTP status code (if available)
|
|
140
|
-
* @param {number} count - Number of
|
|
157
|
+
* @param {number} count - Number of traces that were being sent
|
|
141
158
|
*/
|
|
142
159
|
_logRequestError (err, statusCode, count) {
|
|
143
160
|
if (statusCode === 401 || statusCode === 403) {
|
|
144
161
|
log.error(
|
|
145
|
-
'Authentication failed sending %d
|
|
162
|
+
'Authentication failed sending %d trace(s) (status %s). Verify DD_API_KEY is valid.',
|
|
146
163
|
count,
|
|
147
164
|
statusCode
|
|
148
165
|
)
|
|
149
166
|
} else if (statusCode === 404) {
|
|
150
167
|
log.error(
|
|
151
|
-
'
|
|
168
|
+
'Trace intake endpoint not found (status %s). Verify DD_SITE is correctly configured. %d trace(s) dropped.',
|
|
152
169
|
statusCode,
|
|
153
170
|
count
|
|
154
171
|
)
|
|
155
172
|
} else if (statusCode === 429) {
|
|
156
173
|
log.error(
|
|
157
|
-
'Rate limited by
|
|
174
|
+
'Rate limited by trace intake (status 429). %d trace(s) dropped.',
|
|
158
175
|
count
|
|
159
176
|
)
|
|
160
177
|
} else if (statusCode >= 500) {
|
|
161
178
|
log.error(
|
|
162
|
-
'
|
|
179
|
+
'Trace intake server error (status %s). %d trace(s) dropped. This may be transient.',
|
|
163
180
|
statusCode,
|
|
164
181
|
count
|
|
165
182
|
)
|
|
166
183
|
} else if (statusCode) {
|
|
167
184
|
log.error(
|
|
168
|
-
'Error sending agentless payload (status %s): %s. %d
|
|
185
|
+
'Error sending agentless payload (status %s): %s. %d trace(s) dropped.',
|
|
169
186
|
statusCode,
|
|
170
187
|
err.message,
|
|
171
188
|
count
|
|
172
189
|
)
|
|
173
190
|
} else {
|
|
174
191
|
log.error(
|
|
175
|
-
'Network error sending %d
|
|
192
|
+
'Network error sending %d trace(s) to %s: %s',
|
|
176
193
|
count,
|
|
177
194
|
this._url?.hostname || 'unknown',
|
|
178
195
|
err.message
|
|
@@ -38,6 +38,8 @@ module.exports = {
|
|
|
38
38
|
TOTAL_TOKENS_METRIC_KEY: 'total_tokens',
|
|
39
39
|
CACHE_READ_INPUT_TOKENS_METRIC_KEY: 'cache_read_input_tokens',
|
|
40
40
|
CACHE_WRITE_INPUT_TOKENS_METRIC_KEY: 'cache_write_input_tokens',
|
|
41
|
+
CACHE_WRITE_5M_INPUT_TOKENS_METRIC_KEY: 'ephemeral_5m_input_tokens',
|
|
42
|
+
CACHE_WRITE_1H_INPUT_TOKENS_METRIC_KEY: 'ephemeral_1h_input_tokens',
|
|
41
43
|
REASONING_OUTPUT_TOKENS_METRIC_KEY: 'reasoning_output_tokens',
|
|
42
44
|
|
|
43
45
|
DROPPED_IO_COLLECTION_ERROR: 'dropped_io',
|
|
@@ -253,6 +253,15 @@ class AnthropicLLMObsPlugin extends LLMObsPlugin {
|
|
|
253
253
|
if (cacheWriteTokens != null) metrics.cacheWriteTokens = cacheWriteTokens
|
|
254
254
|
if (cacheReadTokens != null) metrics.cacheReadTokens = cacheReadTokens
|
|
255
255
|
|
|
256
|
+
const cacheCreation = usage.cache_creation
|
|
257
|
+
if (cacheCreation) {
|
|
258
|
+
metrics.cacheWrite5mTokens = cacheCreation.ephemeral_5m_input_tokens ?? 0
|
|
259
|
+
metrics.cacheWrite1hTokens = cacheCreation.ephemeral_1h_input_tokens ?? 0
|
|
260
|
+
} else if (cacheWriteTokens != null) {
|
|
261
|
+
metrics.cacheWrite5mTokens = cacheWriteTokens
|
|
262
|
+
metrics.cacheWrite1hTokens = 0
|
|
263
|
+
}
|
|
264
|
+
|
|
256
265
|
this._tagger.tagMetrics(span, metrics)
|
|
257
266
|
}
|
|
258
267
|
|
|
@@ -22,6 +22,8 @@ const {
|
|
|
22
22
|
ROOT_PARENT_ID,
|
|
23
23
|
CACHE_READ_INPUT_TOKENS_METRIC_KEY,
|
|
24
24
|
CACHE_WRITE_INPUT_TOKENS_METRIC_KEY,
|
|
25
|
+
CACHE_WRITE_5M_INPUT_TOKENS_METRIC_KEY,
|
|
26
|
+
CACHE_WRITE_1H_INPUT_TOKENS_METRIC_KEY,
|
|
25
27
|
INPUT_TOKENS_METRIC_KEY,
|
|
26
28
|
OUTPUT_TOKENS_METRIC_KEY,
|
|
27
29
|
TOTAL_TOKENS_METRIC_KEY,
|
|
@@ -185,6 +187,12 @@ class LLMObsTagger {
|
|
|
185
187
|
case 'cacheWriteTokens':
|
|
186
188
|
processedKey = CACHE_WRITE_INPUT_TOKENS_METRIC_KEY
|
|
187
189
|
break
|
|
190
|
+
case 'cacheWrite5mTokens':
|
|
191
|
+
processedKey = CACHE_WRITE_5M_INPUT_TOKENS_METRIC_KEY
|
|
192
|
+
break
|
|
193
|
+
case 'cacheWrite1hTokens':
|
|
194
|
+
processedKey = CACHE_WRITE_1H_INPUT_TOKENS_METRIC_KEY
|
|
195
|
+
break
|
|
188
196
|
case 'reasoningOutputTokens':
|
|
189
197
|
processedKey = REASONING_OUTPUT_TOKENS_METRIC_KEY
|
|
190
198
|
break
|
|
@@ -667,6 +667,7 @@ class TextMapPropagator {
|
|
|
667
667
|
}
|
|
668
668
|
|
|
669
669
|
_extractBaggageItems (carrier, spanContext) {
|
|
670
|
+
removeAllBaggageItems()
|
|
670
671
|
if (!this._hasPropagationStyle('extract', 'baggage')) return
|
|
671
672
|
if (!carrier?.baggage) return
|
|
672
673
|
const baggages = carrier.baggage.split(',')
|
|
@@ -27,16 +27,21 @@ class ApolloBasePlugin extends TracingPlugin {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
end (ctx) {
|
|
30
|
-
// Only synchronous operations would have `result` or `error` on `end`.
|
|
31
30
|
if (!ctx.hasOwnProperty('result') && !ctx.hasOwnProperty('error')) return
|
|
31
|
+
this.onEnd(ctx)
|
|
32
32
|
ctx?.currentStore?.span?.finish()
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
asyncStart (ctx) {
|
|
36
|
-
|
|
36
|
+
this.onAsyncStart(ctx)
|
|
37
|
+
ctx?.currentStore?.span?.finish()
|
|
37
38
|
return ctx.parentStore
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
onEnd (ctx) {}
|
|
42
|
+
|
|
43
|
+
onAsyncStart (ctx) {}
|
|
44
|
+
|
|
40
45
|
getServiceName () {
|
|
41
46
|
return this.serviceName({
|
|
42
47
|
id: `${this.constructor.id}.${this.constructor.operation}`,
|
|
@@ -6,6 +6,7 @@ const plugins = {
|
|
|
6
6
|
get '@aws-sdk/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
|
|
7
7
|
get '@azure/event-hubs' () { return require('../../../datadog-plugin-azure-event-hubs/src') },
|
|
8
8
|
get '@azure/functions' () { return require('../../../datadog-plugin-azure-functions/src') },
|
|
9
|
+
get 'durable-functions' () { return require('../../../datadog-plugin-azure-durable-functions/src') },
|
|
9
10
|
get '@azure/service-bus' () { return require('../../../datadog-plugin-azure-service-bus/src') },
|
|
10
11
|
get '@cucumber/cucumber' () { return require('../../../datadog-plugin-cucumber/src') },
|
|
11
12
|
get '@playwright/test' () { return require('../../../datadog-plugin-playwright/src') },
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { readFileSync } = require('fs')
|
|
3
|
+
const { readFileSync, readdirSync, existsSync } = require('fs')
|
|
4
|
+
const path = require('path')
|
|
4
5
|
const { getEnvironmentVariable, getEnvironmentVariables, getValueFromEnvSources } = require('../../config/helper')
|
|
5
6
|
const {
|
|
6
7
|
GIT_BRANCH,
|
|
@@ -102,8 +103,92 @@ function getGitHubEventPayload () {
|
|
|
102
103
|
return JSON.parse(readFileSync(path, 'utf8'))
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
function getJobIDFromDiagFile (runnerTemp) {
|
|
107
|
+
if (!runnerTemp || !existsSync(runnerTemp)) { return null }
|
|
108
|
+
|
|
109
|
+
// RUNNER_TEMP usually looks like:
|
|
110
|
+
// Linux/mac hosted: /home/runner/work/_temp
|
|
111
|
+
// Windows hosted: C:\actions-runner\_work\_temp
|
|
112
|
+
// Self-hosted (unix): /opt/actions-runner/_work/_temp
|
|
113
|
+
|
|
114
|
+
const workDir = path.dirname(runnerTemp) // .../work or .../_work
|
|
115
|
+
const runnerRoot = path.dirname(workDir) // /home/runner/ (runner root)
|
|
116
|
+
|
|
117
|
+
const dirs = [
|
|
118
|
+
path.join(runnerRoot, 'cached', '_diag'),
|
|
119
|
+
path.join(runnerRoot, '_diag'),
|
|
120
|
+
path.join(runnerRoot, 'actions-runner', 'cached', '_diag'),
|
|
121
|
+
path.join(runnerRoot, 'actions-runner', '_diag'),
|
|
122
|
+
]
|
|
123
|
+
|
|
124
|
+
const isWin = process.platform === 'win32'
|
|
125
|
+
|
|
126
|
+
// Hardcoded fallbacks
|
|
127
|
+
if (isWin) {
|
|
128
|
+
dirs.push(
|
|
129
|
+
'C:/actions-runner/cached/_diag',
|
|
130
|
+
'C:/actions-runner/_diag',
|
|
131
|
+
)
|
|
132
|
+
} else {
|
|
133
|
+
dirs.push(
|
|
134
|
+
'/home/runner/actions-runner/cached/_diag',
|
|
135
|
+
'/home/runner/actions-runner/_diag',
|
|
136
|
+
'/opt/actions-runner/_diag',
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Remove duplicates
|
|
141
|
+
const possibleDiagsPaths = [...new Set(dirs)]
|
|
142
|
+
|
|
143
|
+
// This will hold the names of the worker log files that (potentially) contain the Job ID
|
|
144
|
+
let workerLogFiles = []
|
|
145
|
+
|
|
146
|
+
// This will hold the chosen diagnostics path (between the ones that are contemplated in possibleDiagsPath)
|
|
147
|
+
let chosenDiagPath = ''
|
|
148
|
+
|
|
149
|
+
for (const diagPath of possibleDiagsPaths) {
|
|
150
|
+
try {
|
|
151
|
+
// Obtain a list of fs.Dirent objects of the files in diagPath
|
|
152
|
+
const files = readdirSync(diagPath, { withFileTypes: true })
|
|
153
|
+
|
|
154
|
+
// Check if there are valid potential log files
|
|
155
|
+
const potentialLogs = files
|
|
156
|
+
.filter((file) => file.isFile() && file.name.startsWith('Worker_'))
|
|
157
|
+
.map((file) => file.name)
|
|
158
|
+
|
|
159
|
+
if (potentialLogs.length > 0) {
|
|
160
|
+
chosenDiagPath = diagPath
|
|
161
|
+
workerLogFiles = potentialLogs
|
|
162
|
+
break // No need to keep looking for more log files
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
// If the directory was not found, just look in the next one
|
|
166
|
+
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
167
|
+
continue
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Any other kind of error must force a return
|
|
171
|
+
return null
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Get the job ID via regex
|
|
176
|
+
for (const logFile of workerLogFiles) {
|
|
177
|
+
const filePath = path.posix.join(chosenDiagPath, logFile)
|
|
178
|
+
const content = readFileSync(filePath, 'utf8')
|
|
179
|
+
|
|
180
|
+
const match = content.match(/"job":\s*{[\s\S]*?"v"\s*:\s*(\d+)(?:\.0)?/)
|
|
181
|
+
|
|
182
|
+
// match[1] is the captured group with the display name
|
|
183
|
+
if (match && match[1]) { return match[1] }
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return null
|
|
187
|
+
}
|
|
188
|
+
|
|
105
189
|
module.exports = {
|
|
106
190
|
normalizeRef,
|
|
191
|
+
getJobIDFromDiagFile,
|
|
107
192
|
getCIMetadata () {
|
|
108
193
|
const env = getEnvironmentVariables()
|
|
109
194
|
|
|
@@ -281,6 +366,8 @@ module.exports = {
|
|
|
281
366
|
GITHUB_RUN_ATTEMPT,
|
|
282
367
|
GITHUB_JOB,
|
|
283
368
|
GITHUB_BASE_REF,
|
|
369
|
+
RUNNER_TEMP,
|
|
370
|
+
JOB_CHECK_RUN_ID,
|
|
284
371
|
} = env
|
|
285
372
|
|
|
286
373
|
const repositoryURL = `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}.git`
|
|
@@ -290,7 +377,12 @@ module.exports = {
|
|
|
290
377
|
pipelineURL = `${pipelineURL}/attempts/${GITHUB_RUN_ATTEMPT}`
|
|
291
378
|
}
|
|
292
379
|
|
|
293
|
-
|
|
380
|
+
// Build the job url extracting the job ID. If extraction fails, job url is constructed as a generalized url
|
|
381
|
+
const GITHUB_JOB_ID = JOB_CHECK_RUN_ID ?? getJobIDFromDiagFile(RUNNER_TEMP)
|
|
382
|
+
const jobUrl =
|
|
383
|
+
GITHUB_JOB_ID === null
|
|
384
|
+
? `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commit/${GITHUB_SHA}/checks`
|
|
385
|
+
: `${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/job/${GITHUB_JOB_ID}`
|
|
294
386
|
|
|
295
387
|
const ref = GITHUB_HEAD_REF || GITHUB_REF || ''
|
|
296
388
|
const refKey = ref.includes('tags/') ? GIT_TAG : GIT_BRANCH
|
|
@@ -315,7 +407,7 @@ module.exports = {
|
|
|
315
407
|
GITHUB_RUN_ID,
|
|
316
408
|
GITHUB_RUN_ATTEMPT,
|
|
317
409
|
}),
|
|
318
|
-
[CI_JOB_ID]: GITHUB_JOB,
|
|
410
|
+
[CI_JOB_ID]: GITHUB_JOB_ID ?? GITHUB_JOB,
|
|
319
411
|
}
|
|
320
412
|
if (GITHUB_BASE_REF) { // `pull_request` or `pull_request_target` event
|
|
321
413
|
tags[GIT_PULL_REQUEST_BASE_BRANCH] = GITHUB_BASE_REF
|
|
@@ -5,8 +5,10 @@ const tags = require('../../../../../ext/tags')
|
|
|
5
5
|
|
|
6
6
|
const RESOURCE_NAME = tags.RESOURCE_NAME
|
|
7
7
|
const SPAN_TYPE = tags.SPAN_TYPE
|
|
8
|
+
const SPAN_KIND = tags.SPAN_KIND
|
|
8
9
|
const HTTP_URL = tags.HTTP_URL
|
|
9
10
|
const HTTP_METHOD = tags.HTTP_METHOD
|
|
11
|
+
const HTTP_ROUTE = tags.HTTP_ROUTE
|
|
10
12
|
|
|
11
13
|
const PROXY_HEADER_SYSTEM = 'x-dd-proxy'
|
|
12
14
|
const PROXY_HEADER_START_TIME_MS = 'x-dd-proxy-request-time-ms'
|
|
@@ -15,12 +17,20 @@ const PROXY_HEADER_HTTPMETHOD = 'x-dd-proxy-httpmethod'
|
|
|
15
17
|
const PROXY_HEADER_DOMAIN = 'x-dd-proxy-domain-name'
|
|
16
18
|
const PROXY_HEADER_STAGE = 'x-dd-proxy-stage'
|
|
17
19
|
const PROXY_HEADER_REGION = 'x-dd-proxy-region'
|
|
20
|
+
const PROXY_HEADER_RESOURCE_PATH = 'x-dd-proxy-resource-path'
|
|
21
|
+
const PROXY_HEADER_ACCOUNT_ID = 'x-dd-proxy-account-id'
|
|
22
|
+
const PROXY_HEADER_API_ID = 'x-dd-proxy-api-id'
|
|
23
|
+
const PROXY_HEADER_AWS_USER = 'x-dd-proxy-user'
|
|
18
24
|
|
|
19
25
|
const supportedProxies = {
|
|
20
26
|
'aws-apigateway': {
|
|
21
27
|
spanName: 'aws.apigateway',
|
|
22
28
|
component: 'aws-apigateway',
|
|
23
29
|
},
|
|
30
|
+
'aws-httpapi': {
|
|
31
|
+
spanName: 'aws.httpapi',
|
|
32
|
+
component: 'aws-httpapi',
|
|
33
|
+
},
|
|
24
34
|
'azure-apim': {
|
|
25
35
|
spanName: 'azure.apim',
|
|
26
36
|
component: 'azure-apim',
|
|
@@ -55,10 +65,16 @@ function createInferredProxySpan (headers, childOf, tracer, reqCtx, traceCtx, co
|
|
|
55
65
|
service: proxyContext.domainName || tracer._config.service,
|
|
56
66
|
component: proxySpanInfo.component,
|
|
57
67
|
[SPAN_TYPE]: 'web',
|
|
68
|
+
[SPAN_KIND]: 'server',
|
|
58
69
|
[HTTP_METHOD]: proxyContext.method,
|
|
59
|
-
[HTTP_URL]: proxyContext.domainName + proxyContext.path,
|
|
70
|
+
[HTTP_URL]: 'https://' + proxyContext.domainName + proxyContext.path,
|
|
60
71
|
stage: proxyContext.stage,
|
|
61
72
|
region: proxyContext.region,
|
|
73
|
+
...(proxyContext.resourcePath && { [HTTP_ROUTE]: proxyContext.resourcePath }),
|
|
74
|
+
...(proxyContext.accountId && { account_id: proxyContext.accountId }),
|
|
75
|
+
...(proxyContext.apiId && { apiid: proxyContext.apiId }),
|
|
76
|
+
...(proxyContext.region && { region: proxyContext.region }),
|
|
77
|
+
...(proxyContext.awsUser && { aws_user: proxyContext.awsUser }),
|
|
62
78
|
},
|
|
63
79
|
}, traceCtx, config)
|
|
64
80
|
|
|
@@ -73,8 +89,22 @@ function createInferredProxySpan (headers, childOf, tracer, reqCtx, traceCtx, co
|
|
|
73
89
|
}
|
|
74
90
|
|
|
75
91
|
function setInferredProxySpanTags (span, proxyContext) {
|
|
76
|
-
|
|
92
|
+
const resourcePath = proxyContext.resourcePath || proxyContext.path
|
|
93
|
+
span.setTag(RESOURCE_NAME, `${proxyContext.method} ${resourcePath}`)
|
|
77
94
|
span.setTag('_dd.inferred_span', 1)
|
|
95
|
+
|
|
96
|
+
// Set dd_resource_key as API Gateway ARN if we have the required components
|
|
97
|
+
if (proxyContext.apiId && proxyContext.region) {
|
|
98
|
+
const partition = 'aws'
|
|
99
|
+
// API Gateway v1 (REST): arn:{partition}:apigateway:{region}::/restapis/{api-id}
|
|
100
|
+
// API Gateway v2 (HTTP): arn:{partition}:apigateway:{region}::/apis/{api-id}
|
|
101
|
+
const apiType = proxyContext.proxySystemName === 'aws-httpapi' ? 'apis' : 'restapis'
|
|
102
|
+
span.setTag(
|
|
103
|
+
'dd_resource_key',
|
|
104
|
+
`arn:${partition}:apigateway:${proxyContext.region}::/${apiType}/${proxyContext.apiId}`
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
78
108
|
return span
|
|
79
109
|
}
|
|
80
110
|
|
|
@@ -98,6 +128,10 @@ function extractInferredProxyContext (headers) {
|
|
|
98
128
|
domainName: headers[PROXY_HEADER_DOMAIN],
|
|
99
129
|
proxySystemName: headers[PROXY_HEADER_SYSTEM],
|
|
100
130
|
region: headers[PROXY_HEADER_REGION],
|
|
131
|
+
resourcePath: headers[PROXY_HEADER_RESOURCE_PATH],
|
|
132
|
+
accountId: headers[PROXY_HEADER_ACCOUNT_ID],
|
|
133
|
+
apiId: headers[PROXY_HEADER_API_ID],
|
|
134
|
+
awsUser: headers[PROXY_HEADER_AWS_USER],
|
|
101
135
|
}
|
|
102
136
|
}
|
|
103
137
|
|
|
@@ -410,6 +410,13 @@ const web = {
|
|
|
410
410
|
},
|
|
411
411
|
})
|
|
412
412
|
},
|
|
413
|
+
setRouteOrEndpointTag (req) {
|
|
414
|
+
const context = contexts.get(req)
|
|
415
|
+
|
|
416
|
+
if (!context) return
|
|
417
|
+
|
|
418
|
+
applyRouteOrEndpointTag(context)
|
|
419
|
+
},
|
|
413
420
|
}
|
|
414
421
|
|
|
415
422
|
function addAllowHeaders (req, res, headers) {
|
|
@@ -481,18 +488,9 @@ function addRequestTags (context, spanType) {
|
|
|
481
488
|
}
|
|
482
489
|
|
|
483
490
|
function addResponseTags (context) {
|
|
484
|
-
const { req, res,
|
|
491
|
+
const { req, res, inferredProxySpan, span } = context
|
|
485
492
|
|
|
486
|
-
|
|
487
|
-
if (route) {
|
|
488
|
-
// Use http.route from trusted framework instrumentation
|
|
489
|
-
span.setTag(HTTP_ROUTE, route)
|
|
490
|
-
} else if (config.resourceRenamingEnabled) {
|
|
491
|
-
// Route is unavailable, compute http.endpoint instead
|
|
492
|
-
const url = span.context()._tags[HTTP_URL]
|
|
493
|
-
const endpoint = url ? calculateHttpEndpoint(url) : '/'
|
|
494
|
-
span.setTag(HTTP_ENDPOINT, endpoint)
|
|
495
|
-
}
|
|
493
|
+
applyRouteOrEndpointTag(context)
|
|
496
494
|
|
|
497
495
|
span.addTags({
|
|
498
496
|
[HTTP_STATUS_CODE]: res.statusCode,
|
|
@@ -504,6 +502,28 @@ function addResponseTags (context) {
|
|
|
504
502
|
web.addStatusError(req, res.statusCode)
|
|
505
503
|
}
|
|
506
504
|
|
|
505
|
+
function applyRouteOrEndpointTag (context) {
|
|
506
|
+
const { paths, span, config } = context
|
|
507
|
+
if (!span) return
|
|
508
|
+
const tags = span.context()._tags
|
|
509
|
+
const route = paths.join('')
|
|
510
|
+
|
|
511
|
+
if (route) {
|
|
512
|
+
// Use http.route from trusted framework instrumentation.
|
|
513
|
+
span.setTag(HTTP_ROUTE, route)
|
|
514
|
+
return
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (!config.resourceRenamingEnabled || tags[HTTP_ENDPOINT]) {
|
|
518
|
+
return
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Route is unavailable, compute http.endpoint once.
|
|
522
|
+
const url = tags[HTTP_URL]
|
|
523
|
+
const endpoint = url ? calculateHttpEndpoint(url) : '/'
|
|
524
|
+
span.setTag(HTTP_ENDPOINT, endpoint)
|
|
525
|
+
}
|
|
526
|
+
|
|
507
527
|
function addResourceTag (context) {
|
|
508
528
|
const { req, span } = context
|
|
509
529
|
const tags = span.context()._tags
|
|
@@ -6,7 +6,7 @@ const DatadogTracer = require('./tracer')
|
|
|
6
6
|
const getConfig = require('./config')
|
|
7
7
|
const runtimeMetrics = require('./runtime_metrics')
|
|
8
8
|
const log = require('./log')
|
|
9
|
-
const { setStartupLogPluginManager } = require('./startup-log')
|
|
9
|
+
const { setStartupLogPluginManager, startupLog } = require('./startup-log')
|
|
10
10
|
const DynamicInstrumentation = require('./debugger')
|
|
11
11
|
const telemetry = require('./telemetry')
|
|
12
12
|
const nomenclature = require('./service-naming')
|
|
@@ -292,6 +292,7 @@ class Tracer extends NoopProxy {
|
|
|
292
292
|
this._pluginManager.configure(config)
|
|
293
293
|
DynamicInstrumentation.configure(config)
|
|
294
294
|
setStartupLogPluginManager(this._pluginManager)
|
|
295
|
+
startupLog()
|
|
295
296
|
}
|
|
296
297
|
}
|
|
297
298
|
|
|
@@ -11,6 +11,7 @@ const log = require('../log')
|
|
|
11
11
|
const { getValueFromEnvSources } = require('../config/helper')
|
|
12
12
|
|
|
13
13
|
const { NODE_MAJOR } = require('../../../../version')
|
|
14
|
+
const processTags = require('../process-tags')
|
|
14
15
|
// TODO: This environment variable may not be changed, since the agent expects a flush every ten seconds.
|
|
15
16
|
// It is only a variable for testing. Think about alternatives.
|
|
16
17
|
const DD_RUNTIME_METRICS_FLUSH_INTERVAL = getValueFromEnvSources('DD_RUNTIME_METRICS_FLUSH_INTERVAL') ?? '10000'
|
|
@@ -38,6 +39,12 @@ module.exports = {
|
|
|
38
39
|
this.stop()
|
|
39
40
|
const clientConfig = DogStatsDClient.generateClientConfig(config)
|
|
40
41
|
|
|
42
|
+
if (config.propagateProcessTags?.enabled) {
|
|
43
|
+
for (const tag of processTags.tagsArray) {
|
|
44
|
+
clientConfig.tags.push(tag)
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
const trackEventLoop = config.runtimeMetrics.eventLoop !== false
|
|
42
49
|
const trackGc = config.runtimeMetrics.gc !== false
|
|
43
50
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { SAMPLING_MECHANISM_APPSEC } = require('../constants')
|
|
3
|
+
const { SAMPLING_MECHANISM_APPSEC, SAMPLING_MECHANISM_AI_GUARD } = require('../constants')
|
|
4
4
|
const RateLimiter = require('../rate_limiter')
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -26,6 +26,7 @@ const PRODUCTS = {
|
|
|
26
26
|
DSM: { id: 1 << 2 },
|
|
27
27
|
DJM: { id: 1 << 3 },
|
|
28
28
|
DBM: { id: 1 << 4 },
|
|
29
|
+
AI_GUARD: { id: 1 << 5, mechanism: SAMPLING_MECHANISM_AI_GUARD },
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
module.exports = {
|