Skip to content

Commit 8debc3b

Browse files
tlhunterBridgeAR
authored andcommitted
fix(config): apply pm2_env env vars before tracer init (#8863)
1 parent 76baf63 commit 8debc3b

4 files changed

Lines changed: 81 additions & 0 deletions

File tree

eslint.config.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,9 @@ export default [
690690
// The following are false positives that are supported in Node.js 0.8.0
691691
ignores: [
692692
'JSON',
693+
'JSON.parse',
693694
'JSON.stringify',
695+
'Object.keys',
694696
'parseInt',
695697
'String',
696698
],
@@ -700,6 +702,7 @@ export default [
700702
ignores: [
701703
'array-prototype-indexof',
702704
'json',
705+
'object-keys',
703706
],
704707
}],
705708
'no-var': 'off', // Only supported in Node.js 6+

init.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,23 @@
11
'use strict'
22

3+
// In PM2 cluster mode, per-app env vars arrive as a `pm2_env`
4+
// JSON string after --require has already run so we extract them
5+
// manually if present.
6+
var pm2EnvStr = process.env.pm2_env
7+
if (typeof pm2EnvStr === 'string') {
8+
try {
9+
var pm2Config = JSON.parse(pm2EnvStr)
10+
var pm2Keys = Object.keys(pm2Config)
11+
for (var i = 0; i < pm2Keys.length; i++) {
12+
var k = pm2Keys[i]
13+
var v = pm2Config[k]
14+
if (v != null) {
15+
process.env[k] = String(v)
16+
}
17+
}
18+
} catch (e) {}
19+
}
20+
321
var guard = require('./packages/dd-trace/src/guardrails')
422

523
module.exports = guard(function () {

integration-tests/init.spec.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,56 @@ describe('init.js', () => {
272272

273273
testInjectionScenarios('require', 'init.js', false)
274274
testRuntimeVersionChecks('require', 'init.js')
275+
276+
describe('PM2 cluster mode', () => {
277+
useEnv({ NODE_OPTIONS: '--require dd-trace/init' })
278+
279+
afterEach(() => {
280+
delete process.env.pm2_env
281+
})
282+
283+
function checkEnv (expectedValues) {
284+
return testFile('init/pm2-env.js', out => {
285+
const env = JSON.parse(out.trim())
286+
for (const [key, value] of Object.entries(expectedValues)) {
287+
assert.strictEqual(env[key], value, `expected env.${key} to equal ${value}`)
288+
}
289+
}, [], '')
290+
}
291+
292+
it('applies all env vars from pm2_env blob to process.env', () => {
293+
process.env.pm2_env = JSON.stringify({ DD_SERVICE: 'pm2-svc', DD_ENV: 'pm2-env', MY_APP_VAR: 'hello' })
294+
return checkEnv({ DD_SERVICE: 'pm2-svc', DD_ENV: 'pm2-env', MY_APP_VAR: 'hello' })
295+
})
296+
297+
it('coerces non-string values to strings', () => {
298+
process.env.pm2_env = JSON.stringify({ DD_TRACE_SAMPLE_RATE: 0.5 })
299+
return checkEnv({ DD_TRACE_SAMPLE_RATE: '0.5' })
300+
})
301+
302+
it('skips keys with null values', () => {
303+
process.env.pm2_env = JSON.stringify({ DD_SERVICE: null })
304+
return checkEnv({ DD_SERVICE: undefined })
305+
})
306+
307+
it('does not crash on malformed pm2_env JSON', () => {
308+
process.env.pm2_env = 'not-valid-json'
309+
return checkEnv({ DD_SERVICE: undefined })
310+
})
311+
312+
it('does nothing when pm2_env is absent', () => {
313+
return checkEnv({ DD_SERVICE: undefined })
314+
})
315+
316+
describe('when env vars are already set', () => {
317+
useEnv({ DD_SERVICE: 'original-service', MY_APP_VAR: 'original' })
318+
319+
it('overwrites existing env vars with pm2_env values', () => {
320+
process.env.pm2_env = JSON.stringify({ DD_SERVICE: 'pm2-service', MY_APP_VAR: 'pm2-value' })
321+
return checkEnv({ DD_SERVICE: 'pm2-service', MY_APP_VAR: 'pm2-value' })
322+
})
323+
})
324+
})
275325
})
276326

277327
// ESM is not supportable prior to Node.js 14.13.1 on the 14.x line,

integration-tests/init/pm2-env.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
'use strict'
2+
3+
// eslint-disable-next-line no-console
4+
console.log(JSON.stringify({
5+
DD_SERVICE: process.env.DD_SERVICE,
6+
DD_ENV: process.env.DD_ENV,
7+
DD_TRACE_SAMPLE_RATE: process.env.DD_TRACE_SAMPLE_RATE,
8+
MY_APP_VAR: process.env.MY_APP_VAR,
9+
}))
10+
process.exit()

0 commit comments

Comments
 (0)