From 2fc89a454904de80c00839ff87d0b07877e6eade Mon Sep 17 00:00:00 2001 From: Martin Sonnberger Date: Wed, 17 Sep 2025 11:58:42 +0200 Subject: [PATCH 1/4] chore(aws): Remove experimental flag for Lambda extension --- .../ExperimentalExtension/index.mjs | 16 ------- .../aws-serverless/tests/layer.test.ts | 48 ------------------- packages/aws-serverless/src/init.ts | 16 +++---- packages/aws-serverless/test/init.test.ts | 39 +++++++++------ 4 files changed, 32 insertions(+), 87 deletions(-) delete mode 100644 dev-packages/e2e-tests/test-applications/aws-serverless/src/lambda-functions-layer/ExperimentalExtension/index.mjs diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/src/lambda-functions-layer/ExperimentalExtension/index.mjs b/dev-packages/e2e-tests/test-applications/aws-serverless/src/lambda-functions-layer/ExperimentalExtension/index.mjs deleted file mode 100644 index d4cd56b78c90..000000000000 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/src/lambda-functions-layer/ExperimentalExtension/index.mjs +++ /dev/null @@ -1,16 +0,0 @@ -import * as Sentry from '@sentry/aws-serverless'; - -Sentry.init({ - dsn: process.env.SENTRY_DSN, - tracesSampleRate: 1, - debug: true, - _experiments: { - enableLambdaExtension: true, - }, -}); - -export const handler = async (event, context) => { - Sentry.startSpan({ name: 'manual-span', op: 'test' }, async () => { - return 'Hello, world!'; - }); -}; diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts index 6ec76124140d..bb7ae03a96e7 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts @@ -242,52 +242,4 @@ test.describe('Lambda layer', () => { }), ); }); - - test('experimental extension works', async ({ lambdaClient }) => { - const transactionEventPromise = waitForTransaction('aws-serverless-lambda-sam', transactionEvent => { - return transactionEvent?.transaction === 'LayerExperimentalExtension'; - }); - - await lambdaClient.send( - new InvokeCommand({ - FunctionName: 'LayerExperimentalExtension', - Payload: JSON.stringify({}), - }), - ); - - const transactionEvent = await transactionEventPromise; - - expect(transactionEvent.transaction).toEqual('LayerExperimentalExtension'); - expect(transactionEvent.contexts?.trace).toEqual({ - data: { - 'sentry.sample_rate': 1, - 'sentry.source': 'custom', - 'sentry.origin': 'auto.otel.aws-lambda', - 'sentry.op': 'function.aws.lambda', - 'cloud.account.id': '012345678912', - 'faas.execution': expect.any(String), - 'faas.id': 'arn:aws:lambda:us-east-1:012345678912:function:LayerExperimentalExtension', - 'faas.coldstart': true, - 'otel.kind': 'SERVER', - }, - op: 'function.aws.lambda', - origin: 'auto.otel.aws-lambda', - span_id: expect.stringMatching(/[a-f0-9]{16}/), - status: 'ok', - trace_id: expect.stringMatching(/[a-f0-9]{32}/), - }); - - expect(transactionEvent.spans).toHaveLength(1); - - expect(transactionEvent.spans).toContainEqual( - expect.objectContaining({ - data: expect.objectContaining({ - 'sentry.op': 'test', - 'sentry.origin': 'manual', - }), - description: 'manual-span', - op: 'test', - }), - ); - }); }); diff --git a/packages/aws-serverless/src/init.ts b/packages/aws-serverless/src/init.ts index 9de744bedf34..7bdcc1c58e9d 100644 --- a/packages/aws-serverless/src/init.ts +++ b/packages/aws-serverless/src/init.ts @@ -15,12 +15,10 @@ export function getDefaultIntegrations(_options: Options): Integration[] { } export interface AwsServerlessOptions extends NodeOptions { - _experiments?: NodeOptions['_experiments'] & { - /** - * If proxying Sentry events through the Sentry Lambda extension should be enabled. - */ - enableLambdaExtension?: boolean; - }; + /** + * If proxying Sentry events through the Sentry Lambda extension should be enabled. Defaults to `true` when using the AWS Lambda layer. + */ + enableLambdaExtension?: boolean; } /** @@ -29,14 +27,14 @@ export interface AwsServerlessOptions extends NodeOptions { * @param options Configuration options for the SDK, @see {@link AWSLambdaOptions}. */ export function init(options: AwsServerlessOptions = {}): NodeClient | undefined { + const sdkSource = getSDKSource(); const opts = { defaultIntegrations: getDefaultIntegrations(options), + enableLambdaExtension: sdkSource === 'aws-lambda-layer', ...options, }; - const sdkSource = getSDKSource(); - - if (opts._experiments?.enableLambdaExtension) { + if (opts.enableLambdaExtension) { if (sdkSource === 'aws-lambda-layer') { if (!opts.tunnel) { DEBUG_BUILD && debug.log('Proxying Sentry events through the Sentry Lambda extension'); diff --git a/packages/aws-serverless/test/init.test.ts b/packages/aws-serverless/test/init.test.ts index b4aa7ddc0d2b..453237b8dfa8 100644 --- a/packages/aws-serverless/test/init.test.ts +++ b/packages/aws-serverless/test/init.test.ts @@ -18,14 +18,12 @@ const mockGetSDKSource = vi.mocked(getSDKSource); const mockInitWithoutDefaultIntegrations = vi.mocked(initWithoutDefaultIntegrations); describe('init', () => { - describe('experimental Lambda extension support', () => { + describe('Lambda extension setup', () => { test('should preserve user-provided tunnel option when Lambda extension is enabled', () => { mockGetSDKSource.mockReturnValue('aws-lambda-layer'); const options: AwsServerlessOptions = { tunnel: 'https://custom-tunnel.example.com', - _experiments: { - enableLambdaExtension: true, - }, + enableLambdaExtension: true, }; init(options); @@ -40,9 +38,7 @@ describe('init', () => { test('should set default tunnel when Lambda extension is enabled and SDK source is aws-lambda-layer', () => { mockGetSDKSource.mockReturnValue('aws-lambda-layer'); const options: AwsServerlessOptions = { - _experiments: { - enableLambdaExtension: true, - }, + enableLambdaExtension: true, }; init(options); @@ -57,9 +53,7 @@ describe('init', () => { test('should not set tunnel when Lambda extension is disabled', () => { mockGetSDKSource.mockReturnValue('aws-lambda-layer'); const options: AwsServerlessOptions = { - _experiments: { - enableLambdaExtension: false, - }, + enableLambdaExtension: false, }; init(options); @@ -74,9 +68,7 @@ describe('init', () => { test('should not set tunnel when SDK source is not aws-lambda-layer even with Lambda extension enabled', () => { mockGetSDKSource.mockReturnValue('npm'); const options: AwsServerlessOptions = { - _experiments: { - enableLambdaExtension: true, - }, + enableLambdaExtension: true, }; init(options); @@ -88,12 +80,31 @@ describe('init', () => { ); }); - test('should not set tunnel when no experiments are provided', () => { + test('should default enableLambdaExtension to true when SDK source is aws-lambda-layer', () => { mockGetSDKSource.mockReturnValue('aws-lambda-layer'); const options: AwsServerlessOptions = {}; init(options); + expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith( + expect.objectContaining({ + enableLambdaExtension: true, + tunnel: 'http://localhost:9000/envelope', + }), + ); + }); + + test('should default enableLambdaExtension to false when SDK source is not aws-lambda-layer', () => { + mockGetSDKSource.mockReturnValue('npm'); + const options: AwsServerlessOptions = {}; + + init(options); + + expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith( + expect.objectContaining({ + enableLambdaExtension: false, + }), + ); expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith( expect.not.objectContaining({ tunnel: expect.any(String), From 8d9e6cf937143aa15b24803e3f6c90e21e69d628 Mon Sep 17 00:00:00 2001 From: Martin Sonnberger Date: Thu, 18 Sep 2025 09:14:10 +0200 Subject: [PATCH 2/4] rename option --- packages/aws-serverless/src/init.ts | 8 ++++---- packages/aws-serverless/test/init.test.ts | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/aws-serverless/src/init.ts b/packages/aws-serverless/src/init.ts index 7bdcc1c58e9d..858b58ba12b4 100644 --- a/packages/aws-serverless/src/init.ts +++ b/packages/aws-serverless/src/init.ts @@ -16,9 +16,9 @@ export function getDefaultIntegrations(_options: Options): Integration[] { export interface AwsServerlessOptions extends NodeOptions { /** - * If proxying Sentry events through the Sentry Lambda extension should be enabled. Defaults to `true` when using the AWS Lambda layer. + * If Sentry events should be proxied through the Lambda extension when using the Lambda layer. Defaults to `true`. */ - enableLambdaExtension?: boolean; + useLayerExtension?: boolean; } /** @@ -30,11 +30,11 @@ export function init(options: AwsServerlessOptions = {}): NodeClient | undefined const sdkSource = getSDKSource(); const opts = { defaultIntegrations: getDefaultIntegrations(options), - enableLambdaExtension: sdkSource === 'aws-lambda-layer', + useLayerExtension: sdkSource === 'aws-lambda-layer', ...options, }; - if (opts.enableLambdaExtension) { + if (opts.useLayerExtension) { if (sdkSource === 'aws-lambda-layer') { if (!opts.tunnel) { DEBUG_BUILD && debug.log('Proxying Sentry events through the Sentry Lambda extension'); diff --git a/packages/aws-serverless/test/init.test.ts b/packages/aws-serverless/test/init.test.ts index 453237b8dfa8..4ab5295033f9 100644 --- a/packages/aws-serverless/test/init.test.ts +++ b/packages/aws-serverless/test/init.test.ts @@ -23,7 +23,7 @@ describe('init', () => { mockGetSDKSource.mockReturnValue('aws-lambda-layer'); const options: AwsServerlessOptions = { tunnel: 'https://custom-tunnel.example.com', - enableLambdaExtension: true, + useLayerExtension: true, }; init(options); @@ -38,7 +38,7 @@ describe('init', () => { test('should set default tunnel when Lambda extension is enabled and SDK source is aws-lambda-layer', () => { mockGetSDKSource.mockReturnValue('aws-lambda-layer'); const options: AwsServerlessOptions = { - enableLambdaExtension: true, + useLayerExtension: true, }; init(options); @@ -53,7 +53,7 @@ describe('init', () => { test('should not set tunnel when Lambda extension is disabled', () => { mockGetSDKSource.mockReturnValue('aws-lambda-layer'); const options: AwsServerlessOptions = { - enableLambdaExtension: false, + useLayerExtension: false, }; init(options); @@ -68,7 +68,7 @@ describe('init', () => { test('should not set tunnel when SDK source is not aws-lambda-layer even with Lambda extension enabled', () => { mockGetSDKSource.mockReturnValue('npm'); const options: AwsServerlessOptions = { - enableLambdaExtension: true, + useLayerExtension: true, }; init(options); @@ -80,7 +80,7 @@ describe('init', () => { ); }); - test('should default enableLambdaExtension to true when SDK source is aws-lambda-layer', () => { + test('should default useLayerExtension to true when SDK source is aws-lambda-layer', () => { mockGetSDKSource.mockReturnValue('aws-lambda-layer'); const options: AwsServerlessOptions = {}; @@ -88,13 +88,13 @@ describe('init', () => { expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith( expect.objectContaining({ - enableLambdaExtension: true, + useLayerExtension: true, tunnel: 'http://localhost:9000/envelope', }), ); }); - test('should default enableLambdaExtension to false when SDK source is not aws-lambda-layer', () => { + test('should default useLayerExtension to false when SDK source is not aws-lambda-layer', () => { mockGetSDKSource.mockReturnValue('npm'); const options: AwsServerlessOptions = {}; @@ -102,7 +102,7 @@ describe('init', () => { expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith( expect.objectContaining({ - enableLambdaExtension: false, + useLayerExtension: false, }), ); expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith( From a131d05e0bc2a27054d97ce31d8ba88e23198a41 Mon Sep 17 00:00:00 2001 From: Martin Sonnberger Date: Thu, 18 Sep 2025 14:30:38 +0200 Subject: [PATCH 3/4] wording Co-authored-by: Francesco Gringl-Novy --- packages/aws-serverless/src/init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/aws-serverless/src/init.ts b/packages/aws-serverless/src/init.ts index 858b58ba12b4..a9a039b5925a 100644 --- a/packages/aws-serverless/src/init.ts +++ b/packages/aws-serverless/src/init.ts @@ -16,7 +16,7 @@ export function getDefaultIntegrations(_options: Options): Integration[] { export interface AwsServerlessOptions extends NodeOptions { /** - * If Sentry events should be proxied through the Lambda extension when using the Lambda layer. Defaults to `true`. + * If Sentry events should be proxied through the Lambda extension when using the Lambda layer. Defaults to `true` when using the Lambda layer. */ useLayerExtension?: boolean; } From 9513fa0ba2e19b94a4e293fa3b7c46134eebe710 Mon Sep 17 00:00:00 2001 From: Martin Sonnberger Date: Thu, 18 Sep 2025 15:17:16 +0200 Subject: [PATCH 4/4] only default to true if tunnel isn't set --- packages/aws-serverless/src/init.ts | 2 +- packages/aws-serverless/test/init.test.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/aws-serverless/src/init.ts b/packages/aws-serverless/src/init.ts index a9a039b5925a..6640db8ec5fa 100644 --- a/packages/aws-serverless/src/init.ts +++ b/packages/aws-serverless/src/init.ts @@ -30,7 +30,7 @@ export function init(options: AwsServerlessOptions = {}): NodeClient | undefined const sdkSource = getSDKSource(); const opts = { defaultIntegrations: getDefaultIntegrations(options), - useLayerExtension: sdkSource === 'aws-lambda-layer', + useLayerExtension: sdkSource === 'aws-lambda-layer' && !options.tunnel, ...options, }; diff --git a/packages/aws-serverless/test/init.test.ts b/packages/aws-serverless/test/init.test.ts index 4ab5295033f9..576257e3f3e4 100644 --- a/packages/aws-serverless/test/init.test.ts +++ b/packages/aws-serverless/test/init.test.ts @@ -111,5 +111,21 @@ describe('init', () => { }), ); }); + + test('should default useLayerExtension to false when tunnel is provided even when SDK source is aws-lambda-layer', () => { + mockGetSDKSource.mockReturnValue('aws-lambda-layer'); + const options: AwsServerlessOptions = { + tunnel: 'https://custom-tunnel.example.com', + }; + + init(options); + + expect(mockInitWithoutDefaultIntegrations).toHaveBeenCalledWith( + expect.objectContaining({ + useLayerExtension: false, + tunnel: 'https://custom-tunnel.example.com', + }), + ); + }); }); });