From 36653f469f8c8c1ca1bfd272172ed028afed397e Mon Sep 17 00:00:00 2001 From: Martin Sonnberger Date: Tue, 28 Jul 2026 15:34:17 +0200 Subject: [PATCH] feat(aws-serverless)!: Use GenAI span ops for Bedrock inference Co-Authored-By: GPT-5.6 Codex --- .../suites/aws-serverless/bedrock/test.ts | 2 ++ .../integration/aws/vendored/services/bedrock-runtime.ts | 6 ++++++ .../src/integrations/tracing-channel/aws-sdk/index.ts | 7 ++++--- .../tracing-channel/aws-sdk/services/bedrock-runtime.ts | 6 ++++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts index d04c2cf1d7fa..013ad6f77c59 100644 --- a/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts +++ b/dev-packages/node-integration-tests/suites/aws-serverless/bedrock/test.ts @@ -19,6 +19,7 @@ function assertBedrockSpans(transaction: TransactionEvent): void { expect(spans, 'expected a Bedrock Converse span').toContainEqual( expect.objectContaining({ description: `chat ${MODEL_ID}`, + op: 'chat', origin: ORIGIN, status: 'ok', data: expect.objectContaining({ @@ -39,6 +40,7 @@ function assertBedrockSpans(transaction: TransactionEvent): void { // InvokeModel (non-streaming, anthropic.claude request/response body) expect(spans, 'expected a Bedrock InvokeModel span').toContainEqual( expect.objectContaining({ + op: 'generate_content', origin: ORIGIN, status: 'ok', data: expect.objectContaining({ diff --git a/packages/aws-serverless/src/integration/aws/vendored/services/bedrock-runtime.ts b/packages/aws-serverless/src/integration/aws/vendored/services/bedrock-runtime.ts index 8eb956a66832..4c5f4ad161b3 100644 --- a/packages/aws-serverless/src/integration/aws/vendored/services/bedrock-runtime.ts +++ b/packages/aws-serverless/src/integration/aws/vendored/services/bedrock-runtime.ts @@ -19,7 +19,9 @@ import { GEN_AI_SYSTEM, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, + SENTRY_OP, } from '@sentry/conventions/attributes'; +import { GEN_AI_CHAT_SPAN_OP } from '@sentry/conventions/op'; import { ATTR_GEN_AI_REQUEST_STOP_SEQUENCES, GEN_AI_OPERATION_NAME_VALUE_CHAT, @@ -41,6 +43,8 @@ interface ConverseStreamOutput { [key: string]: any; } +const GEN_AI_GENERATE_CONTENT_SPAN_OP = 'generate_content'; + export class BedrockRuntimeServiceExtension implements ServiceExtension { private _diag: DiagLogger = diag; @@ -76,6 +80,7 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { // oxlint-disable-next-line typescript/no-deprecated [GEN_AI_SYSTEM]: GEN_AI_SYSTEM_VALUE_AWS_BEDROCK, [GEN_AI_OPERATION_NAME]: GEN_AI_OPERATION_NAME_VALUE_CHAT, + [SENTRY_OP]: GEN_AI_CHAT_SPAN_OP, }; const modelId = request.commandInput.modelId; @@ -120,6 +125,7 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { const spanAttributes: Attributes = { // oxlint-disable-next-line typescript/no-deprecated [GEN_AI_SYSTEM]: GEN_AI_SYSTEM_VALUE_AWS_BEDROCK, + [SENTRY_OP]: GEN_AI_GENERATE_CONTENT_SPAN_OP, // add operation name for InvokeModel API }; diff --git a/packages/server-utils/src/integrations/tracing-channel/aws-sdk/index.ts b/packages/server-utils/src/integrations/tracing-channel/aws-sdk/index.ts index d33bb8ba171c..54cf8b66ccf5 100644 --- a/packages/server-utils/src/integrations/tracing-channel/aws-sdk/index.ts +++ b/packages/server-utils/src/integrations/tracing-channel/aws-sdk/index.ts @@ -13,6 +13,7 @@ import { CLOUD_REGION, HTTP_STATUS_CODE, SENTRY_KIND, + SENTRY_OP, } from '@sentry/conventions/attributes'; import { DEBUG_BUILD } from '../../../debug-build'; import { CHANNELS } from '../../../orchestrion/channels'; @@ -110,10 +111,10 @@ const _awsIntegration = (() => { const span = startInactiveSpan({ name: requestMetadata.spanName ?? `${normalizedRequest.serviceName}.${normalizedRequest.commandName}`, - // `rpc` matches what the exporter infers from `rpc.service` for the OTel aws-sdk spans; - // service extensions override it where inference yields a different op (DynamoDB: `db`). - op: requestMetadata.spanOp || 'rpc', attributes: { + // `rpc` matches what the exporter infers from `rpc.service` for the OTel aws-sdk spans; + // service extensions override it where inference yields a different op (DynamoDB: `db`). + [SENTRY_OP]: requestMetadata.spanOp || 'rpc', [SENTRY_KIND]: 'client', [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: AWS_SDK_ORIGIN, ...extractAttributesFromNormalizedRequest(normalizedRequest), diff --git a/packages/server-utils/src/integrations/tracing-channel/aws-sdk/services/bedrock-runtime.ts b/packages/server-utils/src/integrations/tracing-channel/aws-sdk/services/bedrock-runtime.ts index 94cab0159c18..d3c5bfd524d6 100644 --- a/packages/server-utils/src/integrations/tracing-channel/aws-sdk/services/bedrock-runtime.ts +++ b/packages/server-utils/src/integrations/tracing-channel/aws-sdk/services/bedrock-runtime.ts @@ -11,7 +11,9 @@ import { GEN_AI_SYSTEM, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, + SENTRY_OP, } from '@sentry/conventions/attributes'; +import { GEN_AI_CHAT_SPAN_OP } from '@sentry/conventions/op'; import { DEBUG_BUILD } from '../../../../debug-build'; import { GEN_AI_OPERATION_NAME_VALUE_CHAT, GEN_AI_SYSTEM_VALUE_AWS_BEDROCK } from '../constants'; import type { NormalizedRequest, NormalizedResponse } from '../types'; @@ -36,6 +38,8 @@ interface ConverseStreamOutput { // of one structural type per family. type ParsedChunk = any; +const GEN_AI_GENERATE_CONTENT_SPAN_OP = 'generate_content'; + const textDecoder = new TextDecoder(); export class BedrockRuntimeServiceExtension implements ServiceExtension { @@ -85,6 +89,7 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { // oxlint-disable-next-line typescript/no-deprecated [GEN_AI_SYSTEM]: GEN_AI_SYSTEM_VALUE_AWS_BEDROCK, [GEN_AI_OPERATION_NAME]: GEN_AI_OPERATION_NAME_VALUE_CHAT, + [SENTRY_OP]: GEN_AI_CHAT_SPAN_OP, }; const modelId = request.commandInput.modelId; @@ -123,6 +128,7 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { const spanAttributes: Record = { // oxlint-disable-next-line typescript/no-deprecated [GEN_AI_SYSTEM]: GEN_AI_SYSTEM_VALUE_AWS_BEDROCK, + [SENTRY_OP]: GEN_AI_GENERATE_CONTENT_SPAN_OP, }; const modelId = request.commandInput?.modelId;