Skip to content

Commit 144a5f0

Browse files
authored
feat(aws): Add OTEL based integrations (#11548)
Adds ESM support to `@sentry/aws-serverless` and adds relevant OpenTelemetry integrations.
1 parent e4ea972 commit 144a5f0

File tree

17 files changed

+1282
-408
lines changed

17 files changed

+1282
-408
lines changed

MIGRATION.md

+3-5
Original file line numberDiff line numberDiff line change
@@ -177,12 +177,10 @@ The `Transaction` integration has been removed from `@sentry/integrations`. Ther
177177
#### @sentry/serverless
178178

179179
`@sentry/serverless` has been removed and will no longer be published. The serverless package has been split into two
180-
different packages, `@sentry/aws-serverless` and `@sentry/google-cloud-serverless`. These new packages have smaller
181-
bundle size than `@sentry/serverless`, which should improve your serverless cold-start times.
180+
different packages, `@sentry/aws-serverless` and `@sentry/google-cloud-serverless`.
182181

183-
`@sentry/aws-serverless` and `@sentry/google-cloud-serverless` has also been changed to only emit CJS builds. The ESM
184-
build for the `@sentry/serverless` package was always broken and we decided to remove it entirely. ESM support will be
185-
re-added at a later date.
182+
The `@sentry/google-cloud-serverless` package has also been changed to only emit CJS builds because it can only
183+
instrument CJS. ESM support will be re-added at a later date.
186184

187185
In `@sentry/serverless` you had to use a namespace import to initialize the SDK. This has been removed so that you can
188186
directly import from the SDK instead.

dev-packages/node-integration-tests/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
"mysql2": "^3.7.1",
5151
"nock": "^13.1.0",
5252
"pg": "^8.7.3",
53+
"@aws-sdk/client-s3": "^3.552.0",
5354
"proxy": "^2.1.1",
5455
"reflect-metadata": "0.2.1",
5556
"rxjs": "^7.8.1",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const { loggingTransport } = require('@sentry-internal/node-integration-tests');
2+
const Sentry = require('@sentry/aws-serverless');
3+
4+
Sentry.init({
5+
dsn: 'https://public@dsn.ingest.sentry.io/1337',
6+
tracesSampleRate: 1.0,
7+
debug: true,
8+
transport: loggingTransport,
9+
});
10+
11+
const { S3 } = require('@aws-sdk/client-s3');
12+
const nock = require('nock');
13+
14+
async function run() {
15+
const bucketName = 'aws-test-bucket';
16+
const keyName = 'aws-test-object.txt';
17+
18+
nock(`https://${bucketName}.s3.amazonaws.com`).get(`/${keyName}`).reply(200, 'contents');
19+
nock(`https://${bucketName}.s3.amazonaws.com`).put(`/${keyName}`).reply(200, 'contents');
20+
21+
await Sentry.startSpan({ name: 'Test Transaction' }, async () => {
22+
const region = 'us-east-1';
23+
const s3Client = new S3({ region });
24+
nock(`https://ot-demo-test.s3.${region}.amazonaws.com/`)
25+
.put('/aws-ot-s3-test-object.txt?x-id=PutObject')
26+
.reply(200, 'test');
27+
28+
const params = {
29+
Bucket: 'ot-demo-test',
30+
Key: 'aws-ot-s3-test-object.txt',
31+
};
32+
await s3Client.putObject(params);
33+
});
34+
}
35+
36+
run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { cleanupChildProcesses, createRunner } from '../../../../utils/runner';
2+
3+
const EXPECTED_TRANSCATION = {
4+
transaction: 'Test Transaction',
5+
spans: expect.arrayContaining([
6+
expect.objectContaining({
7+
description: 'S3.PutObject',
8+
op: 'rpc',
9+
origin: 'auto.otel.aws',
10+
data: {
11+
'sentry.origin': 'auto.otel.aws',
12+
'sentry.op': 'rpc',
13+
'rpc.system': 'aws-api',
14+
'rpc.method': 'PutObject',
15+
'rpc.service': 'S3',
16+
'aws.region': 'us-east-1',
17+
'otel.kind': 'CLIENT',
18+
},
19+
}),
20+
]),
21+
};
22+
23+
describe('awsIntegration', () => {
24+
afterAll(() => {
25+
cleanupChildProcesses();
26+
});
27+
28+
test('should auto-instrument aws-sdk v2 package.', done => {
29+
createRunner(__dirname, 'scenario.js').expect({ transaction: EXPECTED_TRANSCATION }).start(done);
30+
});
31+
});

docs/v8-node.md

+2-6
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,18 @@ working on this during the v8 alpha/beta cycle.
8181
### Using Custom OpenTelemetry Instrumentation
8282

8383
While we include some vetted OpenTelemetry instrumentation out of the box, you can also add your own instrumentation on
84-
top of that. You can do that by installing an instrumentation package (as well as `@opentelemetry/instrumentation`) and
85-
setting it up like this:
84+
top of that. You can do that by installing an instrumentation package and setting it up like this:
8685

8786
```js
8887
const Sentry = require('@sentry/node');
8988
const { GenericPoolInstrumentation } = require('@opentelemetry/instrumentation-generic-pool');
90-
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
9189

9290
Sentry.init({
9391
dsn: '__DSN__',
9492
});
9593

9694
// Afterwards, you can add additional instrumentation:
97-
registerInsturmentations({
98-
instrumentations: [new GenericPoolInstrumentation()],
99-
});
95+
Sentry.addOpenTelemetryInstrumentation(new GenericPoolInstrumentation());
10096
```
10197

10298
### Using a Custom OpenTelemetry Setup

packages/aws-serverless/package.json

+8-7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@
2020
"exports": {
2121
"./package.json": "./package.json",
2222
".": {
23+
"import": {
24+
"types": "./build/npm/types/index.d.ts",
25+
"default": "./build/npm/esm/index.js"
26+
},
2327
"require": {
2428
"types": "./build/npm/types/index.d.ts",
2529
"default": "./build/npm/cjs/index.js"
@@ -47,19 +51,16 @@
4751
"access": "public"
4852
},
4953
"dependencies": {
54+
"@opentelemetry/instrumentation-aws-lambda": "0.40.0",
55+
"@opentelemetry/instrumentation-aws-sdk": "0.40.0",
5056
"@sentry/core": "8.0.0-beta.3",
5157
"@sentry/node": "8.0.0-beta.3",
5258
"@sentry/types": "8.0.0-beta.3",
5359
"@sentry/utils": "8.0.0-beta.3",
54-
"@types/aws-lambda": "^8.10.62",
55-
"@types/express": "^4.17.14"
60+
"@types/aws-lambda": "^8.10.62"
5661
},
5762
"devDependencies": {
58-
"@types/node": "^14.18.0",
59-
"aws-sdk": "^2.765.0",
60-
"find-up": "^5.0.0",
61-
"nock": "^13.0.4",
62-
"npm-packlist": "^2.1.4"
63+
"@types/node": "^14.18.0"
6364
},
6465
"scripts": {
6566
"build": "run-p build:transpile build:types build:bundle",

packages/aws-serverless/rollup.npm.config.mjs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ export default [
1010
// packages with bundles have a different build directory structure
1111
hasBundles: true,
1212
}),
13-
{ emitEsm: false },
1413
),
1514
...makeOtelLoaders('./build', 'sentry-node'),
1615
];

packages/aws-serverless/src/awslambda-auto.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { init, tryPatchHandler } from './awslambda';
1+
import { init, tryPatchHandler } from './sdk';
22

33
const lambdaTaskRoot = process.env.LAMBDA_TASK_ROOT;
44
if (lambdaTaskRoot) {

packages/aws-serverless/src/awsservices.ts

-115
This file was deleted.

packages/aws-serverless/src/index.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ export {
108108
sessionTimingIntegration,
109109
} from '@sentry/core';
110110

111-
export { getDefaultIntegrations, init, tryPatchHandler, wrapHandler } from './awslambda';
112-
export type { WrapperOptions } from './awslambda';
111+
export { awsIntegration } from './integration/aws';
112+
export { awsLambdaIntegration } from './integration/awslambda';
113113

114-
export { awsServicesIntegration } from './awsservices';
114+
export { getDefaultIntegrations, init, tryPatchHandler, wrapHandler } from './sdk';
115+
export type { WrapperOptions } from './sdk';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { AwsInstrumentation } from '@opentelemetry/instrumentation-aws-sdk';
2+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration } from '@sentry/core';
3+
import { addOpenTelemetryInstrumentation } from '@sentry/node';
4+
import type { IntegrationFn } from '@sentry/types';
5+
6+
const _awsIntegration = (() => {
7+
return {
8+
name: 'Aws',
9+
setupOnce() {
10+
addOpenTelemetryInstrumentation(
11+
new AwsInstrumentation({
12+
preRequestHook(span) {
13+
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.otel.aws');
14+
},
15+
}),
16+
);
17+
},
18+
};
19+
}) satisfies IntegrationFn;
20+
21+
/**
22+
* Instrumentation for aws-sdk package
23+
*/
24+
export const awsIntegration = defineIntegration(_awsIntegration);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { AwsLambdaInstrumentation } from '@opentelemetry/instrumentation-aws-lambda';
2+
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, defineIntegration } from '@sentry/core';
3+
import { addOpenTelemetryInstrumentation } from '@sentry/node';
4+
import type { IntegrationFn } from '@sentry/types';
5+
6+
const _awsLambdaIntegration = (() => {
7+
return {
8+
name: 'AwsLambda',
9+
setupOnce() {
10+
addOpenTelemetryInstrumentation(
11+
new AwsLambdaInstrumentation({
12+
requestHook(span) {
13+
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.otel.aws-lambda');
14+
},
15+
}),
16+
);
17+
},
18+
};
19+
}) satisfies IntegrationFn;
20+
21+
/**
22+
* Instrumentation for aws-sdk package
23+
*/
24+
export const awsLambdaIntegration = defineIntegration(_awsLambdaIntegration);

packages/aws-serverless/src/awslambda.ts renamed to packages/aws-serverless/src/sdk.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ import type { Context, Handler } from 'aws-lambda';
2121
import { performance } from 'perf_hooks';
2222

2323
import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core';
24-
import { awsServicesIntegration } from './awsservices';
2524

2625
import { DEBUG_BUILD } from './debug-build';
26+
import { awsIntegration } from './integration/aws';
27+
import { awsLambdaIntegration } from './integration/awslambda';
2728
import { markEventUnhandled } from './utils';
2829

2930
const { isPromise } = types;
@@ -61,7 +62,7 @@ export interface WrapperOptions {
6162

6263
/** Get the default integrations for the AWSLambda SDK. */
6364
export function getDefaultIntegrations(options: Options): Integration[] {
64-
return [...getNodeDefaultIntegrations(options), awsServicesIntegration({ optional: true })];
65+
return [...getNodeDefaultIntegrations(options), awsIntegration(), awsLambdaIntegration()];
6566
}
6667

6768
/**

0 commit comments

Comments
 (0)