From 1b9c8c73158a562d40191ef48e3e2cd8477e3c14 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Wed, 30 Jul 2025 15:10:27 -0400 Subject: [PATCH 01/24] first draft --- packages/dd-trace/src/guardrails/index.js | 13 +++++++++++++ packages/dd-trace/src/guardrails/telemetry.js | 17 ++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/dd-trace/src/guardrails/index.js b/packages/dd-trace/src/guardrails/index.js index ab60c2d550f..42243b4c444 100644 --- a/packages/dd-trace/src/guardrails/index.js +++ b/packages/dd-trace/src/guardrails/index.js @@ -42,6 +42,11 @@ function guard (fn) { // should not initialize the tracer. if (!clobberBailout && NODE_MAJOR < minMajor) { initBailout = true + + telemetryModule.result = 'abort' + telemetryModule.result_reason = "Aborting application instrumentation due to incompatible_runtime." + telemetryModule.result_class = 'incompatible_runtime' + telemetry([ { name: 'abort', tags: ['reason:incompatible_runtime'] }, { name: 'abort.runtime', tags: [] } @@ -50,12 +55,20 @@ function guard (fn) { log.info('Found incompatible runtime nodejs %s, Supported runtimes: nodejs %s.', version, engines.node) if (forced) { log.info('DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.') + telemetryModule.result = 'success' + telemetryModule.result_reason = "DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing." + telemetryModule.result_class = 'success_forced' } } if (!clobberBailout && (!initBailout || forced)) { // Ensure the instrumentation source is set for the current process and potential child processes. var result = fn() + + telemetryModule.result = "success" + telemetryModule.result_reason = "Successfully configured ddtrace package" + telemetryModule.result_class = "success" + telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')]) log.info('Application instrumentation bootstrapping complete') return result diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index 3930c9c15a9..947bb9e0d97 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -4,6 +4,9 @@ var fs = require('fs') var spawn = require('child_process').spawn var tracerVersion = require('../../../../package.json').version var log = require('./log') +var result = "unknown" +var result_class = "unknown" +var result_reason = "unknown" module.exports = sendTelemetry @@ -22,7 +25,10 @@ var metadata = { runtime_name: 'nodejs', runtime_version: process.versions.node, tracer_version: tracerVersion, - pid: process.pid + pid: process.pid, + result: result, + result_reason: result_reason, + result_class: result_class } var seen = {} @@ -64,14 +70,23 @@ function sendTelemetry (name, tags) { }) proc.on('error', function () { log.error('Failed to spawn telemetry forwarder') + result = "error" + result_class = "internal_error" + result_reason = "Failed to spawn telemetry forwarder" }) proc.on('exit', function (code) { if (code !== 0) { log.error('Telemetry forwarder exited with code', code) + result = "error" + result_class = "internal_error" + result_reason = "Telemetry forwarder exited with code " + code } }) proc.stdin.on('error', function () { log.error('Failed to write telemetry data to telemetry forwarder') + result = "error" + result_class = "internal_error" + result_reason = "Failed to write telemetry data to telemetry forwarder" }) proc.stdin.end(JSON.stringify({ metadata: metadata, points: points })) } From f673ee21eb4bccf40e49565bbcc4ec23eeec1ec3 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Wed, 30 Jul 2025 15:39:35 -0400 Subject: [PATCH 02/24] fix --- integration-tests/helpers/index.js | 5 ++- packages/dd-trace/src/guardrails/index.js | 21 ++++++----- packages/dd-trace/src/guardrails/telemetry.js | 35 +++++++++++-------- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/integration-tests/helpers/index.js b/integration-tests/helpers/index.js index 6875eaf6478..b4eeb793ecd 100644 --- a/integration-tests/helpers/index.js +++ b/integration-tests/helpers/index.js @@ -111,7 +111,10 @@ function assertTelemetryPoints (pid, msgs, expectedTelemetryPoints) { runtime_name: 'nodejs', runtime_version: process.versions.node, tracer_version: require('../../package.json').version, - pid: Number(pid) + pid: Number(pid), + result: 'unknown', + result_reason: 'unknown', + result_class: 'unknown' } } } diff --git a/packages/dd-trace/src/guardrails/index.js b/packages/dd-trace/src/guardrails/index.js index 42243b4c444..5311d6ce414 100644 --- a/packages/dd-trace/src/guardrails/index.js +++ b/packages/dd-trace/src/guardrails/index.js @@ -16,6 +16,7 @@ function guard (fn) { var engines = require('../../../../package.json').engines var minMajor = parseInt(engines.node.replace(/[^0-9]/g, '')) var version = process.versions.node + var telemetryModule = require('./telemetry') if (process.env.DD_INJECTION_ENABLED) { // If we're running via single-step install, and we're in the app's @@ -42,11 +43,9 @@ function guard (fn) { // should not initialize the tracer. if (!clobberBailout && NODE_MAJOR < minMajor) { initBailout = true - - telemetryModule.result = 'abort' - telemetryModule.result_reason = "Aborting application instrumentation due to incompatible_runtime." - telemetryModule.result_class = 'incompatible_runtime' - + telemetryModule.resultMetadata.result = 'abort' + telemetryModule.resultMetadata.result_reason = "Aborting application instrumentation due to incompatible_runtime." + telemetryModule.resultMetadata.result_class = 'incompatible_runtime' telemetry([ { name: 'abort', tags: ['reason:incompatible_runtime'] }, { name: 'abort.runtime', tags: [] } @@ -55,9 +54,9 @@ function guard (fn) { log.info('Found incompatible runtime nodejs %s, Supported runtimes: nodejs %s.', version, engines.node) if (forced) { log.info('DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.') - telemetryModule.result = 'success' - telemetryModule.result_reason = "DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing." - telemetryModule.result_class = 'success_forced' + telemetryModule.resultMetadata.result = 'success' + telemetryModule.resultMetadata.result_reason = 'DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.' + telemetryModule.resultMetadata.result_class = 'success_forced' } } @@ -65,9 +64,9 @@ function guard (fn) { // Ensure the instrumentation source is set for the current process and potential child processes. var result = fn() - telemetryModule.result = "success" - telemetryModule.result_reason = "Successfully configured ddtrace package" - telemetryModule.result_class = "success" + telemetryModule.resultMetadata.result = 'success' + telemetryModule.resultMetadata.result_reason = 'Successfully configured ddtrace package' + telemetryModule.resultMetadata.result_class = 'success' telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')]) log.info('Application instrumentation bootstrapping complete') diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index 947bb9e0d97..6a4186a0e28 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -4,19 +4,24 @@ var fs = require('fs') var spawn = require('child_process').spawn var tracerVersion = require('../../../../package.json').version var log = require('./log') -var result = "unknown" -var result_class = "unknown" -var result_reason = "unknown" +var resultMetadata = { + result: "unknown", + result_class: "unknown", + result_reason: "unknown" +} module.exports = sendTelemetry +module.exports.resultMetadata = resultMetadata if (!process.env.DD_INJECTION_ENABLED) { module.exports = function noop () {} + module.exports.resultMetadata = resultMetadata } var telemetryForwarderPath = process.env.DD_TELEMETRY_FORWARDER_PATH if (typeof telemetryForwarderPath !== 'string' || !fs.existsSync(telemetryForwarderPath)) { module.exports = function noop () {} + module.exports.resultMetadata = resultMetadata } var metadata = { @@ -26,9 +31,9 @@ var metadata = { runtime_version: process.versions.node, tracer_version: tracerVersion, pid: process.pid, - result: result, - result_reason: result_reason, - result_class: result_class + result: resultMetadata.result, + result_reason: resultMetadata.result_reason, + result_class: resultMetadata.result_class } var seen = {} @@ -70,23 +75,23 @@ function sendTelemetry (name, tags) { }) proc.on('error', function () { log.error('Failed to spawn telemetry forwarder') - result = "error" - result_class = "internal_error" - result_reason = "Failed to spawn telemetry forwarder" + resultMetadata.result = "error" + resultMetadata.result_class = "internal_error" + resultMetadata.result_reason = "Failed to spawn telemetry forwarder" }) proc.on('exit', function (code) { if (code !== 0) { log.error('Telemetry forwarder exited with code', code) - result = "error" - result_class = "internal_error" - result_reason = "Telemetry forwarder exited with code " + code + resultMetadata.result = "error" + resultMetadata.result_class = "internal_error" + resultMetadata.result_reason = "Telemetry forwarder exited with code " + code } }) proc.stdin.on('error', function () { log.error('Failed to write telemetry data to telemetry forwarder') - result = "error" - result_class = "internal_error" - result_reason = "Failed to write telemetry data to telemetry forwarder" + resultMetadata.result = "error" + resultMetadata.result_class = "internal_error" + resultMetadata.result_reason = "Failed to write telemetry data to telemetry forwarder" }) proc.stdin.end(JSON.stringify({ metadata: metadata, points: points })) } From cc51b73c339255ad055365a560496ccffdfb53fb Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Wed, 30 Jul 2025 16:32:25 -0400 Subject: [PATCH 03/24] fixed --- integration-tests/helpers/index.js | 2 +- packages/dd-trace/src/guardrails/index.js | 6 ++--- packages/dd-trace/src/guardrails/telemetry.js | 24 +++++++++---------- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/integration-tests/helpers/index.js b/integration-tests/helpers/index.js index b4eeb793ecd..a905603fb99 100644 --- a/integration-tests/helpers/index.js +++ b/integration-tests/helpers/index.js @@ -113,7 +113,7 @@ function assertTelemetryPoints (pid, msgs, expectedTelemetryPoints) { tracer_version: require('../../package.json').version, pid: Number(pid), result: 'unknown', - result_reason: 'unknown', + result_reason: 'unknown', result_class: 'unknown' } } diff --git a/packages/dd-trace/src/guardrails/index.js b/packages/dd-trace/src/guardrails/index.js index 5311d6ce414..a453d7e58e2 100644 --- a/packages/dd-trace/src/guardrails/index.js +++ b/packages/dd-trace/src/guardrails/index.js @@ -44,7 +44,7 @@ function guard (fn) { if (!clobberBailout && NODE_MAJOR < minMajor) { initBailout = true telemetryModule.resultMetadata.result = 'abort' - telemetryModule.resultMetadata.result_reason = "Aborting application instrumentation due to incompatible_runtime." + telemetryModule.resultMetadata.result_reason = 'Aborting application instrumentation due to incompatible_runtime.' telemetryModule.resultMetadata.result_class = 'incompatible_runtime' telemetry([ { name: 'abort', tags: ['reason:incompatible_runtime'] }, @@ -55,7 +55,7 @@ function guard (fn) { if (forced) { log.info('DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.') telemetryModule.resultMetadata.result = 'success' - telemetryModule.resultMetadata.result_reason = 'DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.' + telemetryModule.resultMetadata.result_reason = 'DD_INJECT_FORCE enabled, allowing unsupported runtimes' telemetryModule.resultMetadata.result_class = 'success_forced' } } @@ -63,11 +63,9 @@ function guard (fn) { if (!clobberBailout && (!initBailout || forced)) { // Ensure the instrumentation source is set for the current process and potential child processes. var result = fn() - telemetryModule.resultMetadata.result = 'success' telemetryModule.resultMetadata.result_reason = 'Successfully configured ddtrace package' telemetryModule.resultMetadata.result_class = 'success' - telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')]) log.info('Application instrumentation bootstrapping complete') return result diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index 6a4186a0e28..5144a8a194c 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -5,9 +5,9 @@ var spawn = require('child_process').spawn var tracerVersion = require('../../../../package.json').version var log = require('./log') var resultMetadata = { - result: "unknown", - result_class: "unknown", - result_reason: "unknown" + result: 'unknown', + result_class: 'unknown', + result_reason: 'unknown' } module.exports = sendTelemetry @@ -75,23 +75,23 @@ function sendTelemetry (name, tags) { }) proc.on('error', function () { log.error('Failed to spawn telemetry forwarder') - resultMetadata.result = "error" - resultMetadata.result_class = "internal_error" - resultMetadata.result_reason = "Failed to spawn telemetry forwarder" + resultMetadata.result = 'error' + resultMetadata.result_class = 'internal_error' + resultMetadata.result_reason = 'Failed to spawn telemetry forwarder' }) proc.on('exit', function (code) { if (code !== 0) { log.error('Telemetry forwarder exited with code', code) - resultMetadata.result = "error" - resultMetadata.result_class = "internal_error" - resultMetadata.result_reason = "Telemetry forwarder exited with code " + code + resultMetadata.result = 'error' + resultMetadata.result_class = 'internal_error' + resultMetadata.result_reason = 'Telemetry forwarder exited with code ' + code } }) proc.stdin.on('error', function () { log.error('Failed to write telemetry data to telemetry forwarder') - resultMetadata.result = "error" - resultMetadata.result_class = "internal_error" - resultMetadata.result_reason = "Failed to write telemetry data to telemetry forwarder" + resultMetadata.result = 'error' + resultMetadata.result_class = 'internal_error' + resultMetadata.result_reason = 'Failed to write telemetry data to telemetry forwarder' }) proc.stdin.end(JSON.stringify({ metadata: metadata, points: points })) } From 714880e91427c9740b80c6215cda8b49e60c1a36 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Fri, 1 Aug 2025 10:26:39 -0400 Subject: [PATCH 04/24] add tests --- integration-tests/helpers/index.js | 7 +-- .../test/guardrails/telemetry.spec.js | 49 ++++++++++++++++++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/integration-tests/helpers/index.js b/integration-tests/helpers/index.js index a905603fb99..e1984323151 100644 --- a/integration-tests/helpers/index.js +++ b/integration-tests/helpers/index.js @@ -13,6 +13,7 @@ const rimraf = promisify(require('rimraf')) const FakeAgent = require('./fake-agent') const id = require('../../packages/dd-trace/src/id') const { version } = require('../../package.json') +const telemetryModule = require('../../packages/dd-trace/src/guardrails/telemetry') const hookFile = 'dd-trace/loader-hook.mjs' @@ -112,9 +113,9 @@ function assertTelemetryPoints (pid, msgs, expectedTelemetryPoints) { runtime_version: process.versions.node, tracer_version: require('../../package.json').version, pid: Number(pid), - result: 'unknown', - result_reason: 'unknown', - result_class: 'unknown' + result: telemetryModule.resultMetadata.result, + result_reason: telemetryModule.resultMetadata.result_reason, + result_class: telemetryModule.resultMetadata.result_class } } } diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 4ed8d5e3119..996d964525d 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -2,6 +2,8 @@ process.env.DD_INJECTION_ENABLED = 'true' +const assert = require('assert') +const proxyquire = require('proxyquire') const { telemetryForwarder, assertTelemetryPoints } = require('../../../../integration-tests/helpers') describe('sendTelemetry', () => { @@ -16,7 +18,7 @@ describe('sendTelemetry', () => { beforeEach(() => { cleanup = telemetryForwarder() - sendTelemetry = proxyquire('../src/guardrails/telemetry', {}) + sendTelemetry = proxyquire('../../src/guardrails/telemetry', {}) }) it('should send telemetry', async () => { @@ -68,4 +70,49 @@ describe('sendTelemetry', () => { assertTelemetryPoints(process.pid, msgs, ['abort.integration', '1']) }) }) + + describe('metadata fields', () => { + let telemetryModule + + beforeEach(() => { + telemetryModule = proxyquire('../../src/guardrails/telemetry', {}) + }) + + it('should start with unknown metadata values', () => { + const metadata = telemetryModule.resultMetadata + assert.strictEqual(metadata.result, 'unknown') + assert.strictEqual(metadata.result_class, 'unknown') + assert.strictEqual(metadata.result_reason, 'unknown') + }) + + it('should update to success metadata', () => { + telemetryModule.resultMetadata.result = 'success' + telemetryModule.resultMetadata.result_class = 'success' + telemetryModule.resultMetadata.result_reason = 'Successfully configured ddtrace package' + + assert.strictEqual(telemetryModule.resultMetadata.result, 'success') + assert.strictEqual(telemetryModule.resultMetadata.result_class, 'success') + assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Successfully configured ddtrace package') + }) + + it('should update to abort metadata', () => { + telemetryModule.resultMetadata.result = 'abort' + telemetryModule.resultMetadata.result_class = 'incompatible_runtime' + telemetryModule.resultMetadata.result_reason = 'Aborting application instrumentation due to incompatible_runtime.' + + assert.strictEqual(telemetryModule.resultMetadata.result, 'abort') + assert.strictEqual(telemetryModule.resultMetadata.result_class, 'incompatible_runtime') + assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Aborting application instrumentation due to incompatible_runtime.') + }) + + it('should update to error metadata', () => { + telemetryModule.resultMetadata.result = 'error' + telemetryModule.resultMetadata.result_class = 'internal_error' + telemetryModule.resultMetadata.result_reason = 'Failed to spawn telemetry forwarder' + + assert.strictEqual(telemetryModule.resultMetadata.result, 'error') + assert.strictEqual(telemetryModule.resultMetadata.result_class, 'internal_error') + assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Failed to spawn telemetry forwarder') + }) + }) }) From 0850b27218ef5ccba8c7bcac0aa6be9dcc4b63e0 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Fri, 1 Aug 2025 11:18:44 -0400 Subject: [PATCH 05/24] fix tests --- .../test/guardrails/telemetry.spec.js | 48 +------------------ 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 996d964525d..8645c3f2c36 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -2,8 +2,6 @@ process.env.DD_INJECTION_ENABLED = 'true' -const assert = require('assert') -const proxyquire = require('proxyquire') const { telemetryForwarder, assertTelemetryPoints } = require('../../../../integration-tests/helpers') describe('sendTelemetry', () => { @@ -18,7 +16,7 @@ describe('sendTelemetry', () => { beforeEach(() => { cleanup = telemetryForwarder() - sendTelemetry = proxyquire('../../src/guardrails/telemetry', {}) + sendTelemetry = proxyquire('../src/guardrails/telemetry', {}) }) it('should send telemetry', async () => { @@ -71,48 +69,4 @@ describe('sendTelemetry', () => { }) }) - describe('metadata fields', () => { - let telemetryModule - - beforeEach(() => { - telemetryModule = proxyquire('../../src/guardrails/telemetry', {}) - }) - - it('should start with unknown metadata values', () => { - const metadata = telemetryModule.resultMetadata - assert.strictEqual(metadata.result, 'unknown') - assert.strictEqual(metadata.result_class, 'unknown') - assert.strictEqual(metadata.result_reason, 'unknown') - }) - - it('should update to success metadata', () => { - telemetryModule.resultMetadata.result = 'success' - telemetryModule.resultMetadata.result_class = 'success' - telemetryModule.resultMetadata.result_reason = 'Successfully configured ddtrace package' - - assert.strictEqual(telemetryModule.resultMetadata.result, 'success') - assert.strictEqual(telemetryModule.resultMetadata.result_class, 'success') - assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Successfully configured ddtrace package') - }) - - it('should update to abort metadata', () => { - telemetryModule.resultMetadata.result = 'abort' - telemetryModule.resultMetadata.result_class = 'incompatible_runtime' - telemetryModule.resultMetadata.result_reason = 'Aborting application instrumentation due to incompatible_runtime.' - - assert.strictEqual(telemetryModule.resultMetadata.result, 'abort') - assert.strictEqual(telemetryModule.resultMetadata.result_class, 'incompatible_runtime') - assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Aborting application instrumentation due to incompatible_runtime.') - }) - - it('should update to error metadata', () => { - telemetryModule.resultMetadata.result = 'error' - telemetryModule.resultMetadata.result_class = 'internal_error' - telemetryModule.resultMetadata.result_reason = 'Failed to spawn telemetry forwarder' - - assert.strictEqual(telemetryModule.resultMetadata.result, 'error') - assert.strictEqual(telemetryModule.resultMetadata.result_class, 'internal_error') - assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Failed to spawn telemetry forwarder') - }) - }) }) From 91d7085ac7b2f9adb777c7adf23abed3e75a63e7 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Fri, 1 Aug 2025 11:19:28 -0400 Subject: [PATCH 06/24] fix format --- packages/dd-trace/test/guardrails/telemetry.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 8645c3f2c36..4ed8d5e3119 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -68,5 +68,4 @@ describe('sendTelemetry', () => { assertTelemetryPoints(process.pid, msgs, ['abort.integration', '1']) }) }) - }) From 491bf5a9add2dcef45a86804758b57ca087e72b5 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Fri, 1 Aug 2025 12:04:36 -0400 Subject: [PATCH 07/24] added tests --- packages/dd-trace/src/guardrails/telemetry.js | 4 ++ .../test/guardrails/telemetry.spec.js | 60 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index 5144a8a194c..8c4f0358ec4 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -85,6 +85,10 @@ function sendTelemetry (name, tags) { resultMetadata.result = 'error' resultMetadata.result_class = 'internal_error' resultMetadata.result_reason = 'Telemetry forwarder exited with code ' + code + } else { + resultMetadata.result = 'success' + resultMetadata.result_class = 'success' + resultMetadata.result_reason = 'Successfully configured ddtrace package' } }) proc.stdin.on('error', function () { diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 4ed8d5e3119..9f7c40f4637 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -2,6 +2,9 @@ process.env.DD_INJECTION_ENABLED = 'true' +const assert = require('assert') +const proxyquire = require('proxyquire') +const { EventEmitter } = require('events') const { telemetryForwarder, assertTelemetryPoints } = require('../../../../integration-tests/helpers') describe('sendTelemetry', () => { @@ -68,4 +71,61 @@ describe('sendTelemetry', () => { assertTelemetryPoints(process.pid, msgs, ['abort.integration', '1']) }) }) + + describe('error scenarios and metadata', () => { + let mockProc, telemetryModule, spawnStub + + beforeEach(() => { + mockProc = new EventEmitter() + mockProc.stdin = new EventEmitter() + mockProc.stdin.end = function () {} + mockProc.pid = 12345 + + spawnStub = function () { return mockProc } + + telemetryModule = proxyquire('../../src/guardrails/telemetry', { + 'child_process': { spawn: spawnStub } + }) + }) + + it('should set error metadata when telemetry forwarder fails to spawn', () => { + telemetryModule([{ name: 'test', tags: [] }]) + mockProc.emit('error', new Error('Spawn failed')) + + assert.strictEqual(telemetryModule.resultMetadata.result, 'error') + assert.strictEqual(telemetryModule.resultMetadata.result_class, 'internal_error') + assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Failed to spawn telemetry forwarder') + }) + + it('should set error metadata when telemetry forwarder exits with non-zero code', () => { + telemetryModule([{ name: 'test', tags: [] }]) + mockProc.emit('exit', 1) + + assert.strictEqual(telemetryModule.resultMetadata.result, 'error') + assert.strictEqual(telemetryModule.resultMetadata.result_class, 'internal_error') + assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Telemetry forwarder exited with code 1') + }) + + it('should set error metadata when writing to telemetry forwarder fails', () => { + telemetryModule([{ name: 'test', tags: [] }]) + mockProc.stdin.emit('error', new Error('Write failed')) + + assert.strictEqual(telemetryModule.resultMetadata.result, 'error') + assert.strictEqual(telemetryModule.resultMetadata.result_class, 'internal_error') + assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Failed to write telemetry data to telemetry forwarder') + }) + + it('should set success metadata when telemetry forwarder exits successfully', () => { + telemetryModule.resultMetadata.result = 'unknown' + telemetryModule.resultMetadata.result_class = 'unknown' + telemetryModule.resultMetadata.result_reason = 'unknown' + + telemetryModule([{ name: 'test', tags: [] }]) + mockProc.emit('exit', 0) + + assert.strictEqual(telemetryModule.resultMetadata.result, 'success') + assert.strictEqual(telemetryModule.resultMetadata.result_class, 'success') + assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Successfully configured ddtrace package') + }) + }) }) From 8f9556ae9bf3cf566226d3ea44ee4593bd5ec9ea Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Fri, 1 Aug 2025 12:27:01 -0400 Subject: [PATCH 08/24] fix format --- packages/dd-trace/src/guardrails/telemetry.js | 10 +++++----- packages/dd-trace/test/guardrails/telemetry.spec.js | 9 ++++++--- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index 8c4f0358ec4..f96e1b1af69 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -80,15 +80,15 @@ function sendTelemetry (name, tags) { resultMetadata.result_reason = 'Failed to spawn telemetry forwarder' }) proc.on('exit', function (code) { - if (code !== 0) { + if (code === 0) { + resultMetadata.result = 'success' + resultMetadata.result_class = 'success' + resultMetadata.result_reason = 'Successfully configured ddtrace package' + } else { log.error('Telemetry forwarder exited with code', code) resultMetadata.result = 'error' resultMetadata.result_class = 'internal_error' resultMetadata.result_reason = 'Telemetry forwarder exited with code ' + code - } else { - resultMetadata.result = 'success' - resultMetadata.result_class = 'success' - resultMetadata.result_reason = 'Successfully configured ddtrace package' } }) proc.stdin.on('error', function () { diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 9f7c40f4637..e396a9d2095 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -19,7 +19,7 @@ describe('sendTelemetry', () => { beforeEach(() => { cleanup = telemetryForwarder() - sendTelemetry = proxyquire('../src/guardrails/telemetry', {}) + sendTelemetry = proxyquire('../../src/guardrails/telemetry', {}) }) it('should send telemetry', async () => { @@ -84,7 +84,7 @@ describe('sendTelemetry', () => { spawnStub = function () { return mockProc } telemetryModule = proxyquire('../../src/guardrails/telemetry', { - 'child_process': { spawn: spawnStub } + child_process: { spawn: spawnStub } }) }) @@ -112,7 +112,10 @@ describe('sendTelemetry', () => { assert.strictEqual(telemetryModule.resultMetadata.result, 'error') assert.strictEqual(telemetryModule.resultMetadata.result_class, 'internal_error') - assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Failed to write telemetry data to telemetry forwarder') + assert.strictEqual( + telemetryModule.resultMetadata.result_reason, + 'Failed to write telemetry data to telemetry forwarder' + ) }) it('should set success metadata when telemetry forwarder exits successfully', () => { From 38736e2af2e0103beeba5fc0fa63b15f1e2bc5cf Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Mon, 4 Aug 2025 09:23:11 -0400 Subject: [PATCH 09/24] edit --- integration-tests/helpers/index.js | 6 +-- packages/dd-trace/src/guardrails/index.js | 18 +++---- packages/dd-trace/src/guardrails/telemetry.js | 50 ++++++++++--------- .../test/guardrails/telemetry.spec.js | 30 +++++------ 4 files changed, 54 insertions(+), 50 deletions(-) diff --git a/integration-tests/helpers/index.js b/integration-tests/helpers/index.js index ed652b21fba..6655274fd59 100644 --- a/integration-tests/helpers/index.js +++ b/integration-tests/helpers/index.js @@ -115,9 +115,9 @@ function assertTelemetryPoints (pid, msgs, expectedTelemetryPoints) { runtime_version: process.versions.node, tracer_version: require('../../package.json').version, pid: Number(pid), - result: telemetryModule.resultMetadata.result, - result_reason: telemetryModule.resultMetadata.result_reason, - result_class: telemetryModule.resultMetadata.result_class + result: telemetryModule.result, + result_reason: telemetryModule.result_reason, + result_class: telemetryModule.result_class } } } diff --git a/packages/dd-trace/src/guardrails/index.js b/packages/dd-trace/src/guardrails/index.js index a453d7e58e2..9685fa7fc8b 100644 --- a/packages/dd-trace/src/guardrails/index.js +++ b/packages/dd-trace/src/guardrails/index.js @@ -43,9 +43,9 @@ function guard (fn) { // should not initialize the tracer. if (!clobberBailout && NODE_MAJOR < minMajor) { initBailout = true - telemetryModule.resultMetadata.result = 'abort' - telemetryModule.resultMetadata.result_reason = 'Aborting application instrumentation due to incompatible_runtime.' - telemetryModule.resultMetadata.result_class = 'incompatible_runtime' + telemetryModule.result = 'abort' + telemetryModule.result_reason = 'Aborting application instrumentation due to incompatible_runtime.' + telemetryModule.result_class = 'incompatible_runtime' telemetry([ { name: 'abort', tags: ['reason:incompatible_runtime'] }, { name: 'abort.runtime', tags: [] } @@ -54,18 +54,18 @@ function guard (fn) { log.info('Found incompatible runtime nodejs %s, Supported runtimes: nodejs %s.', version, engines.node) if (forced) { log.info('DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.') - telemetryModule.resultMetadata.result = 'success' - telemetryModule.resultMetadata.result_reason = 'DD_INJECT_FORCE enabled, allowing unsupported runtimes' - telemetryModule.resultMetadata.result_class = 'success_forced' + telemetryModule.result = 'success' + telemetryModule.result_reason = 'DD_INJECT_FORCE enabled, allowing unsupported runtimes' + telemetryModule.result_class = 'success_forced' } } if (!clobberBailout && (!initBailout || forced)) { // Ensure the instrumentation source is set for the current process and potential child processes. var result = fn() - telemetryModule.resultMetadata.result = 'success' - telemetryModule.resultMetadata.result_reason = 'Successfully configured ddtrace package' - telemetryModule.resultMetadata.result_class = 'success' + telemetryModule.result = 'success' + telemetryModule.result_reason = 'Successfully configured ddtrace package' + telemetryModule.result_class = 'success' telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')]) log.info('Application instrumentation bootstrapping complete') return result diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index f96e1b1af69..70f90080105 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -4,24 +4,28 @@ var fs = require('fs') var spawn = require('child_process').spawn var tracerVersion = require('../../../../package.json').version var log = require('./log') -var resultMetadata = { - result: 'unknown', - result_class: 'unknown', - result_reason: 'unknown' -} +var result = 'unknown' +var result_class = 'unknown' +var result_reason = 'unknown' module.exports = sendTelemetry -module.exports.resultMetadata = resultMetadata +module.exports.result = result +module.exports.result_class = result_class +module.exports.result_reason = result_reason if (!process.env.DD_INJECTION_ENABLED) { module.exports = function noop () {} - module.exports.resultMetadata = resultMetadata + module.exports.result = result + module.exports.result_class = result_class + module.exports.result_reason = result_reason } var telemetryForwarderPath = process.env.DD_TELEMETRY_FORWARDER_PATH if (typeof telemetryForwarderPath !== 'string' || !fs.existsSync(telemetryForwarderPath)) { module.exports = function noop () {} - module.exports.resultMetadata = resultMetadata + module.exports.result = result + module.exports.result_class = result_class + module.exports.result_reason = result_reason } var metadata = { @@ -31,9 +35,9 @@ var metadata = { runtime_version: process.versions.node, tracer_version: tracerVersion, pid: process.pid, - result: resultMetadata.result, - result_reason: resultMetadata.result_reason, - result_class: resultMetadata.result_class + result: module.exports.result, + result_reason: module.exports.result_reason, + result_class: module.exports.result_class } var seen = {} @@ -75,27 +79,27 @@ function sendTelemetry (name, tags) { }) proc.on('error', function () { log.error('Failed to spawn telemetry forwarder') - resultMetadata.result = 'error' - resultMetadata.result_class = 'internal_error' - resultMetadata.result_reason = 'Failed to spawn telemetry forwarder' + module.exports.result = 'error' + module.exports.result_class = 'internal_error' + module.exports.result_reason = 'Failed to spawn telemetry forwarder' }) proc.on('exit', function (code) { if (code === 0) { - resultMetadata.result = 'success' - resultMetadata.result_class = 'success' - resultMetadata.result_reason = 'Successfully configured ddtrace package' + module.exports.result = 'success' + module.exports.result_class = 'success' + module.exports.result_reason = 'Successfully configured ddtrace package' } else { log.error('Telemetry forwarder exited with code', code) - resultMetadata.result = 'error' - resultMetadata.result_class = 'internal_error' - resultMetadata.result_reason = 'Telemetry forwarder exited with code ' + code + module.exports.result = 'error' + module.exports.result_class = 'internal_error' + module.exports.result_reason = 'Telemetry forwarder exited with code ' + code } }) proc.stdin.on('error', function () { log.error('Failed to write telemetry data to telemetry forwarder') - resultMetadata.result = 'error' - resultMetadata.result_class = 'internal_error' - resultMetadata.result_reason = 'Failed to write telemetry data to telemetry forwarder' + module.exports.result = 'error' + module.exports.result_class = 'internal_error' + module.exports.result_reason = 'Failed to write telemetry data to telemetry forwarder' }) proc.stdin.end(JSON.stringify({ metadata: metadata, points: points })) } diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index e396a9d2095..81b6f6df946 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -92,43 +92,43 @@ describe('sendTelemetry', () => { telemetryModule([{ name: 'test', tags: [] }]) mockProc.emit('error', new Error('Spawn failed')) - assert.strictEqual(telemetryModule.resultMetadata.result, 'error') - assert.strictEqual(telemetryModule.resultMetadata.result_class, 'internal_error') - assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Failed to spawn telemetry forwarder') + assert.strictEqual(telemetryModule.result, 'error') + assert.strictEqual(telemetryModule.result_class, 'internal_error') + assert.strictEqual(telemetryModule.result_reason, 'Failed to spawn telemetry forwarder') }) it('should set error metadata when telemetry forwarder exits with non-zero code', () => { telemetryModule([{ name: 'test', tags: [] }]) mockProc.emit('exit', 1) - assert.strictEqual(telemetryModule.resultMetadata.result, 'error') - assert.strictEqual(telemetryModule.resultMetadata.result_class, 'internal_error') - assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Telemetry forwarder exited with code 1') + assert.strictEqual(telemetryModule.result, 'error') + assert.strictEqual(telemetryModule.result_class, 'internal_error') + assert.strictEqual(telemetryModule.result_reason, 'Telemetry forwarder exited with code 1') }) it('should set error metadata when writing to telemetry forwarder fails', () => { telemetryModule([{ name: 'test', tags: [] }]) mockProc.stdin.emit('error', new Error('Write failed')) - assert.strictEqual(telemetryModule.resultMetadata.result, 'error') - assert.strictEqual(telemetryModule.resultMetadata.result_class, 'internal_error') + assert.strictEqual(telemetryModule.result, 'error') + assert.strictEqual(telemetryModule.result_class, 'internal_error') assert.strictEqual( - telemetryModule.resultMetadata.result_reason, + telemetryModule.result_reason, 'Failed to write telemetry data to telemetry forwarder' ) }) it('should set success metadata when telemetry forwarder exits successfully', () => { - telemetryModule.resultMetadata.result = 'unknown' - telemetryModule.resultMetadata.result_class = 'unknown' - telemetryModule.resultMetadata.result_reason = 'unknown' + telemetryModule.result = 'unknown' + telemetryModule.result_class = 'unknown' + telemetryModule.result_reason = 'unknown' telemetryModule([{ name: 'test', tags: [] }]) mockProc.emit('exit', 0) - assert.strictEqual(telemetryModule.resultMetadata.result, 'success') - assert.strictEqual(telemetryModule.resultMetadata.result_class, 'success') - assert.strictEqual(telemetryModule.resultMetadata.result_reason, 'Successfully configured ddtrace package') + assert.strictEqual(telemetryModule.result, 'success') + assert.strictEqual(telemetryModule.result_class, 'success') + assert.strictEqual(telemetryModule.result_reason, 'Successfully configured ddtrace package') }) }) }) From 20a89e1e5f2ea4113d25f96b3bc5f5893a2773cb Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Mon, 4 Aug 2025 09:31:08 -0400 Subject: [PATCH 10/24] clean --- packages/dd-trace/src/guardrails/index.js | 10 ----- .../test/guardrails/telemetry.spec.js | 40 +++++++------------ 2 files changed, 14 insertions(+), 36 deletions(-) diff --git a/packages/dd-trace/src/guardrails/index.js b/packages/dd-trace/src/guardrails/index.js index 9685fa7fc8b..ab60c2d550f 100644 --- a/packages/dd-trace/src/guardrails/index.js +++ b/packages/dd-trace/src/guardrails/index.js @@ -16,7 +16,6 @@ function guard (fn) { var engines = require('../../../../package.json').engines var minMajor = parseInt(engines.node.replace(/[^0-9]/g, '')) var version = process.versions.node - var telemetryModule = require('./telemetry') if (process.env.DD_INJECTION_ENABLED) { // If we're running via single-step install, and we're in the app's @@ -43,9 +42,6 @@ function guard (fn) { // should not initialize the tracer. if (!clobberBailout && NODE_MAJOR < minMajor) { initBailout = true - telemetryModule.result = 'abort' - telemetryModule.result_reason = 'Aborting application instrumentation due to incompatible_runtime.' - telemetryModule.result_class = 'incompatible_runtime' telemetry([ { name: 'abort', tags: ['reason:incompatible_runtime'] }, { name: 'abort.runtime', tags: [] } @@ -54,18 +50,12 @@ function guard (fn) { log.info('Found incompatible runtime nodejs %s, Supported runtimes: nodejs %s.', version, engines.node) if (forced) { log.info('DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.') - telemetryModule.result = 'success' - telemetryModule.result_reason = 'DD_INJECT_FORCE enabled, allowing unsupported runtimes' - telemetryModule.result_class = 'success_forced' } } if (!clobberBailout && (!initBailout || forced)) { // Ensure the instrumentation source is set for the current process and potential child processes. var result = fn() - telemetryModule.result = 'success' - telemetryModule.result_reason = 'Successfully configured ddtrace package' - telemetryModule.result_class = 'success' telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')]) log.info('Application instrumentation bootstrapping complete') return result diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 81b6f6df946..14f1733692d 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -72,63 +72,51 @@ describe('sendTelemetry', () => { }) }) - describe('error scenarios and metadata', () => { - let mockProc, telemetryModule, spawnStub + describe('error scenarios and metadata', () => { + let mockProc, telemetryModule beforeEach(() => { mockProc = new EventEmitter() mockProc.stdin = new EventEmitter() - mockProc.stdin.end = function () {} - mockProc.pid = 12345 - - spawnStub = function () { return mockProc } + mockProc.stdin.end = () => {} telemetryModule = proxyquire('../../src/guardrails/telemetry', { - child_process: { spawn: spawnStub } + child_process: { spawn: () => mockProc } }) }) + function assertMetadata (result, result_class, result_reason) { + assert.strictEqual(telemetryModule.result, result) + assert.strictEqual(telemetryModule.result_class, result_class) + assert.strictEqual(telemetryModule.result_reason, result_reason) + } + it('should set error metadata when telemetry forwarder fails to spawn', () => { telemetryModule([{ name: 'test', tags: [] }]) mockProc.emit('error', new Error('Spawn failed')) - assert.strictEqual(telemetryModule.result, 'error') - assert.strictEqual(telemetryModule.result_class, 'internal_error') - assert.strictEqual(telemetryModule.result_reason, 'Failed to spawn telemetry forwarder') + assertMetadata('error', 'internal_error', 'Failed to spawn telemetry forwarder') }) it('should set error metadata when telemetry forwarder exits with non-zero code', () => { telemetryModule([{ name: 'test', tags: [] }]) mockProc.emit('exit', 1) - assert.strictEqual(telemetryModule.result, 'error') - assert.strictEqual(telemetryModule.result_class, 'internal_error') - assert.strictEqual(telemetryModule.result_reason, 'Telemetry forwarder exited with code 1') + assertMetadata('error', 'internal_error', 'Telemetry forwarder exited with code 1') }) it('should set error metadata when writing to telemetry forwarder fails', () => { telemetryModule([{ name: 'test', tags: [] }]) mockProc.stdin.emit('error', new Error('Write failed')) - assert.strictEqual(telemetryModule.result, 'error') - assert.strictEqual(telemetryModule.result_class, 'internal_error') - assert.strictEqual( - telemetryModule.result_reason, - 'Failed to write telemetry data to telemetry forwarder' - ) + assertMetadata('error', 'internal_error', 'Failed to write telemetry data to telemetry forwarder') }) it('should set success metadata when telemetry forwarder exits successfully', () => { - telemetryModule.result = 'unknown' - telemetryModule.result_class = 'unknown' - telemetryModule.result_reason = 'unknown' - telemetryModule([{ name: 'test', tags: [] }]) mockProc.emit('exit', 0) - assert.strictEqual(telemetryModule.result, 'success') - assert.strictEqual(telemetryModule.result_class, 'success') - assert.strictEqual(telemetryModule.result_reason, 'Successfully configured ddtrace package') + assertMetadata('success', 'success', 'Successfully configured ddtrace package') }) }) }) From a666cf855fee5e693cc20ad46d356fe3bcbeecc1 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Mon, 4 Aug 2025 09:46:34 -0400 Subject: [PATCH 11/24] checks --- integration-tests/helpers/index.js | 4 +- packages/dd-trace/src/guardrails/telemetry.js | 73 +++++++++++-------- .../test/guardrails/telemetry.spec.js | 8 +- 3 files changed, 48 insertions(+), 37 deletions(-) diff --git a/integration-tests/helpers/index.js b/integration-tests/helpers/index.js index 6655274fd59..0a2f0a471d4 100644 --- a/integration-tests/helpers/index.js +++ b/integration-tests/helpers/index.js @@ -116,8 +116,8 @@ function assertTelemetryPoints (pid, msgs, expectedTelemetryPoints) { tracer_version: require('../../package.json').version, pid: Number(pid), result: telemetryModule.result, - result_reason: telemetryModule.result_reason, - result_class: telemetryModule.result_class + resultReason: telemetryModule.resultReason, + resultClass: telemetryModule.resultClass } } } diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index 70f90080105..ce13a9a3063 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -5,39 +5,41 @@ var spawn = require('child_process').spawn var tracerVersion = require('../../../../package.json').version var log = require('./log') var result = 'unknown' -var result_class = 'unknown' -var result_reason = 'unknown' +var resultClass = 'unknown' +var resultReason = 'unknown' module.exports = sendTelemetry module.exports.result = result -module.exports.result_class = result_class -module.exports.result_reason = result_reason +module.exports.resultClass = resultClass +module.exports.resultReason = resultReason if (!process.env.DD_INJECTION_ENABLED) { module.exports = function noop () {} module.exports.result = result - module.exports.result_class = result_class - module.exports.result_reason = result_reason + module.exports.resultClass = resultClass + module.exports.resultReason = resultReason } var telemetryForwarderPath = process.env.DD_TELEMETRY_FORWARDER_PATH if (typeof telemetryForwarderPath !== 'string' || !fs.existsSync(telemetryForwarderPath)) { module.exports = function noop () {} module.exports.result = result - module.exports.result_class = result_class - module.exports.result_reason = result_reason + module.exports.resultClass = resultClass + module.exports.resultReason = resultReason } -var metadata = { - language_name: 'nodejs', - language_version: process.versions.node, - runtime_name: 'nodejs', - runtime_version: process.versions.node, - tracer_version: tracerVersion, - pid: process.pid, - result: module.exports.result, - result_reason: module.exports.result_reason, - result_class: module.exports.result_class +function getMetadata () { + return { + language_name: 'nodejs', + language_version: process.versions.node, + runtime_name: 'nodejs', + runtime_version: process.versions.node, + tracer_version: tracerVersion, + pid: process.pid, + result: result, + resultReason: resultReason, + resultClass: resultClass + } } var seen = {} @@ -79,27 +81,36 @@ function sendTelemetry (name, tags) { }) proc.on('error', function () { log.error('Failed to spawn telemetry forwarder') - module.exports.result = 'error' - module.exports.result_class = 'internal_error' - module.exports.result_reason = 'Failed to spawn telemetry forwarder' + result = 'error' + resultClass = 'internal_error' + resultReason = 'Failed to spawn telemetry forwarder' + module.exports.result = result + module.exports.resultClass = resultClass + module.exports.resultReason = resultReason }) proc.on('exit', function (code) { if (code === 0) { - module.exports.result = 'success' - module.exports.result_class = 'success' - module.exports.result_reason = 'Successfully configured ddtrace package' + result = 'success' + resultClass = 'success' + resultReason = 'Successfully configured ddtrace package' } else { log.error('Telemetry forwarder exited with code', code) - module.exports.result = 'error' - module.exports.result_class = 'internal_error' - module.exports.result_reason = 'Telemetry forwarder exited with code ' + code + result = 'error' + resultClass = 'internal_error' + resultReason = 'Telemetry forwarder exited with code ' + code } + module.exports.result = result + module.exports.resultClass = resultClass + module.exports.resultReason = resultReason }) proc.stdin.on('error', function () { log.error('Failed to write telemetry data to telemetry forwarder') - module.exports.result = 'error' - module.exports.result_class = 'internal_error' - module.exports.result_reason = 'Failed to write telemetry data to telemetry forwarder' + result = 'error' + resultClass = 'internal_error' + resultReason = 'Failed to write telemetry data to telemetry forwarder' + module.exports.result = result + module.exports.resultClass = resultClass + module.exports.resultReason = resultReason }) - proc.stdin.end(JSON.stringify({ metadata: metadata, points: points })) + proc.stdin.end(JSON.stringify({ metadata: getMetadata(), points: points })) } diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 14f1733692d..734b367e093 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -72,7 +72,7 @@ describe('sendTelemetry', () => { }) }) - describe('error scenarios and metadata', () => { + describe('error scenarios and metadata', () => { let mockProc, telemetryModule beforeEach(() => { @@ -85,10 +85,10 @@ describe('sendTelemetry', () => { }) }) - function assertMetadata (result, result_class, result_reason) { + function assertMetadata (result, resultClass, resultReason) { assert.strictEqual(telemetryModule.result, result) - assert.strictEqual(telemetryModule.result_class, result_class) - assert.strictEqual(telemetryModule.result_reason, result_reason) + assert.strictEqual(telemetryModule.resultClass, resultClass) + assert.strictEqual(telemetryModule.resultReason, resultReason) } it('should set error metadata when telemetry forwarder fails to spawn', () => { From 516376ab86e95a5b780ddb8fa85ed2505ea3b7ae Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Mon, 4 Aug 2025 09:52:48 -0400 Subject: [PATCH 12/24] debug --- packages/dd-trace/test/guardrails/telemetry.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 734b367e093..f53d9169af4 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -72,7 +72,7 @@ describe('sendTelemetry', () => { }) }) - describe('error scenarios and metadata', () => { + describe('Error scenarios and metadata', () => { let mockProc, telemetryModule beforeEach(() => { From 17651a9c4e267edbddc22fe4f977e46e884a805e Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Mon, 4 Aug 2025 10:09:12 -0400 Subject: [PATCH 13/24] fix --- packages/dd-trace/src/guardrails/telemetry.js | 37 +++++-------------- 1 file changed, 10 insertions(+), 27 deletions(-) diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index ce13a9a3063..ab801a8b249 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -9,37 +9,26 @@ var resultClass = 'unknown' var resultReason = 'unknown' module.exports = sendTelemetry -module.exports.result = result -module.exports.resultClass = resultClass -module.exports.resultReason = resultReason if (!process.env.DD_INJECTION_ENABLED) { module.exports = function noop () {} - module.exports.result = result - module.exports.resultClass = resultClass - module.exports.resultReason = resultReason } var telemetryForwarderPath = process.env.DD_TELEMETRY_FORWARDER_PATH if (typeof telemetryForwarderPath !== 'string' || !fs.existsSync(telemetryForwarderPath)) { module.exports = function noop () {} - module.exports.result = result - module.exports.resultClass = resultClass - module.exports.resultReason = resultReason } -function getMetadata () { - return { +var metadata = { language_name: 'nodejs', language_version: process.versions.node, runtime_name: 'nodejs', runtime_version: process.versions.node, tracer_version: tracerVersion, pid: process.pid, - result: result, - resultReason: resultReason, - resultClass: resultClass - } + result: module.exports.result, + resultReason: module.exports.resultReason, + resultClass: module.exports.resultClass } var seen = {} @@ -84,9 +73,6 @@ function sendTelemetry (name, tags) { result = 'error' resultClass = 'internal_error' resultReason = 'Failed to spawn telemetry forwarder' - module.exports.result = result - module.exports.resultClass = resultClass - module.exports.resultReason = resultReason }) proc.on('exit', function (code) { if (code === 0) { @@ -99,18 +85,15 @@ function sendTelemetry (name, tags) { resultClass = 'internal_error' resultReason = 'Telemetry forwarder exited with code ' + code } - module.exports.result = result - module.exports.resultClass = resultClass - module.exports.resultReason = resultReason }) proc.stdin.on('error', function () { log.error('Failed to write telemetry data to telemetry forwarder') result = 'error' - resultClass = 'internal_error' - resultReason = 'Failed to write telemetry data to telemetry forwarder' - module.exports.result = result - module.exports.resultClass = resultClass - module.exports.resultReason = resultReason + result_class = 'internal_error' + result_reason = 'Failed to write telemetry data to telemetry forwarder' }) - proc.stdin.end(JSON.stringify({ metadata: getMetadata(), points: points })) + module.exports.result = result + module.exports.resultClass = resultClass + module.exports.resultReason = resultReason + proc.stdin.end(JSON.stringify({ metadata: metadata, points: points })) } From d72b0cfbe3c4af613954021caed38f51bc26af01 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Mon, 4 Aug 2025 10:24:23 -0400 Subject: [PATCH 14/24] fix --- packages/dd-trace/src/guardrails/telemetry.js | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index ab801a8b249..874a0375490 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -4,19 +4,24 @@ var fs = require('fs') var spawn = require('child_process').spawn var tracerVersion = require('../../../../package.json').version var log = require('./log') -var result = 'unknown' -var resultClass = 'unknown' -var resultReason = 'unknown' - module.exports = sendTelemetry +module.exports.result = 'unknown' +module.exports.resultClass = 'unknown' +module.exports.resultReason = 'unknown' if (!process.env.DD_INJECTION_ENABLED) { module.exports = function noop () {} + module.exports.result = 'unknown' + module.exports.resultClass = 'unknown' + module.exports.resultReason = 'unknown' } var telemetryForwarderPath = process.env.DD_TELEMETRY_FORWARDER_PATH if (typeof telemetryForwarderPath !== 'string' || !fs.existsSync(telemetryForwarderPath)) { module.exports = function noop () {} + module.exports.result = 'unknown' + module.exports.resultClass = 'unknown' + module.exports.resultReason = 'unknown' } var metadata = { @@ -70,30 +75,27 @@ function sendTelemetry (name, tags) { }) proc.on('error', function () { log.error('Failed to spawn telemetry forwarder') - result = 'error' - resultClass = 'internal_error' - resultReason = 'Failed to spawn telemetry forwarder' + module.exports.result = 'error' + module.exports.resultClass = 'internal_error' + module.exports.resultReason = 'Failed to spawn telemetry forwarder' }) proc.on('exit', function (code) { if (code === 0) { - result = 'success' - resultClass = 'success' - resultReason = 'Successfully configured ddtrace package' + module.exports.result = 'success' + module.exports.resultClass = 'success' + module.exports.resultReason = 'Successfully configured ddtrace package' } else { log.error('Telemetry forwarder exited with code', code) - result = 'error' - resultClass = 'internal_error' - resultReason = 'Telemetry forwarder exited with code ' + code + module.exports.result = 'error' + module.exports.resultClass = 'internal_error' + module.exports.resultReason = 'Telemetry forwarder exited with code ' + code } }) proc.stdin.on('error', function () { log.error('Failed to write telemetry data to telemetry forwarder') - result = 'error' - result_class = 'internal_error' - result_reason = 'Failed to write telemetry data to telemetry forwarder' + module.exports.result = 'error' + module.exports.resultClass = 'internal_error' + module.exports.resultReason = 'Failed to write telemetry data to telemetry forwarder' }) - module.exports.result = result - module.exports.resultClass = resultClass - module.exports.resultReason = resultReason proc.stdin.end(JSON.stringify({ metadata: metadata, points: points })) } From 87597c865a318b01bcc274636a1f739fd19feef3 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Mon, 4 Aug 2025 10:26:40 -0400 Subject: [PATCH 15/24] fix format --- packages/dd-trace/src/guardrails/telemetry.js | 19 ++++++++++--------- .../test/guardrails/telemetry.spec.js | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index 874a0375490..7f77420753f 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -4,6 +4,7 @@ var fs = require('fs') var spawn = require('child_process').spawn var tracerVersion = require('../../../../package.json').version var log = require('./log') + module.exports = sendTelemetry module.exports.result = 'unknown' module.exports.resultClass = 'unknown' @@ -25,15 +26,15 @@ if (typeof telemetryForwarderPath !== 'string' || !fs.existsSync(telemetryForwar } var metadata = { - language_name: 'nodejs', - language_version: process.versions.node, - runtime_name: 'nodejs', - runtime_version: process.versions.node, - tracer_version: tracerVersion, - pid: process.pid, - result: module.exports.result, - resultReason: module.exports.resultReason, - resultClass: module.exports.resultClass + language_name: 'nodejs', + language_version: process.versions.node, + runtime_name: 'nodejs', + runtime_version: process.versions.node, + tracer_version: tracerVersion, + pid: process.pid, + result: module.exports.result, + resultReason: module.exports.resultReason, + resultClass: module.exports.resultClass } var seen = {} diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index f53d9169af4..90c26fd8460 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -80,7 +80,7 @@ describe('sendTelemetry', () => { mockProc.stdin = new EventEmitter() mockProc.stdin.end = () => {} - telemetryModule = proxyquire('../../src/guardrails/telemetry', { + telemetryModule = proxyquire('../src/guardrails/telemetry', { child_process: { spawn: () => mockProc } }) }) From e15417b71dee52fbaf0dc5d68071d070a0d77c5b Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Mon, 4 Aug 2025 10:37:54 -0400 Subject: [PATCH 16/24] fix --- packages/dd-trace/test/guardrails/telemetry.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 90c26fd8460..f53d9169af4 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -80,7 +80,7 @@ describe('sendTelemetry', () => { mockProc.stdin = new EventEmitter() mockProc.stdin.end = () => {} - telemetryModule = proxyquire('../src/guardrails/telemetry', { + telemetryModule = proxyquire('../../src/guardrails/telemetry', { child_process: { spawn: () => mockProc } }) }) From d8fcb22c34d3863e214edc745932601a831d4e67 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Tue, 5 Aug 2025 12:51:41 -0400 Subject: [PATCH 17/24] fix --- integration-tests/helpers/index.js | 6 +- packages/dd-trace/src/guardrails/telemetry.js | 39 +++----- .../test/guardrails/telemetry.spec.js | 99 ++++++++++++++----- 3 files changed, 91 insertions(+), 53 deletions(-) diff --git a/integration-tests/helpers/index.js b/integration-tests/helpers/index.js index 0a2f0a471d4..e61def6a20a 100644 --- a/integration-tests/helpers/index.js +++ b/integration-tests/helpers/index.js @@ -115,9 +115,9 @@ function assertTelemetryPoints (pid, msgs, expectedTelemetryPoints) { runtime_version: process.versions.node, tracer_version: require('../../package.json').version, pid: Number(pid), - result: telemetryModule.result, - resultReason: telemetryModule.resultReason, - resultClass: telemetryModule.resultClass + result: 'unknown', + result_reason: 'unknown', + result_class: 'unknown' } } } diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index 7f77420753f..dc4a2eb4d8a 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -6,23 +6,14 @@ var tracerVersion = require('../../../../package.json').version var log = require('./log') module.exports = sendTelemetry -module.exports.result = 'unknown' -module.exports.resultClass = 'unknown' -module.exports.resultReason = 'unknown' if (!process.env.DD_INJECTION_ENABLED) { module.exports = function noop () {} - module.exports.result = 'unknown' - module.exports.resultClass = 'unknown' - module.exports.resultReason = 'unknown' } var telemetryForwarderPath = process.env.DD_TELEMETRY_FORWARDER_PATH if (typeof telemetryForwarderPath !== 'string' || !fs.existsSync(telemetryForwarderPath)) { module.exports = function noop () {} - module.exports.result = 'unknown' - module.exports.resultClass = 'unknown' - module.exports.resultReason = 'unknown' } var metadata = { @@ -32,9 +23,9 @@ var metadata = { runtime_version: process.versions.node, tracer_version: tracerVersion, pid: process.pid, - result: module.exports.result, - resultReason: module.exports.resultReason, - resultClass: module.exports.resultClass + result: 'unknown', + result_reason: 'unknown', + result_class: 'unknown' } var seen = {} @@ -76,27 +67,27 @@ function sendTelemetry (name, tags) { }) proc.on('error', function () { log.error('Failed to spawn telemetry forwarder') - module.exports.result = 'error' - module.exports.resultClass = 'internal_error' - module.exports.resultReason = 'Failed to spawn telemetry forwarder' + metadata.result = 'error' + metadata.result_class = 'internal_error' + metadata.result_reason = 'Failed to spawn telemetry forwarder' }) proc.on('exit', function (code) { if (code === 0) { - module.exports.result = 'success' - module.exports.resultClass = 'success' - module.exports.resultReason = 'Successfully configured ddtrace package' + metadata.result = 'success' + metadata.result_class = 'success' + metadata.result_reason = 'Successfully configured ddtrace package' } else { log.error('Telemetry forwarder exited with code', code) - module.exports.result = 'error' - module.exports.resultClass = 'internal_error' - module.exports.resultReason = 'Telemetry forwarder exited with code ' + code + metadata.result = 'error' + metadata.result_class = 'internal_error' + metadata.result_reason = 'Telemetry forwarder exited with code ' + code } }) proc.stdin.on('error', function () { log.error('Failed to write telemetry data to telemetry forwarder') - module.exports.result = 'error' - module.exports.resultClass = 'internal_error' - module.exports.resultReason = 'Failed to write telemetry data to telemetry forwarder' + metadata.result = 'error' + metadata.result_class = 'internal_error' + metadata.result_reason = 'Failed to write telemetry data to telemetry forwarder' }) proc.stdin.end(JSON.stringify({ metadata: metadata, points: points })) } diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index f53d9169af4..d776a9bd2a8 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -71,52 +71,99 @@ describe('sendTelemetry', () => { assertTelemetryPoints(process.pid, msgs, ['abort.integration', '1']) }) }) - + describe('Error scenarios and metadata', () => { - let mockProc, telemetryModule - - beforeEach(() => { - mockProc = new EventEmitter() - mockProc.stdin = new EventEmitter() - mockProc.stdin.end = () => {} + let mockProc, telemetryModule, capturedStdinData + + function createMockProcess() { + const proc = new EventEmitter() + proc.stdin = new EventEmitter() + proc.stdin.end = (data) => { + capturedStdinData = data + } + return proc + } - telemetryModule = proxyquire('../../src/guardrails/telemetry', { + function loadTelemetryModuleWithMockProc() { + return proxyquire('../../src/guardrails/telemetry', { child_process: { spawn: () => mockProc } }) - }) + } + + function runTelemetry(eventType, value) { + const originalStringify = JSON.stringify + JSON.stringify = function (obj) { + if (obj && obj.metadata && obj.points) { + if (eventType === 'spawn-error') { + mockProc.emit('error', new Error(value)) + } else if (eventType === 'exit') { + mockProc.emit('exit', value) + } else if (eventType === 'stdin-error') { + mockProc.stdin.emit('error', new Error(value)) + } + } + return originalStringify.apply(this, arguments) + } + + try { + telemetryModule([{ name: 'test', tags: [] }]) + } finally { + JSON.stringify = originalStringify + } + } - function assertMetadata (result, resultClass, resultReason) { - assert.strictEqual(telemetryModule.result, result) - assert.strictEqual(telemetryModule.resultClass, resultClass) - assert.strictEqual(telemetryModule.resultReason, resultReason) + function assertStdinMetadata(expected) { + expect(capturedStdinData).to.exist + const parsed = JSON.parse(capturedStdinData) + expect(parsed.metadata.result).to.equal(expected.result) + expect(parsed.metadata.result_class).to.equal(expected.result_class) + expect(parsed.metadata.result_reason).to.equal(expected.result_reason) } + beforeEach(() => { + mockProc = createMockProcess() + capturedStdinData = null + telemetryModule = loadTelemetryModuleWithMockProc() + }) + it('should set error metadata when telemetry forwarder fails to spawn', () => { - telemetryModule([{ name: 'test', tags: [] }]) - mockProc.emit('error', new Error('Spawn failed')) + runTelemetry('spawn-error', 'Spawn failed') - assertMetadata('error', 'internal_error', 'Failed to spawn telemetry forwarder') + assertStdinMetadata({ + result: 'error', + result_class: 'internal_error', + result_reason: 'Failed to spawn telemetry forwarder' + }) }) it('should set error metadata when telemetry forwarder exits with non-zero code', () => { - telemetryModule([{ name: 'test', tags: [] }]) - mockProc.emit('exit', 1) + runTelemetry('exit', 1) - assertMetadata('error', 'internal_error', 'Telemetry forwarder exited with code 1') + assertStdinMetadata({ + result: 'error', + result_class: 'internal_error', + result_reason: 'Telemetry forwarder exited with code 1' + }) }) it('should set error metadata when writing to telemetry forwarder fails', () => { - telemetryModule([{ name: 'test', tags: [] }]) - mockProc.stdin.emit('error', new Error('Write failed')) + runTelemetry('stdin-error', 'Write failed') - assertMetadata('error', 'internal_error', 'Failed to write telemetry data to telemetry forwarder') + assertStdinMetadata({ + result: 'error', + result_class: 'internal_error', + result_reason: 'Failed to write telemetry data to telemetry forwarder' + }) }) it('should set success metadata when telemetry forwarder exits successfully', () => { - telemetryModule([{ name: 'test', tags: [] }]) - mockProc.emit('exit', 0) + runTelemetry('exit', 0) - assertMetadata('success', 'success', 'Successfully configured ddtrace package') + assertStdinMetadata({ + result: 'success', + result_class: 'success', + result_reason: 'Successfully configured ddtrace package' + }) }) - }) + }) }) From e4327d55da6c3362d5671b7b89059c2acd2f139e Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Tue, 5 Aug 2025 12:56:23 -0400 Subject: [PATCH 18/24] format --- integration-tests/helpers/index.js | 1 - packages/dd-trace/test/guardrails/telemetry.spec.js | 13 ++++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/integration-tests/helpers/index.js b/integration-tests/helpers/index.js index e61def6a20a..a41de56ee92 100644 --- a/integration-tests/helpers/index.js +++ b/integration-tests/helpers/index.js @@ -14,7 +14,6 @@ const rimraf = promisify(require('rimraf')) const FakeAgent = require('./fake-agent') const id = require('../../packages/dd-trace/src/id') const { version } = require('../../package.json') -const telemetryModule = require('../../packages/dd-trace/src/guardrails/telemetry') const { getCappedRange } = require('../../packages/dd-trace/test/plugins/versions') const hookFile = 'dd-trace/loader-hook.mjs' diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index d776a9bd2a8..160ee4752ad 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -2,7 +2,6 @@ process.env.DD_INJECTION_ENABLED = 'true' -const assert = require('assert') const proxyquire = require('proxyquire') const { EventEmitter } = require('events') const { telemetryForwarder, assertTelemetryPoints } = require('../../../../integration-tests/helpers') @@ -71,11 +70,11 @@ describe('sendTelemetry', () => { assertTelemetryPoints(process.pid, msgs, ['abort.integration', '1']) }) }) - + describe('Error scenarios and metadata', () => { let mockProc, telemetryModule, capturedStdinData - function createMockProcess() { + function createMockProcess () { const proc = new EventEmitter() proc.stdin = new EventEmitter() proc.stdin.end = (data) => { @@ -84,13 +83,13 @@ describe('sendTelemetry', () => { return proc } - function loadTelemetryModuleWithMockProc() { + function loadTelemetryModuleWithMockProc () { return proxyquire('../../src/guardrails/telemetry', { child_process: { spawn: () => mockProc } }) } - function runTelemetry(eventType, value) { + function runTelemetry (eventType, value) { const originalStringify = JSON.stringify JSON.stringify = function (obj) { if (obj && obj.metadata && obj.points) { @@ -112,7 +111,7 @@ describe('sendTelemetry', () => { } } - function assertStdinMetadata(expected) { + function assertStdinMetadata (expected) { expect(capturedStdinData).to.exist const parsed = JSON.parse(capturedStdinData) expect(parsed.metadata.result).to.equal(expected.result) @@ -165,5 +164,5 @@ describe('sendTelemetry', () => { result_reason: 'Successfully configured ddtrace package' }) }) - }) + }) }) From 01c0dbe301e11e0a9d15a48a26b277ed0ea889f7 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Wed, 20 Aug 2025 09:44:04 -0400 Subject: [PATCH 19/24] fix metadata errors --- packages/dd-trace/src/guardrails/index.js | 13 +++- packages/dd-trace/src/guardrails/telemetry.js | 24 +++----- .../test/guardrails/telemetry.spec.js | 60 +------------------ 3 files changed, 21 insertions(+), 76 deletions(-) diff --git a/packages/dd-trace/src/guardrails/index.js b/packages/dd-trace/src/guardrails/index.js index ab60c2d550f..e96c38e7429 100644 --- a/packages/dd-trace/src/guardrails/index.js +++ b/packages/dd-trace/src/guardrails/index.js @@ -45,7 +45,11 @@ function guard (fn) { telemetry([ { name: 'abort', tags: ['reason:incompatible_runtime'] }, { name: 'abort.runtime', tags: [] } - ]) + ], { + result: 'abort', + result_class: 'incompatible_runtime', + result_reason: 'Node.js ' + NODE_MAJOR + ' is incompatible with SII' + }) log.info('Aborting application instrumentation due to incompatible_runtime.') log.info('Found incompatible runtime nodejs %s, Supported runtimes: nodejs %s.', version, engines.node) if (forced) { @@ -56,7 +60,12 @@ function guard (fn) { if (!clobberBailout && (!initBailout || forced)) { // Ensure the instrumentation source is set for the current process and potential child processes. var result = fn() - telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')]) + + telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')], { + result: 'success', + result_class: initBailout ? 'success_forced' : 'success', + result_reason: 'Successfully configured ddtrace package' + }) log.info('Application instrumentation bootstrapping complete') return result } diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index dc4a2eb4d8a..2dbadca554d 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -47,11 +47,16 @@ function shouldSend (point) { return true } -function sendTelemetry (name, tags) { +function sendTelemetry (name, tags, resultMetadata) { var points = name if (typeof name === 'string') { points = [{ name: name, tags: tags || [] }] } + + var currentMetadata = metadata + if (resultMetadata) { + currentMetadata = Object.assign({}, metadata, resultMetadata) + } if (['1', 'true', 'True'].indexOf(process.env.DD_INJECT_FORCE) !== -1) { points = points.filter(function (p) { return ['error', 'complete'].indexOf(p.name) !== -1 }) } @@ -67,27 +72,14 @@ function sendTelemetry (name, tags) { }) proc.on('error', function () { log.error('Failed to spawn telemetry forwarder') - metadata.result = 'error' - metadata.result_class = 'internal_error' - metadata.result_reason = 'Failed to spawn telemetry forwarder' }) proc.on('exit', function (code) { - if (code === 0) { - metadata.result = 'success' - metadata.result_class = 'success' - metadata.result_reason = 'Successfully configured ddtrace package' - } else { + if (code != 0) { log.error('Telemetry forwarder exited with code', code) - metadata.result = 'error' - metadata.result_class = 'internal_error' - metadata.result_reason = 'Telemetry forwarder exited with code ' + code } }) proc.stdin.on('error', function () { log.error('Failed to write telemetry data to telemetry forwarder') - metadata.result = 'error' - metadata.result_class = 'internal_error' - metadata.result_reason = 'Failed to write telemetry data to telemetry forwarder' }) - proc.stdin.end(JSON.stringify({ metadata: metadata, points: points })) + proc.stdin.end(JSON.stringify({ metadata: currentMetadata, points: points })) } diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 160ee4752ad..4d50a214d74 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -2,8 +2,6 @@ process.env.DD_INJECTION_ENABLED = 'true' -const proxyquire = require('proxyquire') -const { EventEmitter } = require('events') const { telemetryForwarder, assertTelemetryPoints } = require('../../../../integration-tests/helpers') describe('sendTelemetry', () => { @@ -18,7 +16,7 @@ describe('sendTelemetry', () => { beforeEach(() => { cleanup = telemetryForwarder() - sendTelemetry = proxyquire('../../src/guardrails/telemetry', {}) + sendTelemetry = proxyquire('../src/guardrails/telemetry', {}) }) it('should send telemetry', async () => { @@ -84,7 +82,7 @@ describe('sendTelemetry', () => { } function loadTelemetryModuleWithMockProc () { - return proxyquire('../../src/guardrails/telemetry', { + return proxyquire('../src/guardrails/telemetry', { child_process: { spawn: () => mockProc } }) } @@ -110,59 +108,5 @@ describe('sendTelemetry', () => { JSON.stringify = originalStringify } } - - function assertStdinMetadata (expected) { - expect(capturedStdinData).to.exist - const parsed = JSON.parse(capturedStdinData) - expect(parsed.metadata.result).to.equal(expected.result) - expect(parsed.metadata.result_class).to.equal(expected.result_class) - expect(parsed.metadata.result_reason).to.equal(expected.result_reason) - } - - beforeEach(() => { - mockProc = createMockProcess() - capturedStdinData = null - telemetryModule = loadTelemetryModuleWithMockProc() - }) - - it('should set error metadata when telemetry forwarder fails to spawn', () => { - runTelemetry('spawn-error', 'Spawn failed') - - assertStdinMetadata({ - result: 'error', - result_class: 'internal_error', - result_reason: 'Failed to spawn telemetry forwarder' - }) - }) - - it('should set error metadata when telemetry forwarder exits with non-zero code', () => { - runTelemetry('exit', 1) - - assertStdinMetadata({ - result: 'error', - result_class: 'internal_error', - result_reason: 'Telemetry forwarder exited with code 1' - }) - }) - - it('should set error metadata when writing to telemetry forwarder fails', () => { - runTelemetry('stdin-error', 'Write failed') - - assertStdinMetadata({ - result: 'error', - result_class: 'internal_error', - result_reason: 'Failed to write telemetry data to telemetry forwarder' - }) - }) - - it('should set success metadata when telemetry forwarder exits successfully', () => { - runTelemetry('exit', 0) - - assertStdinMetadata({ - result: 'success', - result_class: 'success', - result_reason: 'Successfully configured ddtrace package' - }) - }) }) }) From a9f35030a8598edd5e7d2f91349620cbe901c743 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Wed, 20 Aug 2025 10:24:13 -0400 Subject: [PATCH 20/24] fix format --- packages/dd-trace/src/guardrails/index.js | 1 - packages/dd-trace/src/guardrails/telemetry.js | 10 +++-- .../test/guardrails/telemetry.spec.js | 42 ------------------- 3 files changed, 7 insertions(+), 46 deletions(-) diff --git a/packages/dd-trace/src/guardrails/index.js b/packages/dd-trace/src/guardrails/index.js index e96c38e7429..05edf0c9def 100644 --- a/packages/dd-trace/src/guardrails/index.js +++ b/packages/dd-trace/src/guardrails/index.js @@ -60,7 +60,6 @@ function guard (fn) { if (!clobberBailout && (!initBailout || forced)) { // Ensure the instrumentation source is set for the current process and potential child processes. var result = fn() - telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')], { result: 'success', result_class: initBailout ? 'success_forced' : 'success', diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index 2dbadca554d..b53a8bec866 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -52,10 +52,14 @@ function sendTelemetry (name, tags, resultMetadata) { if (typeof name === 'string') { points = [{ name: name, tags: tags || [] }] } - var currentMetadata = metadata if (resultMetadata) { - currentMetadata = Object.assign({}, metadata, resultMetadata) + for (var key in metadata) { + currentMetadata[key] = metadata[key] + } + for (var key in resultMetadata) { + currentMetadata[key] = resultMetadata[key] + } } if (['1', 'true', 'True'].indexOf(process.env.DD_INJECT_FORCE) !== -1) { points = points.filter(function (p) { return ['error', 'complete'].indexOf(p.name) !== -1 }) @@ -74,7 +78,7 @@ function sendTelemetry (name, tags, resultMetadata) { log.error('Failed to spawn telemetry forwarder') }) proc.on('exit', function (code) { - if (code != 0) { + if (code !== 0) { log.error('Telemetry forwarder exited with code', code) } }) diff --git a/packages/dd-trace/test/guardrails/telemetry.spec.js b/packages/dd-trace/test/guardrails/telemetry.spec.js index 47b263bcdcf..4ed8d5e3119 100644 --- a/packages/dd-trace/test/guardrails/telemetry.spec.js +++ b/packages/dd-trace/test/guardrails/telemetry.spec.js @@ -68,46 +68,4 @@ describe('sendTelemetry', () => { assertTelemetryPoints(process.pid, msgs, ['abort.integration', '1']) }) }) - - describe('Error scenarios and metadata', () => { - let mockProc, telemetryModule, capturedStdinData - - function createMockProcess () { - const proc = new EventEmitter() - proc.stdin = new EventEmitter() - proc.stdin.end = (data) => { - capturedStdinData = data - } - return proc - } - - function loadTelemetryModuleWithMockProc () { - return proxyquire('../src/guardrails/telemetry', { - child_process: { spawn: () => mockProc } - }) - } - - function runTelemetry (eventType, value) { - const originalStringify = JSON.stringify - JSON.stringify = function (obj) { - if (obj && obj.metadata && obj.points) { - if (eventType === 'spawn-error') { - mockProc.emit('error', new Error(value)) - } else if (eventType === 'exit') { - mockProc.emit('exit', value) - } else if (eventType === 'stdin-error') { - mockProc.stdin.emit('error', new Error(value)) - } - } - return originalStringify.apply(this, arguments) - } - - try { - telemetryModule([{ name: 'test', tags: [] }]) - } finally { - JSON.stringify = originalStringify - } - } - - }) }) From f2dc1efb87626cdd9777e9f3709fc5b982b4794c Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Wed, 20 Aug 2025 10:31:30 -0400 Subject: [PATCH 21/24] fix syntax --- packages/dd-trace/src/guardrails/telemetry.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/dd-trace/src/guardrails/telemetry.js b/packages/dd-trace/src/guardrails/telemetry.js index b53a8bec866..d5bde38859b 100644 --- a/packages/dd-trace/src/guardrails/telemetry.js +++ b/packages/dd-trace/src/guardrails/telemetry.js @@ -54,11 +54,12 @@ function sendTelemetry (name, tags, resultMetadata) { } var currentMetadata = metadata if (resultMetadata) { + currentMetadata = {} for (var key in metadata) { currentMetadata[key] = metadata[key] } - for (var key in resultMetadata) { - currentMetadata[key] = resultMetadata[key] + for (var curr in resultMetadata) { + currentMetadata[curr] = resultMetadata[curr] } } if (['1', 'true', 'True'].indexOf(process.env.DD_INJECT_FORCE) !== -1) { From ffce3f467c9e32968d73e58b6783cce362aa6cd0 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Thu, 21 Aug 2025 09:37:50 -0400 Subject: [PATCH 22/24] debug index tests --- integration-tests/helpers/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/integration-tests/helpers/index.js b/integration-tests/helpers/index.js index a41de56ee92..857cb8e3582 100644 --- a/integration-tests/helpers/index.js +++ b/integration-tests/helpers/index.js @@ -114,9 +114,9 @@ function assertTelemetryPoints (pid, msgs, expectedTelemetryPoints) { runtime_version: process.versions.node, tracer_version: require('../../package.json').version, pid: Number(pid), - result: 'unknown', - result_reason: 'unknown', - result_class: 'unknown' + result: 'success', + result_reason: 'Successfully configured ddtrace package', + result_class: 'success' } } } @@ -259,7 +259,7 @@ async function createSandbox (dependencies = [], isGitRepo = false, function telemetryForwarder (shouldExpectTelemetryPoints = true) { process.env.DD_TELEMETRY_FORWARDER_PATH = - path.join(__dirname, '..', 'telemetry-forwarder.sh') + path.join(__dirname, '..', 'telemetry-forwarder.sh') process.env.FORWARDER_OUT = path.join(__dirname, `forwarder-${Date.now()}.out`) let retries = 0 From 42cf67cb1e87046ccb32639f900ac21fc9e09f14 Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Fri, 22 Aug 2025 11:46:37 -0400 Subject: [PATCH 23/24] added condition for already_instrumented --- integration-tests/helpers/index.js | 24 ++++------ packages/dd-trace/src/guardrails/index.js | 55 ++++++++++++++--------- 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/integration-tests/helpers/index.js b/integration-tests/helpers/index.js index 857cb8e3582..6bd52039766 100644 --- a/integration-tests/helpers/index.js +++ b/integration-tests/helpers/index.js @@ -78,7 +78,15 @@ function assertTelemetryPoints (pid, msgs, expectedTelemetryPoints) { let points = [] for (const [telemetryType, data] of msgs) { assert.strictEqual(telemetryType, 'library_entrypoint') - assert.deepStrictEqual(data.metadata, meta(pid)) + assert.strictEqual(data.metadata.language_name, 'nodejs') + assert.strictEqual(data.metadata.language_version, process.versions.node) + assert.strictEqual(data.metadata.runtime_name, 'nodejs') + assert.strictEqual(data.metadata.runtime_version, process.versions.node) + assert.strictEqual(data.metadata.tracer_version, require('../../package.json').version) + assert.strictEqual(data.metadata.pid, Number(pid)) + assert.ok(typeof data.metadata.result === 'string') + assert.ok(typeof data.metadata.result_class === 'string') + assert.ok(typeof data.metadata.result_reason === 'string') points = points.concat(data.points) } const expectedPoints = getPoints(...expectedTelemetryPoints) @@ -105,20 +113,6 @@ function assertTelemetryPoints (pid, msgs, expectedTelemetryPoints) { } return expectedPoints } - - function meta (pid) { - return { - language_name: 'nodejs', - language_version: process.versions.node, - runtime_name: 'nodejs', - runtime_version: process.versions.node, - tracer_version: require('../../package.json').version, - pid: Number(pid), - result: 'success', - result_reason: 'Successfully configured ddtrace package', - result_class: 'success' - } - } } /** diff --git a/packages/dd-trace/src/guardrails/index.js b/packages/dd-trace/src/guardrails/index.js index 05edf0c9def..79dbb3aa3cf 100644 --- a/packages/dd-trace/src/guardrails/index.js +++ b/packages/dd-trace/src/guardrails/index.js @@ -38,35 +38,46 @@ function guard (fn) { } } - // If the runtime doesn't match the engines field in package.json, then we - // should not initialize the tracer. - if (!clobberBailout && NODE_MAJOR < minMajor) { - initBailout = true + if (clobberBailout) { telemetry([ - { name: 'abort', tags: ['reason:incompatible_runtime'] }, + { name: 'abort', tags: ['reason:already_instrumented'] }, { name: 'abort.runtime', tags: [] } ], { result: 'abort', - result_class: 'incompatible_runtime', - result_reason: 'Node.js ' + NODE_MAJOR + ' is incompatible with SII' + result_class: 'already_instrumented', + result_reason: 'Node.js is already instrumented' }) - log.info('Aborting application instrumentation due to incompatible_runtime.') - log.info('Found incompatible runtime nodejs %s, Supported runtimes: nodejs %s.', version, engines.node) - if (forced) { - log.info('DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.') + } else { + // If the runtime doesn't match the engines field in package.json, then we + // should not initialize the tracer. + if (!clobberBailout && NODE_MAJOR < minMajor) { + initBailout = true + telemetry([ + { name: 'abort', tags: ['reason:incompatible_runtime'] }, + { name: 'abort.runtime', tags: [] } + ], { + result: 'abort', + result_class: 'incompatible_runtime', + result_reason: 'Node.js ' + NODE_MAJOR + ' is incompatible with SII' + }) + log.info('Aborting application instrumentation due to incompatible_runtime.') + log.info('Found incompatible runtime nodejs %s, Supported runtimes: nodejs %s.', version, engines.node) + if (forced) { + log.info('DD_INJECT_FORCE enabled, allowing unsupported runtimes and continuing.') + } } - } - if (!clobberBailout && (!initBailout || forced)) { - // Ensure the instrumentation source is set for the current process and potential child processes. - var result = fn() - telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')], { - result: 'success', - result_class: initBailout ? 'success_forced' : 'success', - result_reason: 'Successfully configured ddtrace package' - }) - log.info('Application instrumentation bootstrapping complete') - return result + if (!clobberBailout && (!initBailout || forced)) { + // Ensure the instrumentation source is set for the current process and potential child processes. + var result = fn() + telemetry('complete', ['injection_forced:' + (forced && initBailout ? 'true' : 'false')], { + result: 'success', + result_class: initBailout ? 'success_forced' : 'success', + result_reason: 'Successfully configured ddtrace package' + }) + log.info('Application instrumentation bootstrapping complete') + return result + } } } From 97a88c66542dfe74549a95bac9189fe2ae40813d Mon Sep 17 00:00:00 2001 From: Sydney Tung Date: Fri, 22 Aug 2025 12:01:44 -0400 Subject: [PATCH 24/24] added already_instrumented tests --- integration-tests/init.spec.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/integration-tests/init.spec.js b/integration-tests/init.spec.js index 6435b96b3e4..4bf2e633a6b 100644 --- a/integration-tests/init.spec.js +++ b/integration-tests/init.spec.js @@ -16,6 +16,7 @@ const DD_INJECT_FORCE = 'true' const DD_TRACE_DEBUG = 'true' const telemetryAbort = ['abort', 'reason:incompatible_runtime', 'abort.runtime', ''] +const telemetryInstrumented = ['abort', 'reason:already_instrumented', 'abort.runtime', ''] const telemetryForced = ['complete', 'injection_forced:true'] const telemetryGood = ['complete', 'injection_forced:false'] @@ -47,9 +48,9 @@ function testInjectionScenarios (arg, filename, esmWorks = false) { context('with DD_INJECTION_ENABLED', () => { useEnv({ DD_INJECTION_ENABLED }) - it('should not initialize the tracer', () => doTest('init/trace.js', 'false\n', [])) - it('should not initialize instrumentation', () => doTest('init/instrument.js', 'false\n', [])) - it('should not initialize ESM instrumentation', () => doTest('init/instrument.mjs', 'false\n', [])) + it('should not initialize the tracer', () => doTest('init/trace.js', 'false\n', telemetryInstrumented)) + it('should not initialize', () => doTest('init/instrument.js', 'false\n', telemetryInstrumented)) + it('should not initialize', () => doTest('init/instrument.mjs', 'false\n', telemetryInstrumented)) }) }) context('when dd-trace in the app dir', () => {