From 7608585f86036e326fed7f152d2b8e51ffdb9649 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Fri, 21 Mar 2025 11:16:02 +0900 Subject: [PATCH 1/8] feat(instrumentation-aws-sdk): add gen ai conventions for converse stream span --- .../src/aws-sdk.ts | 10 ++- .../src/services/ServiceExtension.ts | 7 ++- .../src/services/ServicesExtensions.ts | 2 +- .../src/services/bedrock-runtime.ts | 61 +++++++++++++++++-- .../test/bedrock-runtime.test.ts | 55 +++++++++++++++++ ...conversestream-adds-genai-conventions.json | 42 +++++++++++++ 6 files changed, 167 insertions(+), 10 deletions(-) create mode 100644 plugins/node/opentelemetry-instrumentation-aws-sdk/test/mock-responses/bedrock-conversestream-adds-genai-conventions.json diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts index f894e28458..63c5c635bd 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/aws-sdk.ts @@ -400,12 +400,16 @@ export class AwsInstrumentation extends InstrumentationBase { - span.end(); + if (!requestMetadata.isStream) { + span.end(); + } }); promiseWithResponseLogic .then(res => { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts index 95f89bdac5..836ac0ddc6 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts @@ -29,6 +29,10 @@ import { export interface RequestMetadata { // isIncoming - if true, then the operation callback / promise should be bind with the operation's span isIncoming: boolean; + // isStream - if true, then the response is a stream so the span should not be ended by the middleware. + // the ServiceExtension must end the span itself, generally by wrapping the stream and ending after it is + // consumed. + isStream?: boolean; spanAttributes?: SpanAttributes; spanKind?: SpanKind; spanName?: string; @@ -45,10 +49,11 @@ export interface ServiceExtension { // called before request is sent, and after span is started requestPostSpanHook?: (request: NormalizedRequest) => void; + // called after response is received. If value is returned, it replaces the response output. responseHook?: ( response: NormalizedResponse, span: Span, tracer: Tracer, config: AwsSdkInstrumentationConfig - ) => void; + ) => any | undefined; } diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts index edf18bdaea..23c1e2aa59 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts @@ -67,6 +67,6 @@ export class ServicesExtensions implements ServiceExtension { config: AwsSdkInstrumentationConfig ) { const serviceExtension = this.services.get(response.request.serviceName); - serviceExtension?.responseHook?.(response, span, tracer, config); + return serviceExtension?.responseHook?.(response, span, tracer, config); } } diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts index 3c3e88c813..cd1cd830a9 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts @@ -34,6 +34,10 @@ import { NormalizedRequest, NormalizedResponse, } from '../types'; +import { + ConverseStreamOutput, + TokenUsage, +} from '@aws-sdk/client-bedrock-runtime'; export class BedrockRuntimeServiceExtension implements ServiceExtension { requestPreSpanHook( @@ -43,7 +47,9 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { ): RequestMetadata { switch (request.commandName) { case 'Converse': - return this.requestPreSpanHookConverse(request, config, diag); + return this.requestPreSpanHookConverse(request, config, diag, false); + case 'ConverseStream': + return this.requestPreSpanHookConverse(request, config, diag, true); } return { @@ -54,7 +60,8 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { private requestPreSpanHookConverse( request: NormalizedRequest, config: AwsSdkInstrumentationConfig, - diag: DiagLogger + diag: DiagLogger, + isStream: boolean ): RequestMetadata { let spanName = GEN_AI_OPERATION_NAME_VALUE_CHAT; const spanAttributes: Attributes = { @@ -90,6 +97,7 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { return { spanName, isIncoming: false, + isStream, spanAttributes, }; } @@ -107,6 +115,8 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { switch (response.request.commandName) { case 'Converse': return this.responseHookConverse(response, span, tracer, config); + case 'ConverseStream': + return this.responseHookConverseStream(response, span, tracer, config); } } @@ -117,6 +127,49 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { config: AwsSdkInstrumentationConfig ) { const { stopReason, usage } = response.data; + + BedrockRuntimeServiceExtension.setStopReason(span, stopReason); + BedrockRuntimeServiceExtension.setUsage(span, usage); + } + + private responseHookConverseStream( + response: NormalizedResponse, + span: Span, + tracer: Tracer, + config: AwsSdkInstrumentationConfig + ) { + return { + ...response.data, + stream: this.wrapConverseStreamResponse(response.data.stream, span), + }; + } + + private async *wrapConverseStreamResponse( + response: AsyncIterable, + span: Span + ) { + try { + for await (const item of response) { + BedrockRuntimeServiceExtension.setStopReason( + span, + item.messageStop?.stopReason + ); + BedrockRuntimeServiceExtension.setUsage(span, item.metadata?.usage); + yield item; + } + } finally { + span.end(); + } + } + + private static setStopReason(span: Span, stopReason: string | undefined) { + if (stopReason !== undefined) { + console.log(stopReason); + span.setAttribute(ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [stopReason]); + } + } + + private static setUsage(span: Span, usage: TokenUsage | undefined) { if (usage) { const { inputTokens, outputTokens } = usage; if (inputTokens !== undefined) { @@ -126,9 +179,5 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { span.setAttribute(ATTR_GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens); } } - - if (stopReason !== undefined) { - span.setAttribute(ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [stopReason]); - } } } diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts index 43bf1abd47..23271562b7 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts @@ -39,6 +39,7 @@ import { ConverseCommand, ConversationRole, InvokeModelCommand, + ConverseStreamCommand, } from '@aws-sdk/client-bedrock-runtime'; import { AwsCredentialIdentity } from '@aws-sdk/types'; import * as path from 'path'; @@ -154,6 +155,60 @@ describe('Bedrock', () => { }); }); + describe('ConverseStream', () => { + it('adds genai conventions', async () => { + const modelId = 'amazon.titan-text-lite-v1'; + const messages = [ + { + role: ConversationRole.USER, + content: [{ text: 'Say this is a test' }], + }, + ]; + const inferenceConfig = { + maxTokens: 10, + temperature: 0.8, + topP: 1, + stopSequences: ['|'], + }; + + const command = new ConverseStreamCommand({ + modelId, + messages, + inferenceConfig, + }); + + const response = await client.send(command); + const chunks: string[] = []; + for await (const item of response.stream!) { + const text = item.contentBlockDelta?.delta?.text; + if (text) { + chunks.push(text); + } + } + expect(chunks.join('')).toBe('Hi! How are you? How'); + + const testSpans: ReadableSpan[] = getTestSpans(); + const converseSpans: ReadableSpan[] = testSpans.filter( + (s: ReadableSpan) => { + return s.name === 'chat amazon.titan-text-lite-v1'; + } + ); + expect(converseSpans.length).toBe(1); + expect(converseSpans[0].attributes).toMatchObject({ + [ATTR_GEN_AI_SYSTEM]: GEN_AI_SYSTEM_VALUE_AWS_BEDROCK, + [ATTR_GEN_AI_OPERATION_NAME]: GEN_AI_OPERATION_NAME_VALUE_CHAT, + [ATTR_GEN_AI_REQUEST_MODEL]: modelId, + [ATTR_GEN_AI_REQUEST_MAX_TOKENS]: 10, + [ATTR_GEN_AI_REQUEST_TEMPERATURE]: 0.8, + [ATTR_GEN_AI_REQUEST_TOP_P]: 1, + [ATTR_GEN_AI_REQUEST_STOP_SEQUENCES]: ['|'], + [ATTR_GEN_AI_USAGE_INPUT_TOKENS]: 8, + [ATTR_GEN_AI_USAGE_OUTPUT_TOKENS]: 10, + [ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: ['max_tokens'], + }); + }); + }); + // TODO: Instrument InvokeModel describe('InvokeModel', () => { it('does not currently add genai conventions', async () => { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/mock-responses/bedrock-conversestream-adds-genai-conventions.json b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/mock-responses/bedrock-conversestream-adds-genai-conventions.json new file mode 100644 index 0000000000..2fd8efdee3 --- /dev/null +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/mock-responses/bedrock-conversestream-adds-genai-conventions.json @@ -0,0 +1,42 @@ +[ + { + "scope": "https://bedrock-runtime.us-east-1.amazonaws.com:443", + "method": "POST", + "path": "/model/amazon.titan-text-lite-v1/converse-stream", + "body": { + "inferenceConfig": { + "maxTokens": 10, + "stopSequences": [ + "|" + ], + "temperature": 0.8, + "topP": 1 + }, + "messages": [ + { + "content": [ + { + "text": "Say this is a test" + } + ], + "role": "user" + } + ] + }, + "status": 200, + "response": "00000081000000526cc176930b3a6576656e742d7479706507000c6d65737361676553746172740d3a636f6e74656e742d747970650700106170706c69636174696f6e2f6a736f6e0d3a6d6573736167652d747970650700056576656e747b2270223a2261626364222c22726f6c65223a22617373697374616e74227df512a005000000c600000057f67806450b3a6576656e742d74797065070011636f6e74656e74426c6f636b44656c74610d3a636f6e74656e742d747970650700106170706c69636174696f6e2f6a736f6e0d3a6d6573736167652d747970650700056576656e747b22636f6e74656e74426c6f636b496e646578223a302c2264656c7461223a7b2274657874223a2248692120486f772061726520796f753f20486f77227d2c2270223a226162636465666768696a6b6c6d6e6f70717273747576777879227da88f22a40000009500000056fecc83c80b3a6576656e742d74797065070010636f6e74656e74426c6f636b53746f700d3a636f6e74656e742d747970650700106170706c69636174696f6e2f6a736f6e0d3a6d6573736167652d747970650700056576656e747b22636f6e74656e74426c6f636b496e646578223a302c2270223a226162636465666768696a6b6c6d6e6f7071227d8dc2956d00000097000000511a68450b0b3a6576656e742d7479706507000b6d65737361676553746f700d3a636f6e74656e742d747970650700106170706c69636174696f6e2f6a736f6e0d3a6d6573736167652d747970650700056576656e747b2270223a226162636465666768696a6b6c6d6e6f7071727374222c2273746f70526561736f6e223a226d61785f746f6b656e73227ddb5bf387000000ce0000004ea263e5440b3a6576656e742d747970650700086d657461646174610d3a636f6e74656e742d747970650700106170706c69636174696f6e2f6a736f6e0d3a6d6573736167652d747970650700056576656e747b226d657472696373223a7b226c6174656e63794d73223a3736357d2c2270223a226162636465666768696a6b6c6d6e6f222c227573616765223a7b22696e707574546f6b656e73223a382c226f7574707574546f6b656e73223a31302c22746f74616c546f6b656e73223a31387d7d98eada7f", + "rawHeaders": [ + "Date", + "Fri, 21 Mar 2025 02:04:20 GMT", + "Content-Type", + "application/vnd.amazon.eventstream", + "Transfer-Encoding", + "chunked", + "Connection", + "keep-alive", + "x-amzn-RequestId", + "c01898c3-00ef-43e3-b015-e7458e9afc84" + ], + "responseIsBinary": true + } +] \ No newline at end of file From 938e1c219a523180462b2fb8a2aaf133d4135879 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Fri, 21 Mar 2025 12:13:34 +0900 Subject: [PATCH 2/8] Non-automatic style fix --- .../test/bedrock-runtime.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts index 23271562b7..676303e992 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts @@ -37,9 +37,9 @@ registerInstrumentationTesting(new AwsInstrumentation()); import { BedrockRuntimeClient, ConverseCommand, + ConverseStreamCommand, ConversationRole, InvokeModelCommand, - ConverseStreamCommand, } from '@aws-sdk/client-bedrock-runtime'; import { AwsCredentialIdentity } from '@aws-sdk/types'; import * as path from 'path'; From 22ea86d2bfbe729a97f36e56880c2532935566bd Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Thu, 10 Apr 2025 11:24:30 +0900 Subject: [PATCH 3/8] import type --- .../src/services/bedrock-runtime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts index cd1cd830a9..3b7fe95b6b 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts @@ -34,7 +34,7 @@ import { NormalizedRequest, NormalizedResponse, } from '../types'; -import { +import type { ConverseStreamOutput, TokenUsage, } from '@aws-sdk/client-bedrock-runtime'; From 409b434fe0181a781150877084f011265b2be709 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Thu, 15 May 2025 12:32:16 +0900 Subject: [PATCH 4/8] WIP --- .../src/services/ServiceExtension.ts | 2 +- .../src/services/ServicesExtensions.ts | 8 ++++++- .../src/services/bedrock-runtime.ts | 24 +++++++++++++++---- .../test/bedrock-runtime.test.ts | 2 -- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts index 842556e819..fc30898002 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServiceExtension.ts @@ -56,7 +56,7 @@ export interface ServiceExtension { response: NormalizedResponse, span: Span, tracer: Tracer, - config: AwsSdkInstrumentationConfig + config: AwsSdkInstrumentationConfig, startTime: HrTime ) => any | undefined; diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts index 6e0e5e9437..50fb3508d3 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/ServicesExtensions.ts @@ -69,7 +69,13 @@ export class ServicesExtensions implements ServiceExtension { ) { const serviceExtension = this.services.get(response.request.serviceName); - return serviceExtension?.responseHook?.(response, span, tracer, config, startTime); + return serviceExtension?.responseHook?.( + response, + span, + tracer, + config, + startTime + ); } updateMetricInstruments(meter: Meter) { diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts index 930cd73da1..5373fb0ae9 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts @@ -47,7 +47,6 @@ import { NormalizedResponse, } from '../types'; import type { - ConverseStreamOutput, TokenUsage, } from '@aws-sdk/client-bedrock-runtime'; import { @@ -329,9 +328,21 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { switch (response.request.commandName) { case 'Converse': - return this.responseHookConverse(response, span, tracer, config, startTime); + return this.responseHookConverse( + response, + span, + tracer, + config, + startTime + ); case 'ConverseStream': - return this.responseHookConverseStream(response, span, tracer, config, startTime); + return this.responseHookConverseStream( + response, + span, + tracer, + config, + startTime + ); case 'InvokeModel': return this.responseHookInvokeModel(response, span, tracer, config); } @@ -389,7 +400,12 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { } } - private setUsage(response: NormalizedResponse, span: Span, usage: TokenUsage | undefined, startTime: HrTime) { + private setUsage( + response: NormalizedResponse, + span: Span, + usage: TokenUsage | undefined, + startTime: HrTime + ) { const sharedMetricAttrs: Attributes = { [ATTR_GEN_AI_SYSTEM]: GEN_AI_SYSTEM_VALUE_AWS_BEDROCK, [ATTR_GEN_AI_OPERATION_NAME]: GEN_AI_OPERATION_NAME_VALUE_CHAT, diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts index c9a25bcc4e..8cac0da0a9 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts @@ -277,8 +277,6 @@ describe('Bedrock', () => { [ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: ['max_tokens'], }); - - const { resourceMetrics } = await metricReader.collect(); expect(resourceMetrics.scopeMetrics.length).toBe(1); const scopeMetrics = resourceMetrics.scopeMetrics[0]; From 4db49c3da1d36b631c073ab8bd2cb7551bce5bd7 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Thu, 15 May 2025 13:14:29 +0900 Subject: [PATCH 5/8] Finish --- .../src/services/bedrock-runtime.ts | 15 ++++++++++--- .../test/bedrock-runtime.test.ts | 11 +++++++--- .../test/load-instrumentation.ts | 21 +++++++++++++++---- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts index 5373fb0ae9..b7f918ea65 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts @@ -47,6 +47,7 @@ import { NormalizedResponse, } from '../types'; import type { + ConverseStreamOutput, TokenUsage, } from '@aws-sdk/client-bedrock-runtime'; import { @@ -370,24 +371,32 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { ) { return { ...response.data, - stream: this.wrapConverseStreamResponse(response, span, startTime), + stream: this.wrapConverseStreamResponse( + response, + response.data.stream, + span, + startTime + ), }; } private async *wrapConverseStreamResponse( response: NormalizedResponse, + stream: AsyncIterable, span: Span, startTime: HrTime ) { try { - for await (const item of response.data.stream) { + let usage: TokenUsage | undefined; + for await (const item of stream) { BedrockRuntimeServiceExtension.setStopReason( span, item.messageStop?.stopReason ); - this.setUsage(response, span, item.metadata?.usage, startTime); + usage = item.metadata?.usage; yield item; } + this.setUsage(response, span, usage, startTime); } finally { span.end(); } diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts index 8cac0da0a9..ec6246d653 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts @@ -28,7 +28,7 @@ */ import { getTestSpans } from '@opentelemetry/contrib-test-utils'; -import { metricReader } from './load-instrumentation'; +import { meterProvider, metricExporter } from './load-instrumentation'; import { BedrockRuntimeClient, @@ -107,6 +107,9 @@ describe('Bedrock', () => { afterEach(async function () { nockDone(); + + await meterProvider.forceFlush(); + metricExporter.reset(); }); describe('Converse', () => { @@ -155,7 +158,8 @@ describe('Bedrock', () => { [ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: ['max_tokens'], }); - const { resourceMetrics } = await metricReader.collect(); + await meterProvider.forceFlush(); + const [resourceMetrics] = metricExporter.getMetrics(); expect(resourceMetrics.scopeMetrics.length).toBe(1); const scopeMetrics = resourceMetrics.scopeMetrics[0]; const tokenUsage = scopeMetrics.metrics.filter( @@ -277,7 +281,8 @@ describe('Bedrock', () => { [ATTR_GEN_AI_RESPONSE_FINISH_REASONS]: ['max_tokens'], }); - const { resourceMetrics } = await metricReader.collect(); + await meterProvider.forceFlush(); + const [resourceMetrics] = metricExporter.getMetrics(); expect(resourceMetrics.scopeMetrics.length).toBe(1); const scopeMetrics = resourceMetrics.scopeMetrics[0]; const tokenUsage = scopeMetrics.metrics.filter( diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/load-instrumentation.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/load-instrumentation.ts index 531ce19b82..0942f2f9ba 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/load-instrumentation.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/load-instrumentation.ts @@ -21,12 +21,25 @@ * specific test. We instead instantiate a single instrumentation instance here to * use within all tests. */ +import { registerInstrumentationTesting } from '@opentelemetry/contrib-test-utils'; import { - initMeterProvider, - registerInstrumentationTesting, -} from '@opentelemetry/contrib-test-utils'; + AggregationTemporality, + InMemoryMetricExporter, + MeterProvider, + PeriodicExportingMetricReader, +} from '@opentelemetry/sdk-metrics'; import { AwsInstrumentation } from '../src'; export const instrumentation = new AwsInstrumentation(); -export const metricReader = initMeterProvider(instrumentation); +export const metricExporter = new InMemoryMetricExporter( + AggregationTemporality.DELTA +); +export const meterProvider = new MeterProvider({ + readers: [ + new PeriodicExportingMetricReader({ + exporter: metricExporter, + }), + ], +}); +instrumentation.setMeterProvider(meterProvider); registerInstrumentationTesting(instrumentation); From d9c2938bc46cf104ba8448d14fce7507999fbff7 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Fri, 16 May 2025 10:53:41 +0900 Subject: [PATCH 6/8] Cleanup --- .../src/services/bedrock-runtime.ts | 1 - .../test/bedrock-runtime.test.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts index b7f918ea65..1656b2f2fe 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts @@ -404,7 +404,6 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { private static setStopReason(span: Span, stopReason: string | undefined) { if (stopReason !== undefined) { - console.log(stopReason); span.setAttribute(ATTR_GEN_AI_RESPONSE_FINISH_REASONS, [stopReason]); } } diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts index ec6246d653..b01ed09010 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/test/bedrock-runtime.test.ts @@ -352,7 +352,6 @@ describe('Bedrock', () => { }); }); - // TODO: Instrument InvokeModel describe('InvokeModel', () => { it('adds amazon titan model attributes to span', async () => { const modelId = 'amazon.titan-text-express-v1'; From 4838419a6ff7ac9eb74e7d5ac974ac4cddefce85 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Tue, 20 May 2025 10:35:56 +0900 Subject: [PATCH 7/8] Comment --- .../src/services/bedrock-runtime.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts index 1656b2f2fe..3b362e6500 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts @@ -371,6 +371,7 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { ) { return { ...response.data, + // Wrap and replace the response stream to allow processing events to telemetry. stream: this.wrapConverseStreamResponse( response, response.data.stream, From c908fe9bc397dd789064c0a4ec3a451038fd494e Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Tue, 20 May 2025 10:36:16 +0900 Subject: [PATCH 8/8] A bit more --- .../src/services/bedrock-runtime.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts index 3b362e6500..f15a91ad39 100644 --- a/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts +++ b/plugins/node/opentelemetry-instrumentation-aws-sdk/src/services/bedrock-runtime.ts @@ -371,7 +371,8 @@ export class BedrockRuntimeServiceExtension implements ServiceExtension { ) { return { ...response.data, - // Wrap and replace the response stream to allow processing events to telemetry. + // Wrap and replace the response stream to allow processing events to telemetry + // before yielding to the user. stream: this.wrapConverseStreamResponse( response, response.data.stream,