Skip to content

Commit 96eec18

Browse files
committed
Merge branch 'main' into lambda-layer-E2E
# Conflicts: # .github/workflows/application-signals-e2e-test.yml
2 parents 6e2dadf + 4cdc78f commit 96eec18

15 files changed

+1100
-50
lines changed

aws-distro-opentelemetry-node-autoinstrumentation/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
"url": "https://github.com/aws-observability/aws-otel-js-instrumentation/issues"
3939
},
4040
"devDependencies": {
41+
"@aws-sdk/client-bedrock": "3.632.0",
42+
"@aws-sdk/client-bedrock-agent": "3.632.0",
43+
"@aws-sdk/client-bedrock-agent-runtime": "3.632.0",
44+
"@aws-sdk/client-bedrock-runtime": "3.632.0",
4145
"@aws-sdk/client-kinesis": "3.632.0",
4246
"@aws-sdk/client-s3": "3.632.0",
4347
"@aws-sdk/client-sqs": "3.632.0",

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-attribute-keys.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ export const AWS_ATTRIBUTE_KEYS: { [key: string]: string } = {
3131
AWS_SQS_QUEUE_NAME: 'aws.sqs.queue.name',
3232
AWS_KINESIS_STREAM_NAME: 'aws.kinesis.stream.name',
3333
AWS_DYNAMODB_TABLE_NAMES: SEMATTRS_AWS_DYNAMODB_TABLE_NAMES,
34+
AWS_BEDROCK_DATA_SOURCE_ID: 'aws.bedrock.data_source.id',
35+
AWS_BEDROCK_KNOWLEDGE_BASE_ID: 'aws.bedrock.knowledge_base.id',
36+
AWS_BEDROCK_AGENT_ID: 'aws.bedrock.agent.id',
37+
AWS_BEDROCK_GUARDRAIL_ID: 'aws.bedrock.guardrail.id',
3438
};

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-metric-attribute-generator.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ const NORMALIZED_DYNAMO_DB_SERVICE_NAME: string = 'AWS::DynamoDB';
5555
const NORMALIZED_KINESIS_SERVICE_NAME: string = 'AWS::Kinesis';
5656
const NORMALIZED_S3_SERVICE_NAME: string = 'AWS::S3';
5757
const NORMALIZED_SQS_SERVICE_NAME: string = 'AWS::SQS';
58+
const NORMALIZED_BEDROCK_SERVICE_NAME: string = 'AWS::Bedrock';
59+
const NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME: string = 'AWS::BedrockRuntime';
5860

5961
const DB_CONNECTION_RESOURCE_TYPE: string = 'DB::Connection';
6062
// As per https://opentelemetry.io/docs/specs/semconv/resource/#service, if service name is not specified, SDK defaults
@@ -317,10 +319,19 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
317319
* Cloud Control resource format</a> as much as possible, with special attention to services we
318320
* can detect remote resource information for. Long term, we would like to normalize service name
319321
* in the upstream.
322+
*
323+
* For Bedrock, Bedrock Agent, and Bedrock Agent Runtime, we can align with AWS Cloud Control and use
324+
* AWS::Bedrock for RemoteService. For BedrockRuntime, we are using AWS::BedrockRuntime
325+
* as the associated remote resource (Model) is not listed in Cloud Control.
320326
*/
321327
private static normalizeRemoteServiceName(span: ReadableSpan, serviceName: string): string {
322328
if (AwsSpanProcessingUtil.isAwsSDKSpan(span)) {
323-
return 'AWS::' + serviceName;
329+
const awsSdkServiceMapping: { [key: string]: string } = {
330+
BedrockAgent: NORMALIZED_BEDROCK_SERVICE_NAME,
331+
BedrockAgentRuntime: NORMALIZED_BEDROCK_SERVICE_NAME,
332+
BedrockRuntime: NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME,
333+
};
334+
return awsSdkServiceMapping[serviceName] || 'AWS::' + serviceName;
324335
}
325336
return serviceName;
326337
}
@@ -369,6 +380,31 @@ export class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
369380
remoteResourceIdentifier = SqsUrlParser.getQueueName(
370381
AwsMetricAttributeGenerator.escapeDelimiters(span.attributes[AWS_ATTRIBUTE_KEYS.AWS_SQS_QUEUE_URL])
371382
);
383+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_AGENT_ID)) {
384+
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::Agent';
385+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
386+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_AGENT_ID]
387+
);
388+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID)) {
389+
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::DataSource';
390+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
391+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_DATA_SOURCE_ID]
392+
);
393+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID)) {
394+
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::Guardrail';
395+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
396+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_GUARDRAIL_ID]
397+
);
398+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID)) {
399+
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::KnowledgeBase';
400+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
401+
span.attributes[AWS_ATTRIBUTE_KEYS.AWS_BEDROCK_KNOWLEDGE_BASE_ID]
402+
);
403+
} else if (AwsSpanProcessingUtil.isKeyPresent(span, AwsSpanProcessingUtil.GEN_AI_REQUEST_MODEL)) {
404+
remoteResourceType = NORMALIZED_BEDROCK_SERVICE_NAME + '::Model';
405+
remoteResourceIdentifier = AwsMetricAttributeGenerator.escapeDelimiters(
406+
span.attributes[AwsSpanProcessingUtil.GEN_AI_REQUEST_MODEL]
407+
);
372408
}
373409
} else if (AwsSpanProcessingUtil.isDBSpan(span)) {
374410
remoteResourceType = DB_CONNECTION_RESOURCE_TYPE;

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-opentelemetry-configurator.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,13 @@ export class AwsOpentelemetryConfigurator {
273273
resource: resource,
274274
readers: [periodicExportingMetricReader],
275275
});
276-
spanProcessors.push(AwsSpanMetricsProcessorBuilder.create(meterProvider, resource).build());
276+
spanProcessors.push(
277+
AwsSpanMetricsProcessorBuilder.create(
278+
meterProvider,
279+
resource,
280+
meterProvider.forceFlush.bind(meterProvider)
281+
).build()
282+
);
277283
}
278284
}
279285

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-span-metrics-processor-builder.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Resource } from '@opentelemetry/resources';
66
import { AwsMetricAttributeGenerator } from './aws-metric-attribute-generator';
77
import { AwsSpanMetricsProcessor } from './aws-span-metrics-processor';
88
import { MetricAttributeGenerator } from './metric-attribute-generator';
9+
import { ForceFlushFunction } from './aws-span-processing-util';
910

1011
// Metric instrument configuration constants
1112
const ERROR: string = 'Error';
@@ -22,18 +23,24 @@ export class AwsSpanMetricsProcessorBuilder {
2223
// Required builder elements
2324
private meterProvider: MeterProvider;
2425
private resource: Resource;
26+
private forceFlushFunction: ForceFlushFunction;
2527

2628
// Optional builder elements
2729
private generator: MetricAttributeGenerator = AwsSpanMetricsProcessorBuilder.DEFAULT_GENERATOR;
2830
private scopeName: string = AwsSpanMetricsProcessorBuilder.DEFAULT_SCOPE_NAME;
2931

30-
public static create(meterProvider: MeterProvider, resource: Resource): AwsSpanMetricsProcessorBuilder {
31-
return new AwsSpanMetricsProcessorBuilder(meterProvider, resource);
32+
public static create(
33+
meterProvider: MeterProvider,
34+
resource: Resource,
35+
meterProviderForceFlusher: ForceFlushFunction
36+
): AwsSpanMetricsProcessorBuilder {
37+
return new AwsSpanMetricsProcessorBuilder(meterProvider, resource, meterProviderForceFlusher);
3238
}
3339

34-
private constructor(meterProvider: MeterProvider, resource: Resource) {
40+
private constructor(meterProvider: MeterProvider, resource: Resource, meterProviderForceFlusher: ForceFlushFunction) {
3541
this.meterProvider = meterProvider;
3642
this.resource = resource;
43+
this.forceFlushFunction = meterProviderForceFlusher;
3744
}
3845

3946
/**
@@ -72,7 +79,8 @@ export class AwsSpanMetricsProcessorBuilder {
7279
faultHistogram,
7380
latencyHistogram,
7481
this.generator,
75-
this.resource
82+
this.resource,
83+
this.forceFlushFunction
7684
);
7785
}
7886
}

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-span-metrics-processor.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { Resource } from '@opentelemetry/resources';
66
import { ReadableSpan, Span, SpanProcessor } from '@opentelemetry/sdk-trace-base';
77
import { SEMATTRS_HTTP_STATUS_CODE } from '@opentelemetry/semantic-conventions';
88
import { AttributeMap, MetricAttributeGenerator } from './metric-attribute-generator';
9+
import { ForceFlushFunction } from './aws-span-processing-util';
910

1011
/**
1112
* This processor will generate metrics based on span data. It depends on a
@@ -39,30 +40,41 @@ export class AwsSpanMetricsProcessor implements SpanProcessor {
3940

4041
private generator: MetricAttributeGenerator;
4142
private resource: Resource;
43+
private forceFlushFunction: ForceFlushFunction;
4244

4345
/** Use {@link AwsSpanMetricsProcessorBuilder} to construct this processor. */
4446
static create(
4547
errorHistogram: Histogram,
4648
faultHistogram: Histogram,
4749
latencyHistogram: Histogram,
4850
generator: MetricAttributeGenerator,
49-
resource: Resource
51+
resource: Resource,
52+
forceFlushFunction: ForceFlushFunction
5053
): AwsSpanMetricsProcessor {
51-
return new AwsSpanMetricsProcessor(errorHistogram, faultHistogram, latencyHistogram, generator, resource);
54+
return new AwsSpanMetricsProcessor(
55+
errorHistogram,
56+
faultHistogram,
57+
latencyHistogram,
58+
generator,
59+
resource,
60+
forceFlushFunction
61+
);
5262
}
5363

5464
private constructor(
5565
errorHistogram: Histogram,
5666
faultHistogram: Histogram,
5767
latencyHistogram: Histogram,
5868
generator: MetricAttributeGenerator,
59-
resource: Resource
69+
resource: Resource,
70+
forceFlushFunction: ForceFlushFunction
6071
) {
6172
this.errorHistogram = errorHistogram;
6273
this.faultHistogram = faultHistogram;
6374
this.latencyHistogram = latencyHistogram;
6475
this.generator = generator;
6576
this.resource = resource;
77+
this.forceFlushFunction = forceFlushFunction;
6678
}
6779

6880
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -129,6 +141,6 @@ export class AwsSpanMetricsProcessor implements SpanProcessor {
129141
}
130142

131143
public forceFlush(): Promise<void> {
132-
return Promise.resolve();
144+
return this.forceFlushFunction();
133145
}
134146
}

aws-distro-opentelemetry-node-autoinstrumentation/src/aws-span-processing-util.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import { AWS_ATTRIBUTE_KEYS } from './aws-attribute-keys';
2020
import { AWS_LAMBDA_FUNCTION_NAME_CONFIG, isLambdaEnvironment } from './aws-opentelemetry-configurator';
2121
import * as SQL_DIALECT_KEYWORDS_JSON from './configuration/sql_dialect_keywords.json';
2222

23+
export type ForceFlushFunction = (options?: any) => Promise<void>;
24+
2325
/** Utility class designed to support shared logic across AWS Span Processors. */
2426
export class AwsSpanProcessingUtil {
2527
// Default attribute values if no valid span attribute value is identified
@@ -38,6 +40,10 @@ export class AwsSpanProcessingUtil {
3840
static MAX_KEYWORD_LENGTH: number = 27;
3941
static SQL_DIALECT_PATTERN: string = '^(?:' + AwsSpanProcessingUtil.getDialectKeywords().join('|') + ')\\b';
4042

43+
// TODO: Use Semantic Conventions once upgraded
44+
static GEN_AI_REQUEST_MODEL: string = 'gen_ai.request.model';
45+
static GEN_AI_SYSTEM: string = 'gen_ai.system';
46+
4147
static getDialectKeywords(): string[] {
4248
return SQL_DIALECT_KEYWORDS_JSON.keywords;
4349
}

0 commit comments

Comments
 (0)