diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration-streamed/instrument.mjs b/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration-streamed/instrument.mjs
deleted file mode 100644
index abfa58bbff9f..000000000000
--- a/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration-streamed/instrument.mjs
+++ /dev/null
@@ -1,10 +0,0 @@
-import * as Sentry from '@sentry/aws-serverless';
-import { loggingTransport } from '@sentry-internal/node-integration-tests';
-
-Sentry.init({
- dsn: 'https://public@dsn.ingest.sentry.io/1337',
- release: '1.0',
- tracesSampleRate: 1.0,
- transport: loggingTransport,
- traceLifecycle: 'stream',
-});
diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration-streamed/scenario.mjs b/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration-streamed/scenario.mjs
deleted file mode 100644
index 624a10e9523b..000000000000
--- a/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration-streamed/scenario.mjs
+++ /dev/null
@@ -1,183 +0,0 @@
-import * as Sentry from '@sentry/aws-serverless';
-import { createHash } from 'crypto';
-import { DynamoDBClient, PutItemCommand, QueryCommand } from '@aws-sdk/client-dynamodb';
-import { KinesisClient, PutRecordCommand } from '@aws-sdk/client-kinesis';
-import { InvokeCommand, LambdaClient } from '@aws-sdk/client-lambda';
-import { S3 } from '@aws-sdk/client-s3';
-import { GetSecretValueCommand, SecretsManagerClient } from '@aws-sdk/client-secrets-manager';
-import { SFNClient, StartExecutionCommand } from '@aws-sdk/client-sfn';
-import { PublishCommand, SNSClient } from '@aws-sdk/client-sns';
-import { ReceiveMessageCommand, SendMessageCommand, SQSClient } from '@aws-sdk/client-sqs';
-// The Kinesis client defaults to an HTTP/2 request handler, which `nock` cannot intercept.
-// Force the HTTP/1 handler so the request is mocked instead of hitting real AWS.
-import { NodeHttpHandler } from '@smithy/node-http-handler';
-import nock from 'nock';
-
-nock.disableNetConnect();
-
-const region = 'us-east-1';
-const credentials = { accessKeyId: 'aws-test-key', secretAccessKey: 'aws-test-secret' };
-
-async function s3() {
- const s3Client = new S3({ region, credentials, maxAttempts: 1 });
- const host = `https://ot-demo-test.s3.${region}.amazonaws.com`;
-
- nock(host).put('/aws-ot-s3-test-object.txt?x-id=PutObject').reply(200, 'test');
- await s3Client.putObject({ Bucket: 'ot-demo-test', Key: 'aws-ot-s3-test-object.txt' });
-
- nock(host).get('/aws-ot-s3-test-object.txt?x-id=GetObject').reply(200, 'contents');
- const getResult = await s3Client.getObject({ Bucket: 'ot-demo-test', Key: 'aws-ot-s3-test-object.txt' });
- await getResult.Body?.transformToString();
-
- nock(host)
- .get('/missing-object.txt?x-id=GetObject')
- .reply(
- 404,
- 'NoSuchKeyThe specified key does not exist.',
- { 'content-type': 'application/xml' },
- );
- try {
- await s3Client.getObject({ Bucket: 'ot-demo-test', Key: 'missing-object.txt' });
- } catch {
- // expected
- }
-}
-
-async function dynamodb() {
- const client = new DynamoDBClient({ region, credentials, maxAttempts: 1 });
-
- nock(`https://dynamodb.${region}.amazonaws.com`)
- .post('/')
- .reply(200, JSON.stringify({}), { 'content-type': 'application/x-amz-json-1.0' });
- await client.send(new PutItemCommand({ TableName: 'my-table', Item: { id: { S: 'some-id' } } }));
-
- nock(`https://dynamodb.${region}.amazonaws.com`)
- .post('/')
- .reply(200, JSON.stringify({ Items: [{ id: { S: 'some-id' } }], Count: 1, ScannedCount: 1 }), {
- 'content-type': 'application/x-amz-json-1.0',
- });
- await client.send(
- new QueryCommand({
- TableName: 'my-table',
- KeyConditionExpression: 'id = :id',
- ExpressionAttributeValues: { ':id': { S: 'some-id' } },
- }),
- );
-}
-
-async function sqs() {
- const client = new SQSClient({ region, credentials, maxAttempts: 1 });
- const queueUrl = `https://sqs.${region}.amazonaws.com/123456789012/my-queue`;
- const messageBody = 'Hello from Sentry';
- const md5 = createHash('md5').update(messageBody).digest('hex');
-
- nock(`https://sqs.${region}.amazonaws.com`)
- .post('/')
- .reply(200, JSON.stringify({ MessageId: 'message-id-1', MD5OfMessageBody: md5 }), {
- 'content-type': 'application/x-amz-json-1.0',
- });
- await client.send(new SendMessageCommand({ QueueUrl: queueUrl, MessageBody: messageBody }));
-
- nock(`https://sqs.${region}.amazonaws.com`)
- .post('/')
- .reply(
- 200,
- JSON.stringify({
- Messages: [{ MessageId: 'message-id-2', Body: messageBody, MD5OfBody: md5, ReceiptHandle: 'handle' }],
- }),
- { 'content-type': 'application/x-amz-json-1.0' },
- );
- await client.send(new ReceiveMessageCommand({ QueueUrl: queueUrl }));
-}
-
-async function sns() {
- const client = new SNSClient({ region, credentials, maxAttempts: 1 });
-
- nock(`https://sns.${region}.amazonaws.com`)
- .post('/')
- .reply(
- 200,
- 'message-id-1request-id-1',
- { 'content-type': 'text/xml' },
- );
- await client.send(new PublishCommand({ TopicArn: 'arn:aws:sns:us-east-1:123456789012:my-topic', Message: 'Hello' }));
-
- // Publish to a platform endpoint, whose ARN ends in a per-device id.
- nock(`https://sns.${region}.amazonaws.com`)
- .post('/')
- .reply(
- 200,
- 'message-id-2request-id-2',
- { 'content-type': 'text/xml' },
- );
- await client.send(
- new PublishCommand({
- TargetArn: 'arn:aws:sns:us-east-1:123456789012:endpoint/GCM/myapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3',
- Message: 'Hello',
- }),
- );
-}
-
-async function lambda() {
- const client = new LambdaClient({ region, credentials, maxAttempts: 1 });
-
- nock(`https://lambda.${region}.amazonaws.com`)
- .post('/2015-03-31/functions/my-function/invocations')
- .reply(200, JSON.stringify({ result: 'ok' }), {
- 'content-type': 'application/json',
- 'x-amzn-requestid': 'request-id-1',
- });
- await client.send(new InvokeCommand({ FunctionName: 'my-function' }));
-}
-
-async function kinesis() {
- const client = new KinesisClient({ region, credentials, maxAttempts: 1, requestHandler: new NodeHttpHandler() });
-
- nock(`https://kinesis.${region}.amazonaws.com`)
- .post('/')
- .reply(200, JSON.stringify({ SequenceNumber: '1', ShardId: 'shardId-000000000000' }), {
- 'content-type': 'application/x-amz-json-1.1',
- });
- await client.send(
- new PutRecordCommand({ StreamName: 'my-stream', Data: Buffer.from('data'), PartitionKey: 'partition-key' }),
- );
-}
-
-async function secretsmanager() {
- const client = new SecretsManagerClient({ region, credentials, maxAttempts: 1 });
- const secretArn = 'arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret-abc';
-
- nock(`https://secretsmanager.${region}.amazonaws.com`)
- .post('/')
- .reply(200, JSON.stringify({ ARN: secretArn, Name: 'my-secret', SecretString: 'secret-value' }), {
- 'content-type': 'application/x-amz-json-1.1',
- });
- await client.send(new GetSecretValueCommand({ SecretId: secretArn }));
-}
-
-async function stepfunctions() {
- const client = new SFNClient({ region, credentials, maxAttempts: 1 });
- const stateMachineArn = 'arn:aws:states:us-east-1:123456789012:stateMachine:my-state-machine';
-
- nock(`https://states.${region}.amazonaws.com`)
- .post('/')
- .reply(200, JSON.stringify({ executionArn: `${stateMachineArn}:execution-1`, startDate: 1 }), {
- 'content-type': 'application/x-amz-json-1.0',
- });
- await client.send(new StartExecutionCommand({ stateMachineArn, input: '{}' }));
-}
-
-async function run() {
- await Sentry.startSpan({ name: 'Test Service Span' }, async () => {
- await s3();
- await dynamodb();
- await sqs();
- await sns();
- await lambda();
- await kinesis();
- await secretsmanager();
- await stepfunctions();
- });
-}
-
-run();
diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration-streamed/test.ts b/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration-streamed/test.ts
deleted file mode 100644
index b4974f86ef2e..000000000000
--- a/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration-streamed/test.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-import type { SerializedStreamedSpanContainer } from '@sentry/core';
-import { afterAll, describe, expect } from 'vitest';
-import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner';
-
-// See the non-streamed `aws-integration` suite: only the origin differs between the OTel and
-// orchestrion diagnostics-channel runs.
-const ORIGIN = 'auto.aws.aws_sdk';
-
-// The aws-sdk instrumentation creates spans by patching the underlying smithy middleware stack. The
-// patch target differs between aws-sdk versions, so we run the exact same assertions against both:
-// - the current aws-sdk (default, resolved from the workspace) which routes through `@smithy/core` >= 3.24.0
-// - aws-sdk 3.1041.0 pinned together with the pre-`@smithy/core` stack (`@smithy/middleware-stack`)
-const LEGACY_AWS_SDK_DEPENDENCIES = {
- '@aws-sdk/client-dynamodb': '3.1041.0',
- '@aws-sdk/client-kinesis': '3.1041.0',
- '@aws-sdk/client-lambda': '3.1041.0',
- '@aws-sdk/client-s3': '3.1041.0',
- '@aws-sdk/client-secrets-manager': '3.1041.0',
- '@aws-sdk/client-sfn': '3.1041.0',
- '@aws-sdk/client-sns': '3.1041.0',
- '@aws-sdk/client-sqs': '3.1041.0',
- // Pin the smithy layer to the pre-`@smithy/core` versions, otherwise the 3.1041.0 clients still
- // resolve `@smithy/smithy-client` >= 4.13 (which routes through `@smithy/core` >= 3.24.0).
- '@smithy/smithy-client': '4.12.13',
- '@smithy/core': '3.23.17',
- '@smithy/middleware-stack': '4.2.14',
- '@smithy/node-http-handler': '4.7.8',
-};
-
-/**
- * Asserts the transaction contains one span per instrumented aws-sdk service. Each service is checked
- * with its own `expect` so a failure points at the specific service rather than the whole transaction.
- */
-function assertAwsServiceSpans(spanCcontainer: SerializedStreamedSpanContainer): void {
- const spans = spanCcontainer.items;
-
- const expectSpan = (
- label: string,
- expected: Record,
- find?: (item: SerializedStreamedSpanContainer['items'][number]) => boolean,
- ): void => {
- const matches = spans.filter(item => item.name === expected.name);
- const span = find ? matches.find(find) : matches[0];
- expect(span, label).toMatchObject(expected);
- };
-
- const segmentSpan = spans.find(item => item.is_segment);
-
- expect(segmentSpan?.name).toBe('Test Service Span');
-
- // S3 - PutObject (success)
- expectSpan('S3.PutObject', {
- name: 'S3.PutObject',
- status: 'ok',
- attributes: expect.objectContaining({
- 'sentry.origin': { value: ORIGIN, type: 'string' },
- 'sentry.op': { value: 'rpc', type: 'string' },
- 'rpc.system': { value: 'aws-api', type: 'string' },
- 'rpc.method': { value: 'PutObject', type: 'string' },
- 'rpc.service': { value: 'S3', type: 'string' },
- 'cloud.region': { value: 'us-east-1', type: 'string' },
- 'aws.s3.bucket': { value: 'ot-demo-test', type: 'string' },
- 'sentry.kind': { value: 'client', type: 'string' },
- }),
- });
-
- // S3 - GetObject (success)
- expectSpan(
- 'S3.GetObject (success)',
- {
- name: 'S3.GetObject',
- status: 'ok',
- attributes: expect.objectContaining({
- 'rpc.method': { value: 'GetObject', type: 'string' },
- 'rpc.service': { value: 'S3', type: 'string' },
- 'aws.s3.bucket': { value: 'ot-demo-test', type: 'string' },
- }),
- },
- // Two spans share the name `S3.GetObject`; disambiguate by HTTP status code.
- item => item.attributes['http.response.status_code']?.value === 200,
- );
-
- // S3 - GetObject (errored, missing key)
- expectSpan(
- 'S3.GetObject (error)',
- {
- name: 'S3.GetObject',
- status: 'error',
- attributes: expect.objectContaining({
- 'rpc.method': { value: 'GetObject', type: 'string' },
- 'rpc.service': { value: 'S3', type: 'string' },
- }),
- },
- item => item.attributes['http.response.status_code']?.value === 404,
- );
-
- // DynamoDB - PutItem
- expectSpan('DynamoDB.PutItem', {
- name: 'DynamoDB.PutItem',
- attributes: expect.objectContaining({
- 'rpc.method': { value: 'PutItem', type: 'string' },
- 'rpc.service': { value: 'DynamoDB', type: 'string' },
- 'db.system.name': { value: 'dynamodb', type: 'string' },
- 'db.namespace': { value: 'my-table', type: 'string' },
- 'db.operation.name': { value: 'PutItem', type: 'string' },
- 'aws.dynamodb.table_names': { value: ['my-table'], type: 'array' },
- }),
- });
-
- // DynamoDB - Query
- expectSpan('DynamoDB.Query', {
- name: 'DynamoDB.Query',
- attributes: expect.objectContaining({
- 'rpc.method': { value: 'Query', type: 'string' },
- 'db.operation.name': { value: 'Query', type: 'string' },
- 'aws.dynamodb.count': { value: 1, type: 'integer' },
- 'aws.dynamodb.scanned_count': { value: 1, type: 'integer' },
- }),
- });
-
- // SQS - SendMessage (producer)
- expectSpan('SQS SendMessage', {
- name: 'send my-queue',
- attributes: expect.objectContaining({
- 'sentry.op': { value: 'queue.publish', type: 'string' },
- 'rpc.method': { value: 'SendMessage', type: 'string' },
- 'rpc.service': { value: 'SQS', type: 'string' },
- 'messaging.system': { value: 'aws_sqs', type: 'string' },
- 'messaging.destination.name': { value: 'my-queue', type: 'string' },
- 'url.full': { value: 'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue', type: 'string' },
- 'messaging.message.id': { value: 'message-id-1', type: 'string' },
- 'sentry.kind': { value: 'producer', type: 'string' },
- }),
- });
-
- // SQS - ReceiveMessage (consumer)
- expectSpan('SQS ReceiveMessage', {
- name: 'receive my-queue',
- attributes: expect.objectContaining({
- 'sentry.op': { value: 'queue.receive', type: 'string' },
- 'rpc.method': { value: 'ReceiveMessage', type: 'string' },
- 'messaging.system': { value: 'aws_sqs', type: 'string' },
- 'messaging.operation.type': { value: 'receive', type: 'string' },
- 'messaging.batch.message_count': { value: 1, type: 'integer' },
- 'sentry.kind': { value: 'consumer', type: 'string' },
- }),
- });
-
- // SNS - Publish (producer)
- expectSpan('SNS Publish', {
- name: 'send my-topic',
- attributes: expect.objectContaining({
- 'rpc.method': { value: 'Publish', type: 'string' },
- 'rpc.service': { value: 'SNS', type: 'string' },
- 'messaging.system': { value: 'aws.sns', type: 'string' },
- 'sentry.op': { value: 'queue.publish', type: 'string' },
- 'messaging.destination': { value: 'my-topic', type: 'string' },
- 'aws.sns.topic.arn': { value: 'arn:aws:sns:us-east-1:123456789012:my-topic', type: 'string' },
- 'sentry.kind': { value: 'producer', type: 'string' },
- }),
- });
-
- // The ARN suffix is a per-device id, so the streamed name drops the destination.
- expectSpan('SNS Publish (platform endpoint)', {
- name: 'send',
- attributes: expect.objectContaining({
- 'rpc.method': { value: 'Publish', type: 'string' },
- 'rpc.service': { value: 'SNS', type: 'string' },
- 'sentry.op': { value: 'queue.publish', type: 'string' },
- 'messaging.destination': { value: 'endpoint/GCM/myapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3', type: 'string' },
- 'messaging.destination.name': {
- value: 'arn:aws:sns:us-east-1:123456789012:endpoint/GCM/myapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3',
- type: 'string',
- },
- }),
- });
-
- // Lambda - Invoke
- expectSpan('Lambda Invoke', {
- name: 'my-function Invoke',
- attributes: expect.objectContaining({
- 'rpc.method': { value: 'Invoke', type: 'string' },
- 'rpc.service': { value: 'Lambda', type: 'string' },
- 'faas.invoked_name': { value: 'my-function', type: 'string' },
- 'faas.invoked_provider': { value: 'aws', type: 'string' },
- 'faas.invocation_id': { value: 'request-id-1', type: 'string' },
- }),
- });
-
- // Kinesis - PutRecord
- expectSpan('Kinesis.PutRecord', {
- name: 'Kinesis.PutRecord',
- status: 'ok',
- attributes: expect.objectContaining({
- 'rpc.method': { value: 'PutRecord', type: 'string' },
- 'rpc.service': { value: 'Kinesis', type: 'string' },
- 'aws.kinesis.stream.name': { value: 'my-stream', type: 'string' },
- }),
- });
-
- // SecretsManager - GetSecretValue
- expectSpan('SecretsManager.GetSecretValue', {
- name: 'SecretsManager.GetSecretValue',
- attributes: expect.objectContaining({
- 'rpc.method': { value: 'GetSecretValue', type: 'string' },
- 'rpc.service': { value: 'SecretsManager', type: 'string' },
- 'aws.secretsmanager.secret.arn': {
- value: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret-abc',
- type: 'string',
- },
- }),
- });
-
- // StepFunctions - StartExecution
- expectSpan('StepFunctions.StartExecution', {
- name: 'SFN.StartExecution',
- attributes: expect.objectContaining({
- 'rpc.method': { value: 'StartExecution', type: 'string' },
- 'rpc.service': { value: 'SFN', type: 'string' },
- 'aws.step_functions.state_machine.arn': {
- value: 'arn:aws:states:us-east-1:123456789012:stateMachine:my-state-machine',
- type: 'string',
- },
- }),
- });
-}
-
-describe('awsIntegration (streamed)', () => {
- afterAll(() => {
- cleanupChildProcesses();
- });
-
- describe.each([
- { label: 'latest', additionalDependencies: undefined },
- { label: 'v3.1041.0 (@smithy/middleware-stack)', additionalDependencies: LEGACY_AWS_SDK_DEPENDENCIES },
- ])('aws-sdk $label', ({ additionalDependencies }) => {
- createEsmAndCjsTests(
- __dirname,
- 'scenario.mjs',
- 'instrument.mjs',
- (createTestRunner, test) => {
- test('auto-instruments aws-sdk service operations', { timeout: 90_000 }, async () => {
- await createTestRunner().ignore('event').expect({ span: assertAwsServiceSpans }).start().completed();
- });
- },
- { additionalDependencies },
- );
- });
-});
diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration/instrument.mjs b/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration/instrument.mjs
index d6a9efde7bae..fe1c5c47983f 100644
--- a/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration/instrument.mjs
+++ b/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration/instrument.mjs
@@ -2,7 +2,6 @@ import * as Sentry from '@sentry/aws-serverless';
import { loggingTransport } from '@sentry-internal/node-integration-tests';
Sentry.init({
- traceLifecycle: 'static',
dsn: 'https://public@dsn.ingest.sentry.io/1337',
release: '1.0',
tracesSampleRate: 1.0,
diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration/test.ts b/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration/test.ts
index cac71f20ad6e..e12bf1ecaff2 100644
--- a/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration/test.ts
+++ b/dev-packages/node-integration-tests/suites/aws-serverless/aws-integration/test.ts
@@ -1,4 +1,4 @@
-import type { TransactionEvent } from '@sentry/core';
+import type { SerializedStreamedSpanContainer } from '@sentry/core';
import { afterAll, describe, expect } from 'vitest';
import { cleanupChildProcesses, createEsmAndCjsTests } from '../../../utils/runner';
@@ -29,189 +29,216 @@ const LEGACY_AWS_SDK_DEPENDENCIES = {
};
/**
- * Asserts the transaction contains one span per instrumented aws-sdk service. Each service is checked
- * with its own `expect` so a failure points at the specific service rather than the whole transaction.
+ * Asserts the collected spans include one span per instrumented aws-sdk service. Each service is checked
+ * with its own `expect` so a failure points at the specific service rather than the whole trace.
*/
-function assertAwsServiceSpans(transaction: TransactionEvent): void {
- const spans = transaction.spans ?? [];
-
- const expectSpan = (label: string, expected: Record): void => {
- expect(spans, `expected an aws-sdk span for "${label}"`).toContainEqual(expect.objectContaining(expected));
+function assertAwsServiceSpans(spans: SerializedStreamedSpanContainer['items']): void {
+ const expectSpan = (
+ label: string,
+ expected: Record,
+ find?: (item: SerializedStreamedSpanContainer['items'][number]) => boolean,
+ ): void => {
+ const matches = spans.filter(item => item.name === expected.name);
+ const span = find ? matches.find(find) : matches[0];
+ expect(span, label).toMatchObject(expected);
};
- expect(transaction.transaction).toBe('Test Transaction');
+ const segmentSpan = spans.find(item => item.is_segment);
+
+ expect(segmentSpan?.name).toBe('Test Transaction');
// S3 - PutObject (success)
expectSpan('S3.PutObject', {
- description: 'S3.PutObject',
- op: 'rpc',
- origin: ORIGIN,
+ name: 'S3.PutObject',
status: 'ok',
- data: expect.objectContaining({
- 'sentry.origin': ORIGIN,
- 'sentry.op': 'rpc',
- 'rpc.system': 'aws-api',
- 'rpc.method': 'PutObject',
- 'rpc.service': 'S3',
- 'cloud.region': 'us-east-1',
- 'aws.s3.bucket': 'ot-demo-test',
- 'sentry.kind': 'client',
+ attributes: expect.objectContaining({
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'sentry.op': { value: 'rpc', type: 'string' },
+ 'rpc.system': { value: 'aws-api', type: 'string' },
+ 'rpc.method': { value: 'PutObject', type: 'string' },
+ 'rpc.service': { value: 'S3', type: 'string' },
+ 'cloud.region': { value: 'us-east-1', type: 'string' },
+ 'aws.s3.bucket': { value: 'ot-demo-test', type: 'string' },
+ 'sentry.kind': { value: 'client', type: 'string' },
}),
});
// S3 - GetObject (success)
- expectSpan('S3.GetObject (success)', {
- description: 'S3.GetObject',
- op: 'rpc',
- origin: ORIGIN,
- status: 'ok',
- data: expect.objectContaining({ 'rpc.method': 'GetObject', 'rpc.service': 'S3', 'aws.s3.bucket': 'ot-demo-test' }),
- });
+ expectSpan(
+ 'S3.GetObject (success)',
+ {
+ name: 'S3.GetObject',
+ status: 'ok',
+ attributes: expect.objectContaining({
+ 'sentry.op': { value: 'rpc', type: 'string' },
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'rpc.method': { value: 'GetObject', type: 'string' },
+ 'rpc.service': { value: 'S3', type: 'string' },
+ 'aws.s3.bucket': { value: 'ot-demo-test', type: 'string' },
+ }),
+ },
+ // Two spans share the name `S3.GetObject`; disambiguate by HTTP status code.
+ item => item.attributes['http.response.status_code']?.value === 200,
+ );
// S3 - GetObject (errored, missing key)
- expectSpan('S3.GetObject (error)', {
- description: 'S3.GetObject',
- op: 'rpc',
- origin: ORIGIN,
- status: 'internal_error',
- data: expect.objectContaining({ 'rpc.method': 'GetObject', 'rpc.service': 'S3' }),
- });
+ expectSpan(
+ 'S3.GetObject (error)',
+ {
+ name: 'S3.GetObject',
+ status: 'error',
+ attributes: expect.objectContaining({
+ 'sentry.op': { value: 'rpc', type: 'string' },
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'rpc.method': { value: 'GetObject', type: 'string' },
+ 'rpc.service': { value: 'S3', type: 'string' },
+ }),
+ },
+ item => item.attributes['http.response.status_code']?.value === 404,
+ );
// DynamoDB - PutItem
expectSpan('DynamoDB.PutItem', {
- description: 'DynamoDB.PutItem',
- op: 'db',
- origin: ORIGIN,
- data: expect.objectContaining({
- 'sentry.op': 'db',
- 'rpc.method': 'PutItem',
- 'rpc.service': 'DynamoDB',
- 'db.system.name': 'dynamodb',
- 'db.namespace': 'my-table',
- 'db.operation.name': 'PutItem',
- 'aws.dynamodb.table_names': ['my-table'],
+ name: 'DynamoDB.PutItem',
+ attributes: expect.objectContaining({
+ 'sentry.op': { value: 'db', type: 'string' },
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'rpc.method': { value: 'PutItem', type: 'string' },
+ 'rpc.service': { value: 'DynamoDB', type: 'string' },
+ 'db.system.name': { value: 'dynamodb', type: 'string' },
+ 'db.namespace': { value: 'my-table', type: 'string' },
+ 'db.operation.name': { value: 'PutItem', type: 'string' },
+ 'aws.dynamodb.table_names': { value: ['my-table'], type: 'array' },
}),
});
// DynamoDB - Query
expectSpan('DynamoDB.Query', {
- description: 'DynamoDB.Query',
- op: 'db',
- origin: ORIGIN,
- data: expect.objectContaining({
- 'rpc.method': 'Query',
- 'db.operation.name': 'Query',
- 'aws.dynamodb.count': 1,
- 'aws.dynamodb.scanned_count': 1,
+ name: 'DynamoDB.Query',
+ attributes: expect.objectContaining({
+ 'sentry.op': { value: 'db', type: 'string' },
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'rpc.method': { value: 'Query', type: 'string' },
+ 'db.operation.name': { value: 'Query', type: 'string' },
+ 'aws.dynamodb.count': { value: 1, type: 'integer' },
+ 'aws.dynamodb.scanned_count': { value: 1, type: 'integer' },
}),
});
// SQS - SendMessage (producer)
expectSpan('SQS SendMessage', {
- description: 'my-queue send',
- op: 'queue.publish',
- origin: ORIGIN,
- data: expect.objectContaining({
- 'rpc.method': 'SendMessage',
- 'rpc.service': 'SQS',
- 'messaging.system': 'aws_sqs',
- 'messaging.destination.name': 'my-queue',
- 'url.full': 'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue',
- 'messaging.message.id': 'message-id-1',
- 'sentry.kind': 'producer',
+ name: 'send my-queue',
+ attributes: expect.objectContaining({
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'sentry.op': { value: 'queue.publish', type: 'string' },
+ 'rpc.method': { value: 'SendMessage', type: 'string' },
+ 'rpc.service': { value: 'SQS', type: 'string' },
+ 'messaging.system': { value: 'aws_sqs', type: 'string' },
+ 'messaging.destination.name': { value: 'my-queue', type: 'string' },
+ 'url.full': { value: 'https://sqs.us-east-1.amazonaws.com/123456789012/my-queue', type: 'string' },
+ 'messaging.message.id': { value: 'message-id-1', type: 'string' },
+ 'sentry.kind': { value: 'producer', type: 'string' },
}),
});
// SQS - ReceiveMessage (consumer)
expectSpan('SQS ReceiveMessage', {
- description: 'my-queue receive',
- op: 'queue.receive',
- origin: ORIGIN,
- data: expect.objectContaining({
- 'rpc.method': 'ReceiveMessage',
- 'messaging.system': 'aws_sqs',
- 'messaging.operation.type': 'receive',
- 'messaging.batch.message_count': 1,
- 'sentry.kind': 'consumer',
+ name: 'receive my-queue',
+ attributes: expect.objectContaining({
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'sentry.op': { value: 'queue.receive', type: 'string' },
+ 'rpc.method': { value: 'ReceiveMessage', type: 'string' },
+ 'messaging.system': { value: 'aws_sqs', type: 'string' },
+ 'messaging.operation.type': { value: 'receive', type: 'string' },
+ 'messaging.batch.message_count': { value: 1, type: 'integer' },
+ 'sentry.kind': { value: 'consumer', type: 'string' },
}),
});
// SNS - Publish (producer)
expectSpan('SNS Publish', {
- description: 'my-topic send',
- op: 'queue.publish',
- origin: ORIGIN,
- data: expect.objectContaining({
- 'rpc.method': 'Publish',
- 'rpc.service': 'SNS',
- 'messaging.system': 'aws.sns',
- 'messaging.destination': 'my-topic',
- 'aws.sns.topic.arn': 'arn:aws:sns:us-east-1:123456789012:my-topic',
- 'sentry.kind': 'producer',
+ name: 'send my-topic',
+ attributes: expect.objectContaining({
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'rpc.method': { value: 'Publish', type: 'string' },
+ 'rpc.service': { value: 'SNS', type: 'string' },
+ 'messaging.system': { value: 'aws.sns', type: 'string' },
+ 'sentry.op': { value: 'queue.publish', type: 'string' },
+ 'messaging.destination': { value: 'my-topic', type: 'string' },
+ 'aws.sns.topic.arn': { value: 'arn:aws:sns:us-east-1:123456789012:my-topic', type: 'string' },
+ 'sentry.kind': { value: 'producer', type: 'string' },
}),
});
- // Without span streaming the name keeps the raw ARN suffix, including the per-device id.
+ // The ARN suffix is a per-device id, so the streamed name drops the destination.
expectSpan('SNS Publish (platform endpoint)', {
- description: 'endpoint/GCM/myapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3 send',
- op: 'queue.publish',
- data: expect.objectContaining({
- 'rpc.method': 'Publish',
- 'rpc.service': 'SNS',
- 'messaging.destination': 'endpoint/GCM/myapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3',
- 'messaging.destination.name':
- 'arn:aws:sns:us-east-1:123456789012:endpoint/GCM/myapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3',
+ name: 'send',
+ attributes: expect.objectContaining({
+ 'rpc.method': { value: 'Publish', type: 'string' },
+ 'rpc.service': { value: 'SNS', type: 'string' },
+ 'sentry.op': { value: 'queue.publish', type: 'string' },
+ 'messaging.destination': { value: 'endpoint/GCM/myapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3', type: 'string' },
+ 'messaging.destination.name': {
+ value: 'arn:aws:sns:us-east-1:123456789012:endpoint/GCM/myapp/5e3e9847-3183-3f18-a7e8-671c3a57d4b3',
+ type: 'string',
+ },
}),
});
// Lambda - Invoke
expectSpan('Lambda Invoke', {
- description: 'my-function Invoke',
- op: 'rpc',
- origin: ORIGIN,
- data: expect.objectContaining({
- 'rpc.method': 'Invoke',
- 'rpc.service': 'Lambda',
- 'faas.invoked_name': 'my-function',
- 'faas.invoked_provider': 'aws',
- 'faas.invocation_id': 'request-id-1',
+ name: 'my-function Invoke',
+ attributes: expect.objectContaining({
+ 'sentry.op': { value: 'rpc', type: 'string' },
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'rpc.method': { value: 'Invoke', type: 'string' },
+ 'rpc.service': { value: 'Lambda', type: 'string' },
+ 'faas.invoked_name': { value: 'my-function', type: 'string' },
+ 'faas.invoked_provider': { value: 'aws', type: 'string' },
+ 'faas.invocation_id': { value: 'request-id-1', type: 'string' },
}),
});
// Kinesis - PutRecord
expectSpan('Kinesis.PutRecord', {
- description: 'Kinesis.PutRecord',
- op: 'rpc',
- origin: ORIGIN,
+ name: 'Kinesis.PutRecord',
status: 'ok',
- data: expect.objectContaining({
- 'rpc.method': 'PutRecord',
- 'rpc.service': 'Kinesis',
- 'aws.kinesis.stream.name': 'my-stream',
+ attributes: expect.objectContaining({
+ 'sentry.op': { value: 'rpc', type: 'string' },
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'rpc.method': { value: 'PutRecord', type: 'string' },
+ 'rpc.service': { value: 'Kinesis', type: 'string' },
+ 'aws.kinesis.stream.name': { value: 'my-stream', type: 'string' },
}),
});
// SecretsManager - GetSecretValue
expectSpan('SecretsManager.GetSecretValue', {
- description: 'SecretsManager.GetSecretValue',
- op: 'rpc',
- origin: ORIGIN,
- data: expect.objectContaining({
- 'rpc.method': 'GetSecretValue',
- 'rpc.service': 'SecretsManager',
- 'aws.secretsmanager.secret.arn': 'arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret-abc',
+ name: 'SecretsManager.GetSecretValue',
+ attributes: expect.objectContaining({
+ 'sentry.op': { value: 'rpc', type: 'string' },
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'rpc.method': { value: 'GetSecretValue', type: 'string' },
+ 'rpc.service': { value: 'SecretsManager', type: 'string' },
+ 'aws.secretsmanager.secret.arn': {
+ value: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:my-secret-abc',
+ type: 'string',
+ },
}),
});
// StepFunctions - StartExecution
expectSpan('StepFunctions.StartExecution', {
- description: 'SFN.StartExecution',
- op: 'rpc',
- origin: ORIGIN,
- data: expect.objectContaining({
- 'rpc.method': 'StartExecution',
- 'rpc.service': 'SFN',
- 'aws.step_functions.state_machine.arn': 'arn:aws:states:us-east-1:123456789012:stateMachine:my-state-machine',
+ name: 'SFN.StartExecution',
+ attributes: expect.objectContaining({
+ 'sentry.op': { value: 'rpc', type: 'string' },
+ 'sentry.origin': { value: ORIGIN, type: 'string' },
+ 'rpc.method': { value: 'StartExecution', type: 'string' },
+ 'rpc.service': { value: 'SFN', type: 'string' },
+ 'aws.step_functions.state_machine.arn': {
+ value: 'arn:aws:states:us-east-1:123456789012:stateMachine:my-state-machine',
+ type: 'string',
+ },
}),
});
}
@@ -231,7 +258,18 @@ describe('awsIntegration', () => {
'instrument.mjs',
(createTestRunner, test) => {
test('auto-instruments aws-sdk service operations', { timeout: 90_000 }, async () => {
- await createTestRunner().ignore('event').expect({ transaction: assertAwsServiceSpans }).start().completed();
+ const spans: SerializedStreamedSpanContainer['items'] = [];
+ await createTestRunner()
+ .ignore('event')
+ .unordered()
+ .expect({
+ span: container => {
+ spans.push(...container.items);
+ assertAwsServiceSpans(spans);
+ },
+ })
+ .start()
+ .completed();
});
},
{ additionalDependencies },