Skip to content

Commit 0b3ab0c

Browse files
authored
chore(ssi): send injection and instrumentation telemetry (#5721)
1 parent 72597c5 commit 0b3ab0c

File tree

13 files changed

+86
-45
lines changed

13 files changed

+86
-45
lines changed

init.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,8 @@
55
var guard = require('./packages/dd-trace/src/guardrails')
66

77
module.exports = guard(function () {
8-
return require('.').init()
8+
var INSTRUMENTED_BY_SSI = require('./packages/dd-trace/src/constants').INSTRUMENTED_BY_SSI
9+
var obj = {}
10+
obj[INSTRUMENTED_BY_SSI] = 'ssi'
11+
return require('.').init(obj)
912
})

integration-tests/helpers/index.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const hookFile = 'dd-trace/loader-hook.mjs'
1818
// This is set by the setShouldKill function
1919
let shouldKill
2020

21-
async function runAndCheckOutput (filename, cwd, expectedOut) {
21+
async function runAndCheckOutput (filename, cwd, expectedOut, expectedSource) {
2222
const proc = spawn(process.execPath, [filename], { cwd, stdio: 'pipe' })
2323
const pid = proc.pid
2424
let out = await new Promise((resolve, reject) => {
@@ -42,7 +42,12 @@ async function runAndCheckOutput (filename, cwd, expectedOut) {
4242
// Debug adds this, which we don't care about in these tests
4343
out = out.replace('Flushing 0 metrics via HTTP\n', '')
4444
}
45-
assert.strictEqual(out, expectedOut)
45+
assert.match(out, new RegExp(expectedOut), `output "${out} does not contain expected output "${expectedOut}"`)
46+
}
47+
48+
if (expectedSource) {
49+
assert.match(out, new RegExp(`instrumentation source: ${expectedSource}`),
50+
`Expected the process to output "${expectedSource}", but logs only contain: "${out}"`)
4651
}
4752
return pid
4853
}
@@ -51,10 +56,10 @@ async function runAndCheckOutput (filename, cwd, expectedOut) {
5156
let sandbox
5257

5358
// This _must_ be used with the useSandbox function
54-
async function runAndCheckWithTelemetry (filename, expectedOut, ...expectedTelemetryPoints) {
59+
async function runAndCheckWithTelemetry (filename, expectedOut, expectedTelemetryPoints, expectedSource) {
5560
const cwd = sandbox.folder
5661
const cleanup = telemetryForwarder(expectedTelemetryPoints)
57-
const pid = await runAndCheckOutput(filename, cwd, expectedOut)
62+
const pid = await runAndCheckOutput(filename, cwd, expectedOut, expectedSource)
5863
const msgs = await cleanup()
5964
if (expectedTelemetryPoints.length === 0) {
6065
// assert no telemetry sent

integration-tests/init.spec.js

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,37 +36,37 @@ function testInjectionScenarios (arg, filename, esmWorks = false) {
3636

3737
if (currentVersionIsSupported) {
3838
context('without DD_INJECTION_ENABLED', () => {
39-
it('should initialize the tracer', () => doTest('init/trace.js', 'true\n'))
40-
it('should initialize instrumentation', () => doTest('init/instrument.js', 'true\n'))
39+
it('should initialize the tracer', () => doTest('init/trace.js', 'true\n', [], 'ssi'))
40+
it('should initialize instrumentation', () => doTest('init/instrument.js', 'true\n', [], 'ssi'))
4141
it(`should ${esmWorks ? '' : 'not '}initialize ESM instrumentation`, () =>
42-
doTest('init/instrument.mjs', `${esmWorks}\n`))
42+
doTest('init/instrument.mjs', `${esmWorks}\n`, []))
4343
})
4444
}
4545
context('with DD_INJECTION_ENABLED', () => {
4646
useEnv({ DD_INJECTION_ENABLED })
4747

48-
it('should not initialize the tracer', () => doTest('init/trace.js', 'false\n'))
49-
it('should not initialize instrumentation', () => doTest('init/instrument.js', 'false\n'))
50-
it('should not initialize ESM instrumentation', () => doTest('init/instrument.mjs', 'false\n'))
48+
it('should not initialize the tracer', () => doTest('init/trace.js', 'false\n', []))
49+
it('should not initialize instrumentation', () => doTest('init/instrument.js', 'false\n', []))
50+
it('should not initialize ESM instrumentation', () => doTest('init/instrument.mjs', 'false\n', []))
5151
})
5252
})
5353
context('when dd-trace in the app dir', () => {
5454
const NODE_OPTIONS = `--no-warnings --${arg} dd-trace/${filename}`
5555
useEnv({ NODE_OPTIONS })
5656

5757
context('without DD_INJECTION_ENABLED', () => {
58-
it('should initialize the tracer', () => doTest('init/trace.js', 'true\n'))
59-
it('should initialize instrumentation', () => doTest('init/instrument.js', 'true\n'))
58+
it('should initialize the tracer', () => doTest('init/trace.js', 'true\n', [], 'ssi'))
59+
it('should initialize instrumentation', () => doTest('init/instrument.js', 'true\n', [], 'ssi'))
6060
it(`should ${esmWorks ? '' : 'not '}initialize ESM instrumentation`, () =>
61-
doTest('init/instrument.mjs', `${esmWorks}\n`))
61+
doTest('init/instrument.mjs', `${esmWorks}\n`, []))
6262
})
6363
context('with DD_INJECTION_ENABLED', () => {
64-
useEnv({ DD_INJECTION_ENABLED })
64+
useEnv({ DD_INJECTION_ENABLED, DD_TRACE_DEBUG })
6565

66-
it('should initialize the tracer', () => doTest('init/trace.js', 'true\n', ...telemetryGood))
67-
it('should initialize instrumentation', () => doTest('init/instrument.js', 'true\n', ...telemetryGood))
66+
it('should initialize the tracer', () => doTest('init/trace.js', 'true\n', telemetryGood, 'ssi'))
67+
it('should initialize instrumentation', () => doTest('init/instrument.js', 'true\n', telemetryGood, 'ssi'))
6868
it(`should ${esmWorks ? '' : 'not '}initialize ESM instrumentation`, () =>
69-
doTest('init/instrument.mjs', `${esmWorks}\n`, ...telemetryGood))
69+
doTest('init/instrument.mjs', `${esmWorks}\n`, telemetryGood, 'ssi'))
7070
})
7171
})
7272
})
@@ -90,13 +90,13 @@ function testRuntimeVersionChecks (arg, filename) {
9090
useEnv({ NODE_OPTIONS })
9191

9292
it('should not initialize the tracer', () =>
93-
doTest('false\n'))
93+
doTest('false\n', []))
9494
context('with DD_INJECTION_ENABLED', () => {
9595
useEnv({ DD_INJECTION_ENABLED })
9696

9797
context('without debug', () => {
98-
it('should not initialize the tracer', () => doTest('false\n', ...telemetryAbort))
99-
it('should initialize the tracer, if DD_INJECT_FORCE', () => doTestForced('true\n', ...telemetryForced))
98+
it('should not initialize the tracer', () => doTest('false\n', telemetryAbort))
99+
it('should initialize the tracer, if DD_INJECT_FORCE', () => doTestForced('true\n', telemetryForced))
100100
})
101101
context('with debug', () => {
102102
useEnv({ DD_TRACE_DEBUG })
@@ -106,38 +106,38 @@ function testRuntimeVersionChecks (arg, filename) {
106106
Found incompatible runtime nodejs ${process.versions.node}, Supported runtimes: nodejs \
107107
>=18.
108108
false
109-
`, ...telemetryAbort))
109+
`, telemetryAbort))
110110
it('should initialize the tracer, if DD_INJECT_FORCE', () =>
111111
doTestForced(`Aborting application instrumentation due to incompatible_runtime.
112112
Found incompatible runtime nodejs ${process.versions.node}, Supported runtimes: nodejs \
113113
>=18.
114114
DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.
115115
Application instrumentation bootstrapping complete
116116
true
117-
`, ...telemetryForced))
117+
`, telemetryForced))
118118
})
119119
})
120120
})
121121
} else {
122122
context('when node version is more than engines field', () => {
123123
useEnv({ NODE_OPTIONS })
124124

125-
it('should initialize the tracer, if no DD_INJECTION_ENABLED', () => doTest('true\n'))
125+
it('should initialize the tracer, if no DD_INJECTION_ENABLED', () => doTest('true\n', [], 'ssi'))
126126
context('with DD_INJECTION_ENABLED', () => {
127127
useEnv({ DD_INJECTION_ENABLED })
128128

129129
context('without debug', () => {
130-
it('should initialize the tracer', () => doTest('true\n', ...telemetryGood))
130+
it('should initialize the tracer', () => doTest('true\n', telemetryGood, 'ssi'))
131131
it('should initialize the tracer, if DD_INJECT_FORCE', () =>
132-
doTestForced('true\n', ...telemetryGood))
132+
doTestForced('true\n', telemetryGood, 'ssi'))
133133
})
134134
context('with debug', () => {
135135
useEnv({ DD_TRACE_DEBUG })
136136

137137
it('should initialize the tracer', () =>
138-
doTest('Application instrumentation bootstrapping complete\ntrue\n', ...telemetryGood))
138+
doTest('Application instrumentation bootstrapping complete\ntrue\n', telemetryGood, 'ssi'))
139139
it('should initialize the tracer, if DD_INJECT_FORCE', () =>
140-
doTestForced('Application instrumentation bootstrapping complete\ntrue\n', ...telemetryGood))
140+
doTestForced('Application instrumentation bootstrapping complete\ntrue\n', telemetryGood, 'ssi'))
141141
})
142142
})
143143
})

integration-tests/init/instrument.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const server = http.createServer((req, res) => {
1515
server.close()
1616
// eslint-disable-next-line no-console
1717
console.log(gotEvent)
18+
// eslint-disable-next-line no-console
19+
console.log('instrumentation source:', global._ddtrace._tracer._config.instrumentationSource)
1820
process.exit()
1921
})
2022
})

integration-tests/init/instrument.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const server = http.createServer((req, res) => {
1515
server.close()
1616
// eslint-disable-next-line no-console
1717
console.log(gotEvent)
18+
// eslint-disable-next-line no-console
19+
console.log('instrumentation source:', global._ddtrace._tracer._config.instrumentationSource)
1820
process.exit()
1921
})
2022
})

integration-tests/init/trace.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
// eslint-disable-next-line no-console
22
console.log(!!global._ddtrace)
3+
// eslint-disable-next-line no-console
4+
console.log('instrumentation source:', global._ddtrace._tracer._config.instrumentationSource)
35
process.exit()

integration-tests/package-guardrails.spec.js

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,44 +29,45 @@ describe('package guardrails', () => {
2929
useEnv({ DD_INJECTION_ENABLED })
3030
it('should not instrument the package, and send telemetry', () =>
3131
runTest('false\n',
32-
'complete', 'injection_forced:false',
33-
'abort.integration', 'integration:bluebird,integration_version:1.0.0'
32+
['complete', 'injection_forced:false',
33+
'abort.integration', 'integration:bluebird,integration_version:1.0.0'
34+
]
3435
))
3536
})
3637
context('with logging disabled', () => {
37-
it('should not instrument the package', () => runTest('false\n'))
38+
it('should not instrument the package', () => runTest('false\n', []))
3839
})
3940
context('with logging enabled', () => {
4041
useEnv({ DD_TRACE_DEBUG })
4142
it('should not instrument the package', () =>
4243
runTest(`Application instrumentation bootstrapping complete
4344
Found incompatible integration version: bluebird@1.0.0
4445
false
45-
`))
46+
`, []))
4647
})
4748
})
4849

4950
context('when package is in range', () => {
5051
context('when bluebird is 2.9.0', () => {
5152
useSandbox(['bluebird@2.9.0'])
52-
it('should instrument the package', () => runTest('true\n'))
53+
it('should instrument the package', () => runTest('true\n', [], 'ssi'))
5354
})
5455
context('when bluebird is 3.7.2', () => {
5556
useSandbox(['bluebird@3.7.2'])
56-
it('should instrument the package', () => runTest('true\n'))
57+
it('should instrument the package', () => runTest('true\n', [], 'ssi'))
5758
})
5859
})
5960

6061
context('when package is in range (fastify)', () => {
6162
context('when fastify is latest', () => {
6263
useSandbox(['fastify'])
63-
it('should instrument the package', () => runTest('true\n'))
64+
it('should instrument the package', () => runTest('true\n', [], 'ssi'))
6465
})
6566
context('when fastify is latest and logging enabled', () => {
6667
useSandbox(['fastify'])
6768
useEnv({ DD_TRACE_DEBUG })
6869
it('should instrument the package', () =>
69-
runTest('Application instrumentation bootstrapping complete\ntrue\n'))
70+
runTest('Application instrumentation bootstrapping complete\ntrue\n', [], 'ssi'))
7071
})
7172
})
7273

@@ -88,13 +89,13 @@ addHook({ name: 'bluebird', versions: ['*'] }, Promise => {
8889
useEnv({ DD_INJECTION_ENABLED })
8990
it('should not instrument the package, and send telemetry', () =>
9091
runTest('false\n',
91-
'complete', 'injection_forced:false',
92-
'error', 'error_type:ReferenceError,integration:bluebird,integration_version:3.7.2'
92+
['complete', 'injection_forced:false',
93+
'error', 'error_type:ReferenceError,integration:bluebird,integration_version:3.7.2']
9394
))
9495
})
9596

9697
context('with logging disabled', () => {
97-
it('should not instrument the package', () => runTest('false\n'))
98+
it('should not instrument the package', () => runTest('false\n', []))
9899
})
99100

100101
context('with logging enabled', () => {
@@ -107,7 +108,7 @@ Error during ddtrace instrumentation of application, aborting.
107108
ReferenceError: this is a test error
108109
at `))
109110
assert.ok(log.includes('\nfalse\n'))
110-
}))
111+
}, []))
111112
})
112113
})
113114
})
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
'use strict'
22

3-
/* eslint-disable no-console */
4-
53
try {
64
const P = require('bluebird')
75

86
const isWrapped = P.prototype._then.toString().includes('AsyncResource')
97

8+
// eslint-disable-next-line no-console
109
console.log(isWrapped)
1110
} catch (e) {
1211
const fastify = require('fastify')
1312

13+
// eslint-disable-next-line no-console
1414
console.log(fastify.toString().startsWith('function fastifyWithTrace'))
1515
}
16+
if (global._ddtrace) {
17+
// eslint-disable-next-line no-console
18+
console.log('instrumentation source:', global._ddtrace._tracer._config.instrumentationSource)
19+
}

packages/dd-trace/src/config.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ const { getGitMetadataFromGitProperties, removeUserSensitiveInfo } = require('./
1515
const { updateConfig } = require('./telemetry')
1616
const telemetryMetrics = require('./telemetry/metrics')
1717
const { isInServerlessEnvironment, getIsGCPFunction, getIsAzureFunction } = require('./serverless')
18-
const { ORIGIN_KEY, GRPC_CLIENT_ERROR_STATUSES, GRPC_SERVER_ERROR_STATUSES } = require('./constants')
18+
const {
19+
ORIGIN_KEY, GRPC_CLIENT_ERROR_STATUSES, GRPC_SERVER_ERROR_STATUSES, INSTRUMENTED_BY_SSI
20+
} = require('./constants')
1921
const { appendRules } = require('./payload-tagging/config')
2022
const { getEnvironmentVariable, getEnvironmentVariables } = require('./config-helper')
2123

@@ -522,6 +524,8 @@ class Config {
522524
this._setValue(defaults, 'iast.telemetryVerbosity', 'INFORMATION')
523525
this._setValue(defaults, 'iast.stackTrace.enabled', true)
524526
this._setValue(defaults, 'injectionEnabled', [])
527+
this._setValue(defaults, 'instrumentationSource', 'manual')
528+
this._setValue(defaults, 'injectForce', null)
525529
this._setValue(defaults, 'isAzureFunction', false)
526530
this._setValue(defaults, 'isCiVisibility', false)
527531
this._setValue(defaults, 'isEarlyFlakeDetectionEnabled', false)
@@ -701,6 +705,7 @@ class Config {
701705
DD_IAST_TELEMETRY_VERBOSITY,
702706
DD_IAST_STACK_TRACE_ENABLED,
703707
DD_INJECTION_ENABLED,
708+
DD_INJECT_FORCE,
704709
DD_INSTRUMENTATION_TELEMETRY_ENABLED,
705710
DD_INSTRUMENTATION_CONFIG_ID,
706711
DD_LOGS_INJECTION,
@@ -892,6 +897,7 @@ class Config {
892897
this._setString(env, 'iast.telemetryVerbosity', DD_IAST_TELEMETRY_VERBOSITY)
893898
this._setBoolean(env, 'iast.stackTrace.enabled', DD_IAST_STACK_TRACE_ENABLED)
894899
this._setArray(env, 'injectionEnabled', DD_INJECTION_ENABLED)
900+
this._setBoolean(env, 'injectForce', DD_INJECT_FORCE)
895901
this._setBoolean(env, 'isAzureFunction', getIsAzureFunction())
896902
this._setBoolean(env, 'isGCPFunction', getIsGCPFunction())
897903
this._setValue(env, 'langchain.spanCharLimit', maybeInt(DD_LANGCHAIN_SPAN_CHAR_LIMIT))
@@ -1127,6 +1133,9 @@ class Config {
11271133
this._setValue(opts, 'iast.securityControlsConfiguration', options.iast?.securityControlsConfiguration)
11281134
this._setBoolean(opts, 'iast.stackTrace.enabled', options.iast?.stackTrace?.enabled)
11291135
this._setString(opts, 'iast.telemetryVerbosity', options.iast && options.iast.telemetryVerbosity)
1136+
if (options[INSTRUMENTED_BY_SSI]) {
1137+
this._setString(opts, 'instrumentationSource', options[INSTRUMENTED_BY_SSI])
1138+
}
11301139
this._setBoolean(opts, 'isCiVisibility', options.isCiVisibility)
11311140
this._setBoolean(opts, 'legacyBaggageEnabled', options.legacyBaggageEnabled)
11321141
this._setBoolean(opts, 'llmobs.agentlessEnabled', options.llmobs?.agentlessEnabled)

packages/dd-trace/src/constants.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,6 @@ module.exports = {
5353
SPAN_POINTER_DIRECTION: Object.freeze({
5454
UPSTREAM: 'u',
5555
DOWNSTREAM: 'd'
56-
})
56+
}),
57+
INSTRUMENTED_BY_SSI: Symbol('_dd.instrumented.by.ssi')
5758
}

packages/dd-trace/src/guardrails/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ function guard (fn) {
5454
}
5555

5656
if (!clobberBailout && (!initBailout || forced)) {
57+
// Ensure the instrumentation source is set for the current process and potential
58+
// child processes.
5759
var result = fn()
5860
telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')])
5961
log.info('Application instrumentation bootstrapping complete')

packages/dd-trace/src/telemetry/telemetry.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,10 @@ const nameMapping = {
321321
clientIpHeader: 'DD_TRACE_CLIENT_IP_HEADER',
322322
'grpc.client.error.statuses': 'DD_GRPC_CLIENT_ERROR_STATUSES',
323323
'grpc.server.error.statuses': 'DD_GRPC_SERVER_ERROR_STATUSES',
324-
traceId128BitLoggingEnabled: 'DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED'
324+
traceId128BitLoggingEnabled: 'DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED',
325+
instrumentationSource: 'instrumentation_source',
326+
injectionEnabled: 'ssi_injection_enabled',
327+
injectForce: 'ssi_forced_injection_enabled'
325328
}
326329

327330
const namesNeedFormatting = new Set(['DD_TAGS', 'peerServiceMapping', 'serviceMapping'])

packages/dd-trace/test/config.spec.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ describe('Config', () => {
341341
expect(config).to.have.nested.property('llmobs.mlApp', undefined)
342342
expect(config).to.have.nested.property('llmobs.agentlessEnabled', undefined)
343343
expect(config).to.have.nested.property('llmobs.enabled', false)
344+
expect(config).to.have.nested.deep.property('injectionEnabled', [])
345+
expect(config).to.have.nested.property('instrumentationSource', 'manual')
346+
expect(config).to.have.nested.property('injectForce', null)
344347

345348
expect(updateConfig).to.be.calledOnce
346349

@@ -406,7 +409,9 @@ describe('Config', () => {
406409
{ name: 'iast.securityControlsConfiguration', value: null, origin: 'default' },
407410
{ name: 'iast.telemetryVerbosity', value: 'INFORMATION', origin: 'default' },
408411
{ name: 'iast.stackTrace.enabled', value: true, origin: 'default' },
412+
{ name: 'instrumentationSource', value: 'manual', origin: 'default' },
409413
{ name: 'injectionEnabled', value: [], origin: 'default' },
414+
{ name: 'injectForce', value: null, origin: 'default' },
410415
{ name: 'isCiVisibility', value: false, origin: 'default' },
411416
{ name: 'isEarlyFlakeDetectionEnabled', value: false, origin: 'default' },
412417
{ name: 'isFlakyTestRetriesEnabled', value: false, origin: 'default' },
@@ -601,6 +606,7 @@ describe('Config', () => {
601606
process.env.DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED = 'true'
602607
process.env.DD_PROFILING_ENABLED = 'true'
603608
process.env.DD_INJECTION_ENABLED = 'profiler'
609+
process.env.DD_INJECT_FORCE = 'false'
604610
process.env.DD_API_SECURITY_ENABLED = 'true'
605611
process.env.DD_API_SECURITY_SAMPLE_DELAY = '25'
606612
process.env.DD_INSTRUMENTATION_INSTALL_ID = '68e75c48-57ca-4a12-adfc-575c4b05fcbe'
@@ -787,6 +793,7 @@ describe('Config', () => {
787793
{ name: 'iast.stackTrace.enabled', value: false, origin: 'env_var' },
788794
{ name: 'instrumentation_config_id', value: 'abcdef123', origin: 'env_var' },
789795
{ name: 'injectionEnabled', value: ['profiler'], origin: 'env_var' },
796+
{ name: 'injectForce', value: false, origin: 'env_var' },
790797
{ name: 'isGCPFunction', value: false, origin: 'env_var' },
791798
{ name: 'middlewareTracingEnabled', value: false, origin: 'env_var' },
792799
{ name: 'peerServiceMapping', value: process.env.DD_TRACE_PEER_SERVICE_MAPPING, origin: 'env_var' },

0 commit comments

Comments
 (0)