Skip to content

Commit 55220cf

Browse files
BYKBurak Yigit Kaya
and
Burak Yigit Kaya
authored
feat: Add support for SENTRY_SPOTLIGHT env var in Node (#13325)
Enable sending events to spotlight by setting the `SENTRY_SPOTLIGHT` environment variable --------- Co-authored-by: Burak Yigit Kaya <[email protected]>
1 parent 479668b commit 55220cf

File tree

5 files changed

+120
-6
lines changed

5 files changed

+120
-6
lines changed

.vscode/settings.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,5 @@
4242
"[typescript]": {
4343
"editor.defaultFormatter": "biomejs.biome"
4444
},
45-
"cSpell.words": ["arrayify"]
45+
"cSpell.words": ["arrayify", "OTEL"]
4646
}

packages/node/src/preload.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { preloadOpenTelemetry } from './sdk/initOtel';
2+
import { envToBool } from './utils/envToBool';
23

3-
const debug = !!process.env.SENTRY_DEBUG;
4+
const debug = envToBool(process.env.SENTRY_DEBUG);
45
const integrationsStr = process.env.SENTRY_PRELOAD_INTEGRATIONS;
56

67
const integrations = integrationsStr ? integrationsStr.split(',').map(integration => integration.trim()) : undefined;
78

89
/**
9-
* The @sentry/node/preload export can be used with the node --import and --require args to preload the OTEL instrumentation,
10-
* without initializing the Sentry SDK.
10+
* The @sentry/node/preload export can be used with the node --import and --require args to preload the OTEL
11+
* instrumentation, without initializing the Sentry SDK.
1112
*
1213
* This is useful if you cannot initialize the SDK immediately, but still want to preload the instrumentation,
1314
* e.g. if you have to load the DSN from somewhere else.

packages/node/src/sdk/index.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { getAutoPerformanceIntegrations } from '../integrations/tracing';
4141
import { makeNodeTransport } from '../transports';
4242
import type { NodeClientOptions, NodeOptions } from '../types';
4343
import { isCjs } from '../utils/commonjs';
44+
import { envToBool } from '../utils/envToBool';
4445
import { defaultStackParser, getSentryRelease } from './api';
4546
import { NodeClient } from './client';
4647
import { initOpenTelemetry, maybeInitializeEsmLoader } from './initOtel';
@@ -221,6 +222,15 @@ function getClientOptions(
221222
? true
222223
: options.autoSessionTracking;
223224

225+
if (options.spotlight == null) {
226+
const spotlightEnv = envToBool(process.env.SENTRY_SPOTLIGHT, { strict: true });
227+
if (spotlightEnv == null) {
228+
options.spotlight = process.env.SENTRY_SPOTLIGHT;
229+
} else {
230+
options.spotlight = spotlightEnv;
231+
}
232+
}
233+
224234
const tracesSampleRate = getTracesSampleRate(options.tracesSampleRate);
225235

226236
const baseOptions = dropUndefinedKeys({
@@ -292,8 +302,7 @@ function getTracesSampleRate(tracesSampleRate: NodeOptions['tracesSampleRate']):
292302
* for more details.
293303
*/
294304
function updateScopeFromEnvVariables(): void {
295-
const sentryUseEnvironment = (process.env.SENTRY_USE_ENVIRONMENT || '').toLowerCase();
296-
if (!['false', 'n', 'no', 'off', '0'].includes(sentryUseEnvironment)) {
305+
if (envToBool(process.env.SENTRY_USE_ENVIRONMENT) !== false) {
297306
const sentryTraceEnv = process.env.SENTRY_TRACE;
298307
const baggageEnv = process.env.SENTRY_BAGGAGE;
299308
const propagationContext = propagationContextFromHeaders(sentryTraceEnv, baggageEnv);

packages/node/src/utils/envToBool.ts

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
export const FALSY_ENV_VALUES = new Set(['false', 'f', 'n', 'no', 'off', '0']);
2+
export const TRUTHY_ENV_VALUES = new Set(['true', 't', 'y', 'yes', 'on', '1']);
3+
4+
export type StrictBoolCast = {
5+
strict: true;
6+
};
7+
8+
export type LooseBoolCast = {
9+
strict?: false;
10+
};
11+
12+
export type BoolCastOptions = StrictBoolCast | LooseBoolCast;
13+
14+
export function envToBool(value: unknown, options?: LooseBoolCast): boolean;
15+
export function envToBool(value: unknown, options: StrictBoolCast): boolean | null;
16+
export function envToBool(value: unknown, options?: BoolCastOptions): boolean | null;
17+
/**
18+
* A helper function which casts an ENV variable value to `true` or `false` using the constants defined above.
19+
* In strict mode, it may return `null` if the value doesn't match any of the predefined values.
20+
*
21+
* @param value The value of the env variable
22+
* @param options -- Only has `strict` key for now, which requires a strict match for `true` in TRUTHY_ENV_VALUES
23+
* @returns true/false if the lowercase value matches the predefined values above. If not, null in strict mode,
24+
* and Boolean(value) in loose mode.
25+
*/
26+
export function envToBool(value: unknown, options?: BoolCastOptions): boolean | null {
27+
const normalized = String(value).toLowerCase();
28+
29+
if (FALSY_ENV_VALUES.has(normalized)) {
30+
return false;
31+
}
32+
33+
if (TRUTHY_ENV_VALUES.has(normalized)) {
34+
return true;
35+
}
36+
37+
return options && options.strict ? null : Boolean(value);
38+
}
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { envToBool } from '../../src/utils/envToBool';
2+
3+
describe('envToBool', () => {
4+
it.each([
5+
['', true, null],
6+
['', false, false],
7+
['t', true, true],
8+
['T', true, true],
9+
['t', false, true],
10+
['T', false, true],
11+
['y', true, true],
12+
['Y', true, true],
13+
['y', false, true],
14+
['Y', false, true],
15+
['1', true, true],
16+
['1', false, true],
17+
['true', true, true],
18+
['true', false, true],
19+
['tRuE', true, true],
20+
['tRuE', false, true],
21+
['Yes', true, true],
22+
['Yes', false, true],
23+
['yes', true, true],
24+
['yes', false, true],
25+
['yEs', true, true],
26+
['yEs', false, true],
27+
['On', true, true],
28+
['On', false, true],
29+
['on', true, true],
30+
['on', false, true],
31+
['oN', true, true],
32+
['oN', false, true],
33+
['f', true, false],
34+
['f', false, false],
35+
['n', true, false],
36+
['N', true, false],
37+
['n', false, false],
38+
['N', false, false],
39+
['0', true, false],
40+
['0', false, false],
41+
['false', true, false],
42+
['false', false, false],
43+
['false', true, false],
44+
['false', false, false],
45+
['FaLsE', true, false],
46+
['FaLsE', false, false],
47+
['No', true, false],
48+
['No', false, false],
49+
['no', true, false],
50+
['no', false, false],
51+
['nO', true, false],
52+
['nO', false, false],
53+
['Off', true, false],
54+
['Off', false, false],
55+
['off', true, false],
56+
['off', false, false],
57+
['oFf', true, false],
58+
['oFf', false, false],
59+
['xxx', true, null],
60+
['xxx', false, true],
61+
[undefined, false, false],
62+
[undefined, true, null],
63+
])('%s becomes (strict: %s): %s', (value, strict, expected) => {
64+
expect(envToBool(value, { strict })).toBe(expected);
65+
});
66+
});

0 commit comments

Comments
 (0)