Skip to content

Commit d26e1a9

Browse files
andreiborzaLms24
andauthored
feat(aws): Add SENTRY_LAYER_EXTENSION to configure using the lambda layer extension via env variables (#18101)
Our recommended approach for the aws sdk is to use our Lambda layer. When the Lambda layer is used, it would previously automatically set up the layer extension. This can be disabled by setting `useLayerExtension: false` during init, but when using the layer with our auto-wrapping as per recommendation, it wasn't possible to opt out of using the extension. This PR adds `SENTRY_LAYER_EXTENSION` that can be used to opt out of the extension. --------- Co-authored-by: Lukas Stracke <[email protected]>
1 parent d4a2b2b commit d26e1a9

File tree

3 files changed

+124
-13
lines changed

3 files changed

+124
-13
lines changed

packages/aws-serverless/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"@opentelemetry/semantic-conventions": "^1.37.0",
7272
"@sentry/core": "10.23.0",
7373
"@sentry/node": "10.23.0",
74+
"@sentry/node-core": "10.23.0",
7475
"@types/aws-lambda": "^8.10.62"
7576
},
7677
"devDependencies": {

packages/aws-serverless/src/init.ts

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Integration, Options } from '@sentry/core';
22
import { applySdkMetadata, debug, getSDKSource } from '@sentry/core';
33
import type { NodeClient, NodeOptions } from '@sentry/node';
44
import { getDefaultIntegrationsWithoutPerformance, initWithoutDefaultIntegrations } from '@sentry/node';
5+
import { envToBool } from '@sentry/node-core';
56
import { DEBUG_BUILD } from './debug-build';
67
import { awsIntegration } from './integration/aws';
78
import { awsLambdaIntegration } from './integration/awslambda';
@@ -54,7 +55,10 @@ export function getDefaultIntegrations(_options: Options): Integration[] {
5455

5556
export interface AwsServerlessOptions extends NodeOptions {
5657
/**
57-
* If Sentry events should be proxied through the Lambda extension when using the Lambda layer. Defaults to `true` when using the Lambda layer.
58+
* If Sentry events should be proxied through the Lambda extension when using the Lambda layer.
59+
* Defaults to `true` when using the Lambda layer.
60+
*
61+
* Can also be configured via the `SENTRY_LAYER_EXTENSION` environment variable.
5862
*/
5963
useLayerExtension?: boolean;
6064
}
@@ -68,31 +72,41 @@ export function init(options: AwsServerlessOptions = {}): NodeClient | undefined
6872
const sdkSource = getSDKSource();
6973
const proxyWouldInterfere = shouldDisableLayerExtensionForProxy();
7074

75+
// Determine useLayerExtension value with the following priority:
76+
// 1. Explicit option value (if provided)
77+
// 2. Environment variable SENTRY_LAYER_EXTENSION (if set)
78+
// 3. Default logic based on sdkSource, tunnel, and proxy settings
79+
const useLayerExtensionFromEnv = envToBool(process.env.SENTRY_LAYER_EXTENSION, { strict: true });
80+
const defaultUseLayerExtension = sdkSource === 'aws-lambda-layer' && !options.tunnel && !proxyWouldInterfere;
81+
const useLayerExtension = options.useLayerExtension ?? useLayerExtensionFromEnv ?? defaultUseLayerExtension;
82+
7183
const opts = {
7284
defaultIntegrations: getDefaultIntegrations(options),
73-
useLayerExtension: sdkSource === 'aws-lambda-layer' && !options.tunnel && !proxyWouldInterfere,
85+
useLayerExtension,
7486
...options,
7587
};
7688

7789
if (opts.useLayerExtension) {
78-
if (sdkSource === 'aws-lambda-layer') {
79-
if (!opts.tunnel) {
80-
DEBUG_BUILD && debug.log('Proxying Sentry events through the Sentry Lambda extension');
81-
opts.tunnel = 'http://localhost:9000/envelope';
82-
} else {
90+
if (sdkSource !== 'aws-lambda-layer') {
91+
DEBUG_BUILD && debug.warn('The Sentry Lambda extension is only supported when using the AWS Lambda layer.');
92+
} else if (opts.tunnel || proxyWouldInterfere) {
93+
if (opts.tunnel) {
8394
DEBUG_BUILD &&
8495
debug.warn(
8596
`Using a custom tunnel with the Sentry Lambda extension is not supported. Events will be tunnelled to ${opts.tunnel} and not through the extension.`,
8697
);
8798
}
99+
100+
if (proxyWouldInterfere) {
101+
DEBUG_BUILD &&
102+
debug.warn(
103+
'Sentry Lambda extension is disabled due to proxy environment variables (http_proxy/https_proxy). Consider adding localhost to no_proxy to re-enable.',
104+
);
105+
}
88106
} else {
89-
DEBUG_BUILD && debug.warn('The Sentry Lambda extension is only supported when using the AWS Lambda layer.');
107+
DEBUG_BUILD && debug.log('Proxying Sentry events through the Sentry Lambda extension');
108+
opts.tunnel = 'http://localhost:9000/envelope';
90109
}
91-
} else if (sdkSource === 'aws-lambda-layer' && proxyWouldInterfere) {
92-
DEBUG_BUILD &&
93-
debug.warn(
94-
'Sentry Lambda extension disabled due to proxy environment variables (http_proxy/https_proxy). Consider adding localhost to no_proxy to re-enable.',
95-
);
96110
}
97111

98112
applySdkMetadata(opts, 'aws-serverless', ['aws-serverless'], sdkSource);

packages/aws-serverless/test/init.test.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,13 @@ const mockInitWithoutDefaultIntegrations = vi.mocked(initWithoutDefaultIntegrati
1919

2020
describe('init', () => {
2121
beforeEach(() => {
22+
// Clear all mocks between tests
23+
vi.clearAllMocks();
24+
2225
// Clean up environment variables between tests
2326
delete process.env.http_proxy;
2427
delete process.env.no_proxy;
28+
delete process.env.SENTRY_LAYER_EXTENSION;
2529
});
2630

2731
describe('Lambda extension setup', () => {
@@ -386,4 +390,96 @@ describe('init', () => {
386390
);
387391
});
388392
});
393+
394+
describe('SENTRY_LAYER_EXTENSION environment variable', () => {
395+
test('should enable useLayerExtension when SENTRY_LAYER_EXTENSION=true', () => {
396+
process.env.SENTRY_LAYER_EXTENSION = 'true';
397+
mockGetSDKSource.mockReturnValue('aws-lambda-layer');
398+
const options: AwsServerlessOptions = {};
399+
400+
init(options);
401+
402+
expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith(
403+
expect.objectContaining({
404+
useLayerExtension: true,
405+
tunnel: 'http://localhost:9000/envelope',
406+
}),
407+
);
408+
});
409+
410+
test('should disable useLayerExtension when SENTRY_LAYER_EXTENSION=false', () => {
411+
process.env.SENTRY_LAYER_EXTENSION = 'false';
412+
mockGetSDKSource.mockReturnValue('aws-lambda-layer');
413+
const options: AwsServerlessOptions = {};
414+
415+
init(options);
416+
417+
expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith(
418+
expect.objectContaining({
419+
useLayerExtension: false,
420+
}),
421+
);
422+
expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith(
423+
expect.not.objectContaining({
424+
tunnel: expect.any(String),
425+
}),
426+
);
427+
});
428+
429+
test('should fall back to default behavior when SENTRY_LAYER_EXTENSION is not set', () => {
430+
mockGetSDKSource.mockReturnValue('aws-lambda-layer');
431+
const options: AwsServerlessOptions = {};
432+
433+
init(options);
434+
435+
expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith(
436+
expect.objectContaining({
437+
useLayerExtension: true,
438+
tunnel: 'http://localhost:9000/envelope',
439+
}),
440+
);
441+
});
442+
443+
test('should prioritize explicit option over environment variable', () => {
444+
process.env.SENTRY_LAYER_EXTENSION = 'true';
445+
mockGetSDKSource.mockReturnValue('aws-lambda-layer');
446+
const options: AwsServerlessOptions = {
447+
useLayerExtension: false,
448+
};
449+
450+
init(options);
451+
452+
expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith(
453+
expect.objectContaining({
454+
useLayerExtension: false,
455+
}),
456+
);
457+
expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith(
458+
expect.not.objectContaining({
459+
tunnel: expect.any(String),
460+
}),
461+
);
462+
});
463+
464+
test('should not set tunnel even tho useLayerExtension is set via env var when proxy is explicitly set', () => {
465+
process.env.http_proxy = 'http://proxy.example.com:8080';
466+
process.env.SENTRY_LAYER_EXTENSION = 'true';
467+
mockGetSDKSource.mockReturnValue('aws-lambda-layer');
468+
const options: AwsServerlessOptions = {};
469+
470+
init(options);
471+
472+
// useLayerExtension is respected but tunnel is not set due to proxy interference
473+
expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith(
474+
expect.objectContaining({
475+
useLayerExtension: true,
476+
}),
477+
);
478+
expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith(
479+
expect.not.objectContaining({
480+
tunnel: expect.any(String),
481+
}),
482+
);
483+
});
484+
});
389485
});

0 commit comments

Comments
 (0)