-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
feat(server-utils): Port S3, Kinesis, DynamoDB, SecretsManager and StepFunctions aws-sdk extensions #22164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Open
feat(server-utils): Port S3, Kinesis, DynamoDB, SecretsManager and StepFunctions aws-sdk extensions #22164
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
3f185a5
Extract shared makeSafeSpanBuilder from graphql/aws-sdk safe helpers
andreiborza 04d7db4
Inline try/catch instead of safe helper abstraction
andreiborza b332b87
feat(server-utils): Port S3, Kinesis, DynamoDB, SecretsManager and St…
andreiborza c1e5898
Set db op on DynamoDB aws-sdk spans
andreiborza 3d27179
Use unknown for stringified DynamoDB values
andreiborza 413f3af
Scope aws-sdk services oxlint disable to max-lines and complexity
andreiborza 291dfbe
Disable no-unsafe-member-access for aws-sdk channel integration
andreiborza fab7051
Keep the safe() span-builder helper instead of inlining try/catch
andreiborza a73914b
Bump @sentry/node diagnostics-channel injection size limit to 144 KB
andreiborza 8a0ff74
Import S3/Kinesis/DynamoDB/SecretsManager/StepFunctions attributes fr…
andreiborza File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 12 additions & 1 deletion
13
...ages/server-utils/src/integrations/tracing-channel/aws-sdk/services/ServicesExtensions.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
188 changes: 188 additions & 0 deletions
188
packages/server-utils/src/integrations/tracing-channel/aws-sdk/services/dynamodb.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,188 @@ | ||
| import type { Span } from '@sentry/core'; | ||
| import { SPAN_KIND } from '@sentry/core'; | ||
| import { | ||
| AWS_DYNAMODB_ATTRIBUTE_DEFINITIONS as ATTR_AWS_DYNAMODB_ATTRIBUTE_DEFINITIONS, | ||
| AWS_DYNAMODB_CONSISTENT_READ as ATTR_AWS_DYNAMODB_CONSISTENT_READ, | ||
| AWS_DYNAMODB_CONSUMED_CAPACITY as ATTR_AWS_DYNAMODB_CONSUMED_CAPACITY, | ||
| AWS_DYNAMODB_COUNT as ATTR_AWS_DYNAMODB_COUNT, | ||
| AWS_DYNAMODB_EXCLUSIVE_START_TABLE as ATTR_AWS_DYNAMODB_EXCLUSIVE_START_TABLE, | ||
| AWS_DYNAMODB_GLOBAL_SECONDARY_INDEX_UPDATES as ATTR_AWS_DYNAMODB_GLOBAL_SECONDARY_INDEX_UPDATES, | ||
| AWS_DYNAMODB_GLOBAL_SECONDARY_INDEXES as ATTR_AWS_DYNAMODB_GLOBAL_SECONDARY_INDEXES, | ||
| AWS_DYNAMODB_INDEX_NAME as ATTR_AWS_DYNAMODB_INDEX_NAME, | ||
| AWS_DYNAMODB_ITEM_COLLECTION_METRICS as ATTR_AWS_DYNAMODB_ITEM_COLLECTION_METRICS, | ||
| AWS_DYNAMODB_LIMIT as ATTR_AWS_DYNAMODB_LIMIT, | ||
| AWS_DYNAMODB_LOCAL_SECONDARY_INDEXES as ATTR_AWS_DYNAMODB_LOCAL_SECONDARY_INDEXES, | ||
| AWS_DYNAMODB_PROJECTION as ATTR_AWS_DYNAMODB_PROJECTION, | ||
| AWS_DYNAMODB_PROVISIONED_READ_CAPACITY as ATTR_AWS_DYNAMODB_PROVISIONED_READ_CAPACITY, | ||
| AWS_DYNAMODB_PROVISIONED_WRITE_CAPACITY as ATTR_AWS_DYNAMODB_PROVISIONED_WRITE_CAPACITY, | ||
| AWS_DYNAMODB_SCAN_FORWARD as ATTR_AWS_DYNAMODB_SCAN_FORWARD, | ||
| AWS_DYNAMODB_SCANNED_COUNT as ATTR_AWS_DYNAMODB_SCANNED_COUNT, | ||
| AWS_DYNAMODB_SEGMENT as ATTR_AWS_DYNAMODB_SEGMENT, | ||
| AWS_DYNAMODB_SELECT as ATTR_AWS_DYNAMODB_SELECT, | ||
| AWS_DYNAMODB_TABLE_COUNT as ATTR_AWS_DYNAMODB_TABLE_COUNT, | ||
| AWS_DYNAMODB_TABLE_NAMES as ATTR_AWS_DYNAMODB_TABLE_NAMES, | ||
| AWS_DYNAMODB_TOTAL_SEGMENTS as ATTR_AWS_DYNAMODB_TOTAL_SEGMENTS, | ||
| DB_NAME, | ||
| DB_OPERATION, | ||
| DB_SYSTEM, | ||
| } from '@sentry/conventions/attributes'; | ||
| import { DB_SYSTEM_VALUE_DYNAMODB } from '../constants'; | ||
| import type { NormalizedRequest, NormalizedResponse } from '../types'; | ||
| import type { RequestMetadata, ServiceExtension } from './ServiceExtension'; | ||
|
|
||
| function toArray<T>(values: T | T[]): T[] { | ||
| return Array.isArray(values) ? values : [values]; | ||
| } | ||
|
|
||
| export class DynamodbServiceExtension implements ServiceExtension { | ||
| public requestPreSpanHook(normalizedRequest: NormalizedRequest): RequestMetadata { | ||
| const operation = normalizedRequest.commandName; | ||
| const tableName = normalizedRequest.commandInput?.TableName; | ||
|
|
||
| const spanAttributes: Record<string, unknown> = {}; | ||
|
|
||
| /* oxlint-disable typescript/no-deprecated -- old-semconv db.* attributes, matched to the OTel aws-sdk integration */ | ||
| spanAttributes[DB_SYSTEM] = DB_SYSTEM_VALUE_DYNAMODB; | ||
| spanAttributes[DB_NAME] = tableName; | ||
| spanAttributes[DB_OPERATION] = operation; | ||
| /* oxlint-enable typescript/no-deprecated */ | ||
|
|
||
| // `RequestItems` is undefined when no table names are returned; its keys are the table names. | ||
| if (normalizedRequest.commandInput?.TableName) { | ||
| // Necessary for commands with only 1 table name (e.g. CreateTable). Attribute is `TableName`, not keys of `RequestItems`. | ||
| spanAttributes[ATTR_AWS_DYNAMODB_TABLE_NAMES] = [normalizedRequest.commandInput.TableName]; | ||
| } else if (normalizedRequest.commandInput?.RequestItems) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_TABLE_NAMES] = Object.keys(normalizedRequest.commandInput.RequestItems); | ||
| } | ||
|
|
||
| if (operation === 'CreateTable' || operation === 'UpdateTable') { | ||
| // only check for ProvisionedThroughput since ReadCapacityUnits and WriteCapacityUnits are required attributes | ||
| if (normalizedRequest.commandInput?.ProvisionedThroughput) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_PROVISIONED_READ_CAPACITY] = | ||
| normalizedRequest.commandInput.ProvisionedThroughput.ReadCapacityUnits; | ||
| spanAttributes[ATTR_AWS_DYNAMODB_PROVISIONED_WRITE_CAPACITY] = | ||
| normalizedRequest.commandInput.ProvisionedThroughput.WriteCapacityUnits; | ||
| } | ||
| } | ||
|
|
||
| if (operation === 'GetItem' || operation === 'Scan' || operation === 'Query') { | ||
| if (normalizedRequest.commandInput?.ConsistentRead) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_CONSISTENT_READ] = normalizedRequest.commandInput.ConsistentRead; | ||
| } | ||
| } | ||
|
|
||
| if (operation === 'Query' || operation === 'Scan') { | ||
| if (normalizedRequest.commandInput?.ProjectionExpression) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_PROJECTION] = normalizedRequest.commandInput.ProjectionExpression; | ||
| } | ||
| } | ||
|
|
||
| if (operation === 'CreateTable') { | ||
| if (normalizedRequest.commandInput?.GlobalSecondaryIndexes) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_GLOBAL_SECONDARY_INDEXES] = toArray( | ||
| normalizedRequest.commandInput.GlobalSecondaryIndexes, | ||
| ).map((x: unknown) => JSON.stringify(x)); | ||
| } | ||
|
|
||
| if (normalizedRequest.commandInput?.LocalSecondaryIndexes) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_LOCAL_SECONDARY_INDEXES] = toArray( | ||
| normalizedRequest.commandInput.LocalSecondaryIndexes, | ||
| ).map((x: unknown) => JSON.stringify(x)); | ||
| } | ||
| } | ||
|
|
||
| if (operation === 'ListTables' || operation === 'Query' || operation === 'Scan') { | ||
| if (normalizedRequest.commandInput?.Limit) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_LIMIT] = normalizedRequest.commandInput.Limit; | ||
| } | ||
| } | ||
|
|
||
| if (operation === 'ListTables') { | ||
| if (normalizedRequest.commandInput?.ExclusiveStartTableName) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_EXCLUSIVE_START_TABLE] = | ||
| normalizedRequest.commandInput.ExclusiveStartTableName; | ||
| } | ||
| } | ||
|
|
||
| if (operation === 'Query') { | ||
| if (normalizedRequest.commandInput?.ScanIndexForward) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_SCAN_FORWARD] = normalizedRequest.commandInput.ScanIndexForward; | ||
| } | ||
|
|
||
| if (normalizedRequest.commandInput?.IndexName) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_INDEX_NAME] = normalizedRequest.commandInput.IndexName; | ||
| } | ||
|
|
||
| if (normalizedRequest.commandInput?.Select) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_SELECT] = normalizedRequest.commandInput.Select; | ||
| } | ||
| } | ||
|
|
||
| if (operation === 'Scan') { | ||
| if (normalizedRequest.commandInput?.Segment) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_SEGMENT] = normalizedRequest.commandInput?.Segment; | ||
| } | ||
|
|
||
| if (normalizedRequest.commandInput?.TotalSegments) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_TOTAL_SEGMENTS] = normalizedRequest.commandInput?.TotalSegments; | ||
| } | ||
|
|
||
| if (normalizedRequest.commandInput?.IndexName) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_INDEX_NAME] = normalizedRequest.commandInput.IndexName; | ||
| } | ||
|
|
||
| if (normalizedRequest.commandInput?.Select) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_SELECT] = normalizedRequest.commandInput.Select; | ||
| } | ||
| } | ||
|
|
||
| if (operation === 'UpdateTable') { | ||
| if (normalizedRequest.commandInput?.AttributeDefinitions) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_ATTRIBUTE_DEFINITIONS] = toArray( | ||
| normalizedRequest.commandInput.AttributeDefinitions, | ||
| ).map((x: unknown) => JSON.stringify(x)); | ||
| } | ||
|
|
||
| if (normalizedRequest.commandInput?.GlobalSecondaryIndexUpdates) { | ||
| spanAttributes[ATTR_AWS_DYNAMODB_GLOBAL_SECONDARY_INDEX_UPDATES] = toArray( | ||
| normalizedRequest.commandInput.GlobalSecondaryIndexUpdates, | ||
| ).map((x: unknown) => JSON.stringify(x)); | ||
| } | ||
| } | ||
|
|
||
| return { | ||
| spanAttributes, | ||
| spanKind: SPAN_KIND.CLIENT, | ||
| // Matches what the exporter infers from `db.system` for the OTel DynamoDB spans. | ||
| spanOp: 'db', | ||
| }; | ||
| } | ||
|
|
||
| public responseHook(response: NormalizedResponse, span: Span): void { | ||
| if (response.data?.ConsumedCapacity) { | ||
| span.setAttribute( | ||
| ATTR_AWS_DYNAMODB_CONSUMED_CAPACITY, | ||
| toArray(response.data.ConsumedCapacity).map((x: unknown) => JSON.stringify(x)), | ||
| ); | ||
| } | ||
|
|
||
| if (response.data?.ItemCollectionMetrics) { | ||
| span.setAttribute( | ||
| ATTR_AWS_DYNAMODB_ITEM_COLLECTION_METRICS, | ||
| toArray(response.data.ItemCollectionMetrics).map((x: unknown) => JSON.stringify(x)), | ||
| ); | ||
| } | ||
|
sentry[bot] marked this conversation as resolved.
|
||
|
|
||
| if (response.data?.TableNames) { | ||
| span.setAttribute(ATTR_AWS_DYNAMODB_TABLE_COUNT, response.data?.TableNames.length); | ||
| } | ||
|
|
||
| if (response.data?.Count) { | ||
| span.setAttribute(ATTR_AWS_DYNAMODB_COUNT, response.data?.Count); | ||
| } | ||
|
|
||
| if (response.data?.ScannedCount) { | ||
| span.setAttribute(ATTR_AWS_DYNAMODB_SCANNED_COUNT, response.data?.ScannedCount); | ||
|
andreiborza marked this conversation as resolved.
|
||
| } | ||
|
andreiborza marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
andreiborza marked this conversation as resolved.
|
||
21 changes: 21 additions & 0 deletions
21
packages/server-utils/src/integrations/tracing-channel/aws-sdk/services/kinesis.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import { SPAN_KIND } from '@sentry/core'; | ||
| import { _AWS_KINESIS_STREAM_NAME as AWS_KINESIS_STREAM_NAME } from '@sentry/conventions/attributes'; | ||
| import type { NormalizedRequest } from '../types'; | ||
| import type { RequestMetadata, ServiceExtension } from './ServiceExtension'; | ||
|
|
||
| export class KinesisServiceExtension implements ServiceExtension { | ||
| public requestPreSpanHook(request: NormalizedRequest): RequestMetadata { | ||
| const streamName = request.commandInput?.StreamName; | ||
| const spanAttributes: Record<string, unknown> = {}; | ||
|
|
||
| if (streamName) { | ||
| // oxlint-disable-next-line typescript/no-deprecated -- old-semconv aws.kinesis.stream.name, matched to the OTel aws-sdk integration | ||
| spanAttributes[AWS_KINESIS_STREAM_NAME] = streamName; | ||
| } | ||
|
|
||
| return { | ||
| spanAttributes, | ||
| spanKind: SPAN_KIND.CLIENT, | ||
| }; | ||
| } | ||
| } |
20 changes: 20 additions & 0 deletions
20
packages/server-utils/src/integrations/tracing-channel/aws-sdk/services/s3.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| import { SPAN_KIND } from '@sentry/core'; | ||
| import { AWS_S3_BUCKET } from '@sentry/conventions/attributes'; | ||
| import type { NormalizedRequest } from '../types'; | ||
| import type { RequestMetadata, ServiceExtension } from './ServiceExtension'; | ||
|
|
||
| export class S3ServiceExtension implements ServiceExtension { | ||
| public requestPreSpanHook(request: NormalizedRequest): RequestMetadata { | ||
| const bucketName = request.commandInput?.Bucket; | ||
| const spanAttributes: Record<string, unknown> = {}; | ||
|
|
||
| if (bucketName) { | ||
| spanAttributes[AWS_S3_BUCKET] = bucketName; | ||
| } | ||
|
|
||
| return { | ||
| spanAttributes, | ||
| spanKind: SPAN_KIND.CLIENT, | ||
| }; | ||
| } | ||
| } |
27 changes: 27 additions & 0 deletions
27
packages/server-utils/src/integrations/tracing-channel/aws-sdk/services/secretsmanager.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import type { Span } from '@sentry/core'; | ||
| import { SPAN_KIND } from '@sentry/core'; | ||
| import { AWS_SECRETSMANAGER_SECRET_ARN as ATTR_AWS_SECRETSMANAGER_SECRET_ARN } from '@sentry/conventions/attributes'; | ||
| import type { NormalizedRequest, NormalizedResponse } from '../types'; | ||
| import type { RequestMetadata, ServiceExtension } from './ServiceExtension'; | ||
|
|
||
| export class SecretsManagerServiceExtension implements ServiceExtension { | ||
| public requestPreSpanHook(request: NormalizedRequest): RequestMetadata { | ||
| const secretId = request.commandInput?.SecretId; | ||
| const spanAttributes: Record<string, unknown> = {}; | ||
| if (typeof secretId === 'string' && secretId.startsWith('arn:aws:secretsmanager:')) { | ||
| spanAttributes[ATTR_AWS_SECRETSMANAGER_SECRET_ARN] = secretId; | ||
| } | ||
|
|
||
| return { | ||
| spanAttributes, | ||
| spanKind: SPAN_KIND.CLIENT, | ||
| }; | ||
| } | ||
|
|
||
| public responseHook(response: NormalizedResponse, span: Span): void { | ||
| const secretArn = response.data?.ARN; | ||
| if (secretArn) { | ||
| span.setAttribute(ATTR_AWS_SECRETSMANAGER_SECRET_ARN, secretArn); | ||
| } | ||
| } | ||
| } |
28 changes: 28 additions & 0 deletions
28
packages/server-utils/src/integrations/tracing-channel/aws-sdk/services/stepfunctions.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import { SPAN_KIND } from '@sentry/core'; | ||
| import { | ||
| AWS_STEP_FUNCTIONS_ACTIVITY_ARN as ATTR_AWS_STEP_FUNCTIONS_ACTIVITY_ARN, | ||
| AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN as ATTR_AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN, | ||
| } from '@sentry/conventions/attributes'; | ||
| import type { NormalizedRequest } from '../types'; | ||
| import type { RequestMetadata, ServiceExtension } from './ServiceExtension'; | ||
|
|
||
| export class StepFunctionsServiceExtension implements ServiceExtension { | ||
| public requestPreSpanHook(request: NormalizedRequest): RequestMetadata { | ||
| const stateMachineArn = request.commandInput?.stateMachineArn; | ||
| const activityArn = request.commandInput?.activityArn; | ||
| const spanAttributes: Record<string, unknown> = {}; | ||
|
|
||
| if (stateMachineArn) { | ||
| spanAttributes[ATTR_AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN] = stateMachineArn; | ||
| } | ||
|
|
||
| if (activityArn) { | ||
| spanAttributes[ATTR_AWS_STEP_FUNCTIONS_ACTIVITY_ARN] = activityArn; | ||
| } | ||
|
|
||
| return { | ||
| spanAttributes, | ||
| spanKind: SPAN_KIND.CLIENT, | ||
| }; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.