Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@
/packages/dd-trace/test/plugins/util/test.spec.js @DataDog/ci-app-libraries
/packages/dd-trace/test/plugins/util/test-environment.spec.js @DataDog/ci-app-libraries
/packages/dd-trace/src/encode/agentless-ci-visibility.js @DataDog/ci-app-libraries
/packages/dd-trace/src/encode/agentless-json.js @DataDog/ci-app-libraries
/packages/dd-trace/src/encode/coverage-ci-visibility.js @DataDog/ci-app-libraries
/packages/dd-trace/src/encode/tags-processors.js @DataDog/ci-app-libraries
/packages/dd-trace/src/exporters/agentless/ @DataDog/ci-app-libraries
Expand Down
9 changes: 7 additions & 2 deletions ci/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ if (isValidationModeRequested && !isValidationMode) {
let shouldInit = isValidationModeRequested
? isValidationMode && !isFalse(getEnvironmentVariable('DD_CIVISIBILITY_ENABLED'))
: getValueFromEnvSources('DD_CIVISIBILITY_ENABLED', true) !== false
const isAgentlessEnabled = getValueFromEnvSources('DD_CIVISIBILITY_AGENTLESS_ENABLED')
const isGlobalAgentlessEnabled = getValueFromEnvSources('DD_AGENTLESS_ENABLED')
const isAgentlessEnabled = isGlobalAgentlessEnabled ||
getValueFromEnvSources('DD_CIVISIBILITY_AGENTLESS_ENABLED')

if (!isTestWorker && isPackageManager()) {
log.debug('dd-trace is not initialized in a package manager.')
Expand All @@ -85,8 +87,11 @@ if (isTestWorker) {
exporter: 'datadog',
}
} else {
const configurationName = isGlobalAgentlessEnabled
? 'DD_AGENTLESS_ENABLED'
: 'DD_CIVISIBILITY_AGENTLESS_ENABLED'
console.error(
'DD_CIVISIBILITY_AGENTLESS_ENABLED is set, but neither ' +
`${configurationName} is set, but neither ` +
'DD_API_KEY nor DATADOG_API_KEY are set in your environment, so ' +
'dd-trace will not be initialized.'
)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@
"opentracing": ">=0.14.7"
},
"optionalDependencies": {
"@datadog/libdatadog": "0.12.1",
"@datadog/libdatadog": "^0.19.0",
"@datadog/native-appsec": "11.0.2",
"@datadog/native-iast-taint-tracking": "4.2.1",
"@datadog/native-metrics": "4.0.0",
Expand Down
2 changes: 2 additions & 0 deletions packages/dd-trace/src/config/generated-config-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export interface GeneratedConfig {
};
dbmPropagationMode: "disabled" | "service" | "full" | "dynamic_service";
DD_ACTION_EXECUTION_ID: string | undefined;
DD_AGENTLESS_ENABLED: boolean;
DD_AGENTLESS_LOG_SUBMISSION_ENABLED: boolean;
DD_AGENTLESS_LOG_SUBMISSION_URL: string | undefined;
DD_API_KEY: string | undefined;
Expand Down Expand Up @@ -610,6 +611,7 @@ export interface GeneratedEnvVarConfig {
DATADOG_API_KEY: string | undefined;
DD_ACTION_EXECUTION_ID: string | undefined;
DD_AGENT_HOST: string;
DD_AGENTLESS_ENABLED: boolean;
DD_AGENTLESS_LOG_SUBMISSION_ENABLED: boolean;
DD_AGENTLESS_LOG_SUBMISSION_URL: string | undefined;
DD_AI_GUARD_BLOCK: boolean;
Expand Down
25 changes: 20 additions & 5 deletions packages/dd-trace/src/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -622,11 +622,26 @@ class Config extends ConfigBase {
setAndTrack(this, 'telemetry.DD_INSTRUMENTATION_TELEMETRY_ENABLED', false)
}

// Experimental agentless APM span intake
// When enabled, sends spans directly to Datadog intake without an agent
// TODO: Replace this with a proper configuration
const agentlessEnabled = isTrue(getEnvironmentVariable('_DD_APM_TRACING_AGENTLESS_ENABLED'))
if (agentlessEnabled) {
if (this.DD_AGENTLESS_ENABLED) {
setAndTrack(this, 'DD_AGENTLESS_LOG_SUBMISSION_ENABLED', true)
setAndTrack(this, 'testOptimization.DD_CIVISIBILITY_AGENTLESS_ENABLED', true)
setAndTrack(this, 'llmobs.agentlessEnabled', true)
setAndTrack(this, 'featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE', 'agentless')

setAndTrack(this, 'runtimeMetrics.enabled', false)
setAndTrack(this, 'dsmEnabled', false)
setAndTrack(this, 'DD_CRASHTRACKING_ENABLED', false)

const profilingExporters = this.DD_PROFILING_EXPORTERS.filter(exporter => exporter !== 'agent')
setAndTrack(this, 'DD_PROFILING_EXPORTERS', profilingExporters)
if (profilingExporters.length === 0) {
setAndTrack(this, 'profiling.DD_PROFILING_ENABLED', 'false')
}
}

const agentlessTracingEnabled = this.DD_AGENTLESS_ENABLED ||
isTrue(getEnvironmentVariable('_DD_APM_TRACING_AGENTLESS_ENABLED'))
if (agentlessTracingEnabled && !this.isCiVisibility) {
setAndTrack(this, 'experimental.exporter', 'agentless')
// Disable client-side stats computation
setAndTrack(this, 'stats.DD_TRACE_STATS_COMPUTATION_ENABLED', false)
Expand Down
8 changes: 8 additions & 0 deletions packages/dd-trace/src/config/supported-configurations.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
"default": null
}
],
"DD_AGENTLESS_ENABLED": [
{
"implementation": "A",
"type": "boolean",
"default": "false",
"description": "Enable agentless mode for supported features and disable Agent-only features."
}
],
"DD_AGENTLESS_LOG_SUBMISSION_ENABLED": [
{
"implementation": "A",
Expand Down
10 changes: 9 additions & 1 deletion packages/dd-trace/src/debugger/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@

const getGitMetadata = require('../git_metadata')

/**
* @param {ReturnType<import('../config')>} config
* @param {string} [inputPath]
*/
module.exports = function getDebuggerConfig (config, inputPath) {
const { commitSHA, repositoryUrl } = getGitMetadata(config)
const agentless = config.DD_AGENTLESS_ENABLED

return {
agentless,
apiKey: agentless ? config.DD_API_KEY : undefined,
commitSHA,
debug: config.debug,
dynamicInstrumentation: config.dynamicInstrumentation,
Expand All @@ -16,7 +24,7 @@ module.exports = function getDebuggerConfig (config, inputPath) {
repositoryUrl,
runtimeId: config.tags['runtime-id'],
service: config.service,
url: config.url.toString(),
url: agentless ? `https://debugger-intake.${config.site}` : config.url.toString(),
version: config.version,
inputPath,
}
Expand Down
1 change: 1 addition & 0 deletions packages/dd-trace/src/debugger/constants.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict'

module.exports = {
DEBUGGER_INPUT_DIRECT: '/api/v2/debugger',
DEBUGGER_DIAGNOSTICS_V1: '/debugger/v1/diagnostics',
DEBUGGER_INPUT_V1: '/debugger/v1/input',
DEBUGGER_INPUT_V2: '/debugger/v2/input',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use strict'

/**
* @param {ReturnType<import('../config')>} config - Debugger configuration
* @param {string} path - Request path
* @param {Record<string, string>} headers - Payload headers
* @returns {{method: 'POST', url: string | URL, path: string, headers: Record<string, string>}}
*/
module.exports = function getRequestOptions (config, path, headers) {
if (config.agentless) {
if (config.apiKey !== undefined) headers['DD-API-KEY'] = config.apiKey
headers['DD-EVP-ORIGIN'] = 'agent-debugger'
}

return {
method: 'POST',
url: config.url,
path,
headers,
}
}
47 changes: 7 additions & 40 deletions packages/dd-trace/src/debugger/devtools_client/send.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ const { stringify } = require('querystring')

const { version } = require('../../../../../package.json')
const request = require('../../exporters/common/request')
const { GIT_COMMIT_SHA, GIT_REPOSITORY_URL } = require('../../plugins/util/tags')
const { DEBUGGER_DIAGNOSTICS_V1, DEBUGGER_INPUT_V2 } = require('../constants')
const log = require('./log')
const JSONBuffer = require('./json-buffer')
const config = require('./config')
const getRequestOptions = require('./request-options')
const { pruneSnapshot } = require('./snapshot-pruner')
const buildTags = require('./tags')

module.exports = send

Expand All @@ -22,14 +23,7 @@ const ddsource = 'dd_debugger'
const hostname = getHostname()
const service = config.service

const ddtags = buildTags([
['env', config.env],
['version', config.version],
['debugger_version', version],
['host_name', hostname],
[GIT_COMMIT_SHA, config.commitSHA],
[GIT_REPOSITORY_URL, config.repositoryUrl],
])
const ddtags = buildTags(config, hostname, version, log)

let path
setInputPath(config.inputPath)
Expand Down Expand Up @@ -85,7 +79,7 @@ function send (message, logger, dd, snapshot, processTags) {
function onFlush (payload) {
log.debug('[debugger:devtools_client] Flushing probe payload buffer')

request(payload, buildRequestOpts(), (err, res, statusCode) => {
request(payload, buildRequestOptions(), (err, res, statusCode) => {
if (!handleV2FallbackIfNeeded(statusCode, payload) && err) {
log.error('[debugger:devtools_client] Error sending probe payload', err)
}
Expand All @@ -108,7 +102,7 @@ function handleV2FallbackIfNeeded (statusCode, payload) {

setInputPath(DEBUGGER_DIAGNOSTICS_V1)

request(payload, buildRequestOpts(), (err) => {
request(payload, buildRequestOptions(), (err) => {
if (err) {
log.error('[debugger:devtools_client] Error sending probe payload after fallback to %s',
DEBUGGER_DIAGNOSTICS_V1,
Expand All @@ -119,13 +113,8 @@ function handleV2FallbackIfNeeded (statusCode, payload) {
return true
}

function buildRequestOpts () {
return {
method: 'POST',
url: config.url,
path,
headers: { 'Content-Type': 'application/json; charset=utf-8' },
}
function buildRequestOptions () {
return getRequestOptions(config, path, { 'Content-Type': 'application/json; charset=utf-8' })
}

/**
Expand All @@ -135,25 +124,3 @@ function setInputPath (newPath) {
config.inputPath = newPath
path = `${newPath}?${stringify({ ddtags })}`
}

/**
* @param {Array<[string, unknown]>} tags - The tags to serialize.
* @returns {string} The serialized tags.
*/
function buildTags (tags) {
let serializedTags = ''

for (const [key, rawValue] of tags) {
if (rawValue === undefined) continue

if (String(rawValue).includes(',')) {
log.warn('[debugger:devtools_client] Skipping invalid tag value for %s', key)
continue
}

if (serializedTags) serializedTags += ','
serializedTags += `${key}:${rawValue}`
}

return serializedTags
}
17 changes: 11 additions & 6 deletions packages/dd-trace/src/debugger/devtools_client/status.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
'use strict'

const { hostname: getHostname } = require('node:os')
const { stringify } = require('node:querystring')

const { version } = require('../../../../../package.json')
const TTLSet = require('../../../../../vendor/dist/ttl-set')
const request = require('../../exporters/common/request')
const FormData = require('../../exporters/common/form-data')
const { DEBUGGER_DIAGNOSTICS_V1 } = require('../constants')
const config = require('./config')
const JSONBuffer = require('./json-buffer')
const log = require('./log')
const getRequestOptions = require('./request-options')
const buildTags = require('./tags')

module.exports = {
ackReceived,
Expand All @@ -18,6 +24,7 @@ module.exports = {
const ddsource = 'dd_debugger'
const service = config.service
const runtimeId = config.runtimeId
const ddtags = buildTags(config, getHostname(), version, log)

const cache = new TTLSet(60 * 60 * 1000) // 1 hour

Expand Down Expand Up @@ -93,12 +100,10 @@ function onFlush (payload) {
{ filename: 'event.json', contentType: 'application/json; charset=utf-8' }
)

const options = {
method: 'POST',
url: config.url,
path: DEBUGGER_DIAGNOSTICS_V1,
headers: form.getHeaders(),
}
const path = config.agentless
? `${config.inputPath}?${stringify({ ddtags })}`
: DEBUGGER_DIAGNOSTICS_V1
const options = getRequestOptions(config, path, form.getHeaders())

request(form, options, (err) => {
if (err) log.error('[debugger:devtools_client] Error sending diagnostics payload', err)
Expand Down
37 changes: 37 additions & 0 deletions packages/dd-trace/src/debugger/devtools_client/tags.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict'

const { GIT_COMMIT_SHA, GIT_REPOSITORY_URL } = require('../../plugins/util/tags')

/**
* @param {ReturnType<import('../config')>} config - Debugger configuration
* @param {string} hostname - Host name
* @param {string} debuggerVersion - Debugger version
* @param {typeof import('./log')} log - Debugger logger
*/
module.exports = function buildTags (config, hostname, debuggerVersion, log) {
const tags = [
['env', config.env],
['version', config.version],
['debugger_version', debuggerVersion],
['runtime_id', config.agentless ? config.runtimeId : undefined],
['host_name', hostname],
[GIT_COMMIT_SHA, config.commitSHA],
[GIT_REPOSITORY_URL, config.repositoryUrl],
]
let serializedTags = ''

for (const [key, rawValue] of tags) {
if (rawValue === undefined) continue

const value = String(rawValue)
if (value.includes(',')) {
log.warn('[debugger:devtools_client] Skipping invalid tag value for %s', key)
continue
}

if (serializedTags) serializedTags += ','
serializedTags += `${key}:${value}`
}

return serializedTags
}
12 changes: 11 additions & 1 deletion packages/dd-trace/src/debugger/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ const { Worker, MessageChannel, threadId: parentThreadId } = require('worker_thr
const log = require('../log')
const { fetchAgentInfo } = require('../agent/info')
const getDebuggerConfig = require('./config')
const { DEBUGGER_DIAGNOSTICS_V1, DEBUGGER_INPUT_V2, INSPECT_SEGMENT_GLOBAL_PROPERTY } = require('./constants')
const {
DEBUGGER_DIAGNOSTICS_V1,
DEBUGGER_INPUT_DIRECT,
DEBUGGER_INPUT_V2,
INSPECT_SEGMENT_GLOBAL_PROPERTY,
} = require('./constants')
const { installProbeSampler, uninstallProbeSampler } = require('./probe_sampler')

/**
Expand Down Expand Up @@ -215,6 +220,11 @@ function cleanup (error) {
* @param {(endpointPath: string) => void} cb - Callback with the detected endpoint path
*/
function detectDebuggerEndpoint (config, cb) {
if (config.DD_AGENTLESS_ENABLED) {
cb(DEBUGGER_INPUT_DIRECT)
return
}

log.debug('[debugger] Detecting available debugger endpoints...')

fetchAgentInfo(config.url, (err, agentInfo) => {
Expand Down
Loading
Loading