Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@

- "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott

- **feat(aws-serverless): Ship Lambda extension in npm package for container image Lambdas ([#20133](https://github.com/getsentry/sentry-javascript/pull/20133))**

The Sentry Lambda extension is now included in the npm package, enabling container image-based Lambda functions to use it. Copy the extension files into your Docker image and set the `tunnel` option:

```dockerfile
RUN mkdir -p /opt/sentry-extension
COPY node_modules/@sentry/aws-serverless/build/lambda-extension/sentry-extension /opt/extensions/sentry-extension
COPY node_modules/@sentry/aws-serverless/build/lambda-extension/index.mjs /opt/sentry-extension/index.mjs
RUN chmod +x /opt/extensions/sentry-extension /opt/sentry-extension/index.mjs
```

```js
Sentry.init({
dsn: '__DSN__',
tunnel: 'http://localhost:9000/envelope',
});
```

This works with any Sentry SDK (`@sentry/aws-serverless`, `@sentry/sveltekit`, `@sentry/node`, etc.).

- **feat(cloudflare): Support basic WorkerEntrypoint ([#19884](https://github.com/getsentry/sentry-javascript/pull/19884))**

`withSentry` now supports instrumenting classes extending Cloudflare's `WorkerEntrypoint`. This instruments `fetch`, `scheduled`, `queue`, and `tail` handlers.
Expand Down
44 changes: 44 additions & 0 deletions packages/aws-serverless/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,50 @@ export const handler = (event, context, callback) => {
};
```

## Container Image-based Lambda Functions

When using container image-based Lambda functions (e.g., with [Lambda Web Adapter](https://github.com/awslabs/aws-lambda-web-adapter) for frameworks like SvelteKit, Next.js, or Remix), Lambda layers cannot be attached. Instead, you can install the Sentry Lambda extension directly into your Docker image. The extension tunnels Sentry events through a local proxy, improving event delivery reliability during Lambda freezes.

### Setup

1. Install `@sentry/aws-serverless` as a dependency — even if you use a different Sentry SDK in your application (e.g., `@sentry/sveltekit`), this package contains the extension files needed for the Docker image.

2. Copy the extension files from the npm package into your Docker image:

```dockerfile
FROM public.ecr.aws/lambda/nodejs:22

# Copy the Sentry Lambda extension
RUN mkdir -p /opt/sentry-extension
COPY node_modules/@sentry/aws-serverless/build/lambda-extension/sentry-extension /opt/extensions/sentry-extension
COPY node_modules/@sentry/aws-serverless/build/lambda-extension/index.mjs /opt/sentry-extension/index.mjs
RUN chmod +x /opt/extensions/sentry-extension /opt/sentry-extension/index.mjs

# ... rest of your Dockerfile
```

3. Point your Sentry SDK at the extension using the `tunnel` option. The extension always listens on `http://localhost:9000/envelope` — this URL is fixed and must be used exactly as shown:

```js
import * as Sentry from '@sentry/aws-serverless';

Sentry.init({
dsn: '__DSN__',
tunnel: 'http://localhost:9000/envelope',
});
```

This works with any Sentry SDK:

```js
import * as Sentry from '@sentry/sveltekit';

Sentry.init({
dsn: '__DSN__',
tunnel: 'http://localhost:9000/envelope',
});
```

## Integrate Sentry using the Sentry Lambda layer

Another much simpler way to integrate Sentry to your AWS Lambda function is to add the official layer.
Expand Down
23 changes: 19 additions & 4 deletions packages/aws-serverless/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"files": [
"/build/npm",
"/build/import-hook.mjs",
"/build/loader-hook.mjs"
"/build/loader-hook.mjs",
"/build/lambda-extension"
],
"main": "build/npm/cjs/index.js",
"module": "build/npm/esm/index.js",
Expand Down Expand Up @@ -79,8 +80,9 @@
"@vercel/nft": "^1.3.0"
},
"scripts": {
"build": "run-p build:transpile build:types && run-s build:layer",
"build:layer": "rimraf build/aws && rollup -c rollup.lambda-extension.config.mjs && yarn ts-node scripts/buildLambdaLayer.ts",
"build": "run-p build:transpile build:types build:extension && run-s build:layer",
"build:extension": "rollup -c rollup.lambda-extension.config.mjs && yarn ts-node scripts/buildLambdaExtension.ts",
"build:layer": "rimraf build/aws && yarn ts-node scripts/buildLambdaLayer.ts",
"build:dev": "run-p build:transpile build:types",
"build:transpile": "rollup -c rollup.npm.config.mjs",
"build:types": "run-s build:types:core build:types:downlevel",
Expand Down Expand Up @@ -118,13 +120,26 @@
"{projectRoot}/build/npm/cjs"
]
},
"build:extension": {
"inputs": [
"production",
"^production"
],
"dependsOn": [
"^build:transpile"
],
"outputs": [
"{projectRoot}/build/lambda-extension"
]
},
"build:layer": {
"inputs": [
"production",
"^production"
],
"dependsOn": [
"build:transpile"
"build:transpile",
"build:extension"
],
"outputs": [
"{projectRoot}/build/aws"
Expand Down
2 changes: 1 addition & 1 deletion packages/aws-serverless/rollup.lambda-extension.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default [
outputFileBase: 'index.mjs',
packageSpecificConfig: {
output: {
dir: 'build/aws/dist-serverless/sentry-extension',
dir: 'build/lambda-extension',
sourcemap: false,
},
},
Expand Down
16 changes: 16 additions & 0 deletions packages/aws-serverless/scripts/buildLambdaExtension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as fs from 'fs';

// Copy the bash wrapper script into the rollup output directory
// so the npm package ships both the compiled extension and the wrapper.
const targetDir = './build/lambda-extension';
const source = './src/lambda-extension/sentry-extension';
const target = `${targetDir}/sentry-extension`;

fs.mkdirSync(targetDir, { recursive: true });

fs.copyFileSync(source, target);

// The wrapper must be executable because AWS Lambda discovers extensions by
// scanning /opt/extensions/ for executable files. If the file isn't executable,
// Lambda won't register it as an extension.
fs.chmodSync(target, 0o755);
12 changes: 10 additions & 2 deletions packages/aws-serverless/scripts/buildLambdaLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,18 @@ async function buildLambdaLayer(): Promise<void> {

replaceSDKSource();

// Copy the Lambda extension from the shared build output into the layer structure.
// build/lambda-extension/ contains both index.mjs and the sentry-extension wrapper.
// Lambda requires the wrapper to be in /opt/extensions/ for auto-discovery,
// so it gets copied there separately.
fs.cpSync('./build/lambda-extension', './build/aws/dist-serverless/sentry-extension', { recursive: true });
fs.chmodSync('./build/aws/dist-serverless/sentry-extension/index.mjs', 0o755);
fsForceMkdirSync('./build/aws/dist-serverless/extensions');
fs.copyFileSync('./src/lambda-extension/sentry-extension', './build/aws/dist-serverless/extensions/sentry-extension');
fs.copyFileSync(
'./build/aws/dist-serverless/sentry-extension/sentry-extension',
'./build/aws/dist-serverless/extensions/sentry-extension',
);
fs.chmodSync('./build/aws/dist-serverless/extensions/sentry-extension', 0o755);
fs.chmodSync('./build/aws/dist-serverless/sentry-extension/index.mjs', 0o755);

const zipFilename = `sentry-node-serverless-${version}.zip`;
// Only include these directories in the zip file
Expand Down
Loading