Skip to content

Commit 4c14d78

Browse files
authored
feat(aws-serverless): Add lambda extension to npm package (#20133)
This PR adds the Lambda Extension as a build output to the npm package. It was previously only available through our Lambda layer but is useful for users that do not use the layer but would still like to use our extension. To use the extension with container image lambdas, copy the extension files to your Docker image and set the `tunnel` option in your application. This requires the installation of `@sentry/aws-serverless`, regardless of which other Sentry SDK is used in your application. ```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', }); ``` Closes: #20114
1 parent 9aaa191 commit 4c14d78

File tree

6 files changed

+110
-7
lines changed

6 files changed

+110
-7
lines changed

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,26 @@
44

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

7+
- **feat(aws-serverless): Ship Lambda extension in npm package for container image Lambdas ([#20133](https://github.com/getsentry/sentry-javascript/pull/20133))**
8+
9+
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:
10+
11+
```dockerfile
12+
RUN mkdir -p /opt/sentry-extension
13+
COPY node_modules/@sentry/aws-serverless/build/lambda-extension/sentry-extension /opt/extensions/sentry-extension
14+
COPY node_modules/@sentry/aws-serverless/build/lambda-extension/index.mjs /opt/sentry-extension/index.mjs
15+
RUN chmod +x /opt/extensions/sentry-extension /opt/sentry-extension/index.mjs
16+
```
17+
18+
```js
19+
Sentry.init({
20+
dsn: '__DSN__',
21+
tunnel: 'http://localhost:9000/envelope',
22+
});
23+
```
24+
25+
This works with any Sentry SDK (`@sentry/aws-serverless`, `@sentry/sveltekit`, `@sentry/node`, etc.).
26+
727
- **feat(cloudflare): Support basic WorkerEntrypoint ([#19884](https://github.com/getsentry/sentry-javascript/pull/19884))**
828

929
`withSentry` now supports instrumenting classes extending Cloudflare's `WorkerEntrypoint`. This instruments `fetch`, `scheduled`, `queue`, and `tail` handlers.

packages/aws-serverless/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,50 @@ export const handler = (event, context, callback) => {
7373
};
7474
```
7575

76+
## Container Image-based Lambda Functions
77+
78+
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.
79+
80+
### Setup
81+
82+
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.
83+
84+
2. Copy the extension files from the npm package into your Docker image:
85+
86+
```dockerfile
87+
FROM public.ecr.aws/lambda/nodejs:22
88+
89+
# Copy the Sentry Lambda extension
90+
RUN mkdir -p /opt/sentry-extension
91+
COPY node_modules/@sentry/aws-serverless/build/lambda-extension/sentry-extension /opt/extensions/sentry-extension
92+
COPY node_modules/@sentry/aws-serverless/build/lambda-extension/index.mjs /opt/sentry-extension/index.mjs
93+
RUN chmod +x /opt/extensions/sentry-extension /opt/sentry-extension/index.mjs
94+
95+
# ... rest of your Dockerfile
96+
```
97+
98+
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:
99+
100+
```js
101+
import * as Sentry from '@sentry/aws-serverless';
102+
103+
Sentry.init({
104+
dsn: '__DSN__',
105+
tunnel: 'http://localhost:9000/envelope',
106+
});
107+
```
108+
109+
This works with any Sentry SDK:
110+
111+
```js
112+
import * as Sentry from '@sentry/sveltekit';
113+
114+
Sentry.init({
115+
dsn: '__DSN__',
116+
tunnel: 'http://localhost:9000/envelope',
117+
});
118+
```
119+
76120
## Integrate Sentry using the Sentry Lambda layer
77121

78122
Another much simpler way to integrate Sentry to your AWS Lambda function is to add the official layer.

packages/aws-serverless/package.json

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@
1212
"files": [
1313
"/build/npm",
1414
"/build/import-hook.mjs",
15-
"/build/loader-hook.mjs"
15+
"/build/loader-hook.mjs",
16+
"/build/lambda-extension"
1617
],
1718
"main": "build/npm/cjs/index.js",
1819
"module": "build/npm/esm/index.js",
@@ -79,8 +80,9 @@
7980
"@vercel/nft": "^1.3.0"
8081
},
8182
"scripts": {
82-
"build": "run-p build:transpile build:types && run-s build:layer",
83-
"build:layer": "rimraf build/aws && rollup -c rollup.lambda-extension.config.mjs && yarn ts-node scripts/buildLambdaLayer.ts",
83+
"build": "run-p build:transpile build:types build:extension && run-s build:layer",
84+
"build:extension": "rollup -c rollup.lambda-extension.config.mjs && yarn ts-node scripts/buildLambdaExtension.ts",
85+
"build:layer": "rimraf build/aws && yarn ts-node scripts/buildLambdaLayer.ts",
8486
"build:dev": "run-p build:transpile build:types",
8587
"build:transpile": "rollup -c rollup.npm.config.mjs",
8688
"build:types": "run-s build:types:core build:types:downlevel",
@@ -118,13 +120,26 @@
118120
"{projectRoot}/build/npm/cjs"
119121
]
120122
},
123+
"build:extension": {
124+
"inputs": [
125+
"production",
126+
"^production"
127+
],
128+
"dependsOn": [
129+
"^build:transpile"
130+
],
131+
"outputs": [
132+
"{projectRoot}/build/lambda-extension"
133+
]
134+
},
121135
"build:layer": {
122136
"inputs": [
123137
"production",
124138
"^production"
125139
],
126140
"dependsOn": [
127-
"build:transpile"
141+
"build:transpile",
142+
"build:extension"
128143
],
129144
"outputs": [
130145
"{projectRoot}/build/aws"

packages/aws-serverless/rollup.lambda-extension.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export default [
77
outputFileBase: 'index.mjs',
88
packageSpecificConfig: {
99
output: {
10-
dir: 'build/aws/dist-serverless/sentry-extension',
10+
dir: 'build/lambda-extension',
1111
sourcemap: false,
1212
},
1313
},
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import * as fs from 'fs';
2+
3+
// Copy the bash wrapper script into the rollup output directory
4+
// so the npm package ships both the compiled extension and the wrapper.
5+
const targetDir = './build/lambda-extension';
6+
const source = './src/lambda-extension/sentry-extension';
7+
const target = `${targetDir}/sentry-extension`;
8+
9+
fs.mkdirSync(targetDir, { recursive: true });
10+
11+
fs.copyFileSync(source, target);
12+
13+
// The wrapper must be executable because AWS Lambda discovers extensions by
14+
// scanning /opt/extensions/ for executable files. If the file isn't executable,
15+
// Lambda won't register it as an extension.
16+
fs.chmodSync(target, 0o755);

packages/aws-serverless/scripts/buildLambdaLayer.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,18 @@ async function buildLambdaLayer(): Promise<void> {
5454

5555
replaceSDKSource();
5656

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

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

0 commit comments

Comments
 (0)