-
-
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
+331
−3
Open
feat(server-utils): Port S3, Kinesis, DynamoDB, SecretsManager and StepFunctions aws-sdk extensions #22164
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
c9482aa
Extract shared makeSafeSpanBuilder from graphql/aws-sdk safe helpers
andreiborza bb5e97c
Inline try/catch instead of safe helper abstraction
andreiborza 65535f1
feat(server-utils): Port S3, Kinesis, DynamoDB, SecretsManager and St…
andreiborza 2fbdbfa
Set db op on DynamoDB aws-sdk spans
andreiborza 06a694f
Use unknown for stringified DynamoDB values
andreiborza 6bbeff9
Scope aws-sdk services oxlint disable to max-lines and complexity
andreiborza a3857ff
Disable no-unsafe-member-access for aws-sdk channel integration
andreiborza c669bfe
Keep the safe() span-builder helper instead of inlining try/catch
andreiborza f9f1f88
Bump @sentry/node diagnostics-channel injection size limit to 144 KB
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
186 changes: 186 additions & 0 deletions
186
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,186 @@ | ||
| import type { Span } from '@sentry/core'; | ||
| import { SPAN_KIND } from '@sentry/core'; | ||
| import { DB_NAME, DB_OPERATION, DB_SYSTEM } from '@sentry/conventions/attributes'; | ||
| import { | ||
| ATTR_AWS_DYNAMODB_ATTRIBUTE_DEFINITIONS, | ||
| ATTR_AWS_DYNAMODB_CONSISTENT_READ, | ||
| ATTR_AWS_DYNAMODB_CONSUMED_CAPACITY, | ||
| ATTR_AWS_DYNAMODB_COUNT, | ||
| ATTR_AWS_DYNAMODB_EXCLUSIVE_START_TABLE, | ||
| ATTR_AWS_DYNAMODB_GLOBAL_SECONDARY_INDEX_UPDATES, | ||
| ATTR_AWS_DYNAMODB_GLOBAL_SECONDARY_INDEXES, | ||
| ATTR_AWS_DYNAMODB_INDEX_NAME, | ||
| ATTR_AWS_DYNAMODB_ITEM_COLLECTION_METRICS, | ||
| ATTR_AWS_DYNAMODB_LIMIT, | ||
| ATTR_AWS_DYNAMODB_LOCAL_SECONDARY_INDEXES, | ||
| ATTR_AWS_DYNAMODB_PROJECTION, | ||
| ATTR_AWS_DYNAMODB_PROVISIONED_READ_CAPACITY, | ||
| ATTR_AWS_DYNAMODB_PROVISIONED_WRITE_CAPACITY, | ||
| ATTR_AWS_DYNAMODB_SCAN_FORWARD, | ||
| ATTR_AWS_DYNAMODB_SCANNED_COUNT, | ||
| ATTR_AWS_DYNAMODB_SEGMENT, | ||
| ATTR_AWS_DYNAMODB_SELECT, | ||
| ATTR_AWS_DYNAMODB_TABLE_COUNT, | ||
| ATTR_AWS_DYNAMODB_TABLE_NAMES, | ||
| ATTR_AWS_DYNAMODB_TOTAL_SEGMENTS, | ||
| 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.
|
||
20 changes: 20 additions & 0 deletions
20
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,20 @@ | ||
| import { SPAN_KIND } from '@sentry/core'; | ||
| import { AWS_KINESIS_STREAM_NAME } from '../constants'; | ||
| 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) { | ||
| 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 '../constants'; | ||
| 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 { ATTR_AWS_SECRETSMANAGER_SECRET_ARN } from '../constants'; | ||
| 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); | ||
| } | ||
| } | ||
| } |
25 changes: 25 additions & 0 deletions
25
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,25 @@ | ||
| import { SPAN_KIND } from '@sentry/core'; | ||
| import { ATTR_AWS_STEP_FUNCTIONS_ACTIVITY_ARN, ATTR_AWS_STEP_FUNCTIONS_STATE_MACHINE_ARN } from '../constants'; | ||
| 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.