Skip to content

Commit 197bac9

Browse files
authored
Merge branch 'main' into missing-jmx
2 parents d44bc82 + 4077ee0 commit 197bac9

File tree

8 files changed

+206
-11
lines changed

8 files changed

+206
-11
lines changed

awsagentprovider/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ dependencies {
3636
implementation("io.opentelemetry.contrib:opentelemetry-aws-resources")
3737
// Json file reader
3838
implementation("com.fasterxml.jackson.core:jackson-databind:2.16.1")
39+
// Import AWS SDK v1 core for ARN parsing utilities
40+
implementation("com.amazonaws:aws-java-sdk-core:1.12.773")
3941
// Export configuration
4042
compileOnly("io.opentelemetry:opentelemetry-exporter-otlp")
4143

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsApplicationSignalsCustomizerProvider.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717

1818
import io.opentelemetry.api.common.Attributes;
1919
import io.opentelemetry.api.common.AttributesBuilder;
20-
import io.opentelemetry.api.metrics.MeterProvider;
2120
import io.opentelemetry.contrib.awsxray.AlwaysRecordSampler;
2221
import io.opentelemetry.contrib.awsxray.ResourceHolder;
2322
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
@@ -164,14 +163,16 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
164163
MetricReader metricReader =
165164
PeriodicMetricReader.builder(metricsExporter).setInterval(exportInterval).build();
166165

167-
MeterProvider meterProvider =
166+
SdkMeterProvider meterProvider =
168167
SdkMeterProvider.builder()
169168
.setResource(ResourceHolder.getResource())
170169
.registerMetricReader(metricReader)
171170
.build();
171+
172172
// Construct and set application signals metrics processor
173173
SpanProcessor spanMetricsProcessor =
174-
AwsSpanMetricsProcessorBuilder.create(meterProvider, ResourceHolder.getResource())
174+
AwsSpanMetricsProcessorBuilder.create(
175+
meterProvider, ResourceHolder.getResource(), meterProvider::forceFlush)
175176
.build();
176177
tracerProviderBuilder.addSpanProcessor(spanMetricsProcessor);
177178
}

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsAttributeKeys.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ private AwsAttributeKeys() {}
3838
static final AttributeKey<String> AWS_REMOTE_RESOURCE_IDENTIFIER =
3939
AttributeKey.stringKey("aws.remote.resource.identifier");
4040

41+
static final AttributeKey<String> AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER =
42+
AttributeKey.stringKey("aws.remote.resource.cfn.primary.identifier");
43+
4144
static final AttributeKey<String> AWS_REMOTE_RESOURCE_TYPE =
4245
AttributeKey.stringKey("aws.remote.resource.type");
4346

@@ -50,6 +53,26 @@ private AwsAttributeKeys() {}
5053
static final AttributeKey<String> AWS_CONSUMER_PARENT_SPAN_KIND =
5154
AttributeKey.stringKey("aws.consumer.parent.span.kind");
5255

56+
static final AttributeKey<String> AWS_STATE_MACHINE_ARN =
57+
AttributeKey.stringKey("aws.stepfunctions.state_machine.arn");
58+
59+
static final AttributeKey<String> AWS_STEP_FUNCTIONS_ACTIVITY_ARN =
60+
AttributeKey.stringKey("aws.stepfunctions.activity.arn");
61+
62+
static final AttributeKey<String> AWS_SNS_TOPIC_ARN = AttributeKey.stringKey("aws.sns.topic.arn");
63+
64+
static final AttributeKey<String> AWS_SECRET_ARN =
65+
AttributeKey.stringKey("aws.secretsmanager.secret.arn");
66+
67+
static final AttributeKey<String> AWS_LAMBDA_NAME =
68+
AttributeKey.stringKey("aws.lambda.function.name");
69+
70+
static final AttributeKey<String> AWS_LAMBDA_ARN =
71+
AttributeKey.stringKey("aws.lambda.function.arn");
72+
73+
static final AttributeKey<String> AWS_LAMBDA_RESOURCE_ID =
74+
AttributeKey.stringKey("aws.lambda.resource_mapping.id");
75+
5376
// use the same AWS Resource attribute name defined by OTel java auto-instr for aws_sdk_v_1_1
5477
// TODO: all AWS specific attributes should be defined in semconv package and reused cross all
5578
// otel packages. Related sim -

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsMetricAttributeGenerator.java

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,12 @@
4242
import static io.opentelemetry.semconv.SemanticAttributes.SERVER_SOCKET_PORT;
4343
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_AGENT_ID;
4444
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_BUCKET_NAME;
45+
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER;
4546
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_DATA_SOURCE_ID;
4647
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_GUARDRAIL_ID;
4748
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_KNOWLEDGE_BASE_ID;
49+
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LAMBDA_NAME;
50+
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LAMBDA_RESOURCE_ID;
4851
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_OPERATION;
4952
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_SERVICE;
5053
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_QUEUE_NAME;
@@ -54,7 +57,11 @@
5457
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_RESOURCE_IDENTIFIER;
5558
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_RESOURCE_TYPE;
5659
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_REMOTE_SERVICE;
60+
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SECRET_ARN;
61+
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SNS_TOPIC_ARN;
5762
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_SPAN_KIND;
63+
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_STATE_MACHINE_ARN;
64+
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_STEP_FUNCTIONS_ACTIVITY_ARN;
5865
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_STREAM_NAME;
5966
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_TABLE_NAME;
6067
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.GEN_AI_REQUEST_MODEL;
@@ -67,6 +74,7 @@
6774
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isDBSpan;
6875
import static software.amazon.opentelemetry.javaagent.providers.AwsSpanProcessingUtil.isKeyPresent;
6976

77+
import com.amazonaws.arn.Arn;
7078
import io.opentelemetry.api.common.AttributeKey;
7179
import io.opentelemetry.api.common.Attributes;
7280
import io.opentelemetry.api.common.AttributesBuilder;
@@ -111,6 +119,10 @@ final class AwsMetricAttributeGenerator implements MetricAttributeGenerator {
111119
private static final String NORMALIZED_SQS_SERVICE_NAME = "AWS::SQS";
112120
private static final String NORMALIZED_BEDROCK_SERVICE_NAME = "AWS::Bedrock";
113121
private static final String NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME = "AWS::BedrockRuntime";
122+
private static final String NORMALIZED_STEPFUNCTIONS_SERVICE_NAME = "AWS::StepFunctions";
123+
private static final String NORMALIZED_SNS_SERVICE_NAME = "AWS::SNS";
124+
private static final String NORMALIZED_SECRETSMANAGER_SERVICE_NAME = "AWS::SecretsManager";
125+
private static final String NORMALIZED_LAMBDA_SERVICE_NAME = "AWS::Lambda";
114126

115127
// Special DEPENDENCY attribute value if GRAPHQL_OPERATION_TYPE attribute key is present.
116128
private static final String GRAPHQL = "graphql";
@@ -371,6 +383,18 @@ private static String normalizeRemoteServiceName(SpanData span, String serviceNa
371383
case "AmazonBedrockRuntime": // AWS SDK v1
372384
case "BedrockRuntime": // AWS SDK v2
373385
return NORMALIZED_BEDROCK_RUNTIME_SERVICE_NAME;
386+
case "AWSStepFunctions": // AWS SDK v1
387+
case "Sfn": // AWS SDK v2
388+
return NORMALIZED_STEPFUNCTIONS_SERVICE_NAME;
389+
case "AmazonSNS":
390+
case "Sns":
391+
return NORMALIZED_SNS_SERVICE_NAME;
392+
case "AWSSecretsManager": // AWS SDK v1
393+
case "SecretsManager": // AWS SDK v2
394+
return NORMALIZED_SECRETSMANAGER_SERVICE_NAME;
395+
case "AWSLambda": // AWS SDK v1
396+
case "Lambda": // AWS SDK v2
397+
return NORMALIZED_LAMBDA_SERVICE_NAME;
374398
default:
375399
return "AWS::" + serviceName;
376400
}
@@ -392,6 +416,7 @@ private static String normalizeRemoteServiceName(SpanData span, String serviceNa
392416
private static void setRemoteResourceTypeAndIdentifier(SpanData span, AttributesBuilder builder) {
393417
Optional<String> remoteResourceType = Optional.empty();
394418
Optional<String> remoteResourceIdentifier = Optional.empty();
419+
Optional<String> cloudformationPrimaryIdentifier = Optional.empty();
395420

396421
if (isAwsSDKSpan(span)) {
397422
if (isKeyPresent(span, AWS_TABLE_NAME)) {
@@ -434,18 +459,88 @@ private static void setRemoteResourceTypeAndIdentifier(SpanData span, Attributes
434459
remoteResourceType = Optional.of(NORMALIZED_BEDROCK_SERVICE_NAME + "::Model");
435460
remoteResourceIdentifier =
436461
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(GEN_AI_REQUEST_MODEL)));
462+
} else if (isKeyPresent(span, AWS_STATE_MACHINE_ARN)) {
463+
remoteResourceType = Optional.of(NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + "::StateMachine");
464+
remoteResourceIdentifier =
465+
getSfnResourceNameFromArn(
466+
Optional.ofNullable(
467+
escapeDelimiters(span.getAttributes().get(AWS_STATE_MACHINE_ARN))));
468+
cloudformationPrimaryIdentifier =
469+
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_STATE_MACHINE_ARN)));
470+
} else if (isKeyPresent(span, AWS_STEP_FUNCTIONS_ACTIVITY_ARN)) {
471+
remoteResourceType = Optional.of(NORMALIZED_STEPFUNCTIONS_SERVICE_NAME + "::Activity");
472+
remoteResourceIdentifier =
473+
getSfnResourceNameFromArn(
474+
Optional.ofNullable(
475+
escapeDelimiters(span.getAttributes().get(AWS_STEP_FUNCTIONS_ACTIVITY_ARN))));
476+
cloudformationPrimaryIdentifier =
477+
Optional.ofNullable(
478+
escapeDelimiters(span.getAttributes().get(AWS_STEP_FUNCTIONS_ACTIVITY_ARN)));
479+
} else if (isKeyPresent(span, AWS_SNS_TOPIC_ARN)) {
480+
remoteResourceType = Optional.of(NORMALIZED_SNS_SERVICE_NAME + "::Topic");
481+
remoteResourceIdentifier =
482+
getSnsResourceNameFromArn(
483+
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_SNS_TOPIC_ARN))));
484+
cloudformationPrimaryIdentifier =
485+
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_SNS_TOPIC_ARN)));
486+
} else if (isKeyPresent(span, AWS_SECRET_ARN)) {
487+
remoteResourceType = Optional.of(NORMALIZED_SECRETSMANAGER_SERVICE_NAME + "::Secret");
488+
remoteResourceIdentifier =
489+
getSecretsManagerResourceNameFromArn(
490+
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_SECRET_ARN))));
491+
cloudformationPrimaryIdentifier =
492+
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_SECRET_ARN)));
493+
} else if (isKeyPresent(span, AWS_LAMBDA_NAME)) {
494+
remoteResourceType = Optional.of(NORMALIZED_LAMBDA_SERVICE_NAME + "::Function");
495+
remoteResourceIdentifier =
496+
getLambdaResourceNameFromAribitraryName(
497+
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_LAMBDA_NAME))));
498+
} else if (isKeyPresent(span, AWS_LAMBDA_RESOURCE_ID)) {
499+
remoteResourceType = Optional.of(NORMALIZED_LAMBDA_SERVICE_NAME + "::EventSourceMapping");
500+
remoteResourceIdentifier =
501+
Optional.ofNullable(escapeDelimiters(span.getAttributes().get(AWS_LAMBDA_RESOURCE_ID)));
437502
}
438503
} else if (isDBSpan(span)) {
439504
remoteResourceType = Optional.of(DB_CONNECTION_RESOURCE_TYPE);
440505
remoteResourceIdentifier = getDbConnection(span);
441506
}
442507

508+
if (cloudformationPrimaryIdentifier.isEmpty()) {
509+
cloudformationPrimaryIdentifier = remoteResourceIdentifier;
510+
}
511+
443512
if (remoteResourceType.isPresent() && remoteResourceIdentifier.isPresent()) {
444513
builder.put(AWS_REMOTE_RESOURCE_TYPE, remoteResourceType.get());
445514
builder.put(AWS_REMOTE_RESOURCE_IDENTIFIER, remoteResourceIdentifier.get());
515+
builder.put(AWS_CLOUDFORMATION_PRIMARY_IDENTIFIER, cloudformationPrimaryIdentifier.get());
446516
}
447517
}
448518

519+
// NOTE: "name" in this case can be either the lambda name or lambda arn
520+
private static Optional<String> getLambdaResourceNameFromAribitraryName(
521+
Optional<String> arbitraryName) {
522+
if (arbitraryName != null && arbitraryName.get().startsWith("arn:aws:lambda:")) {
523+
Arn resourceArn = Arn.fromString(arbitraryName.get());
524+
return Optional.of(resourceArn.getResource().toString().split(":")[1]);
525+
}
526+
return arbitraryName;
527+
}
528+
529+
private static Optional<String> getSecretsManagerResourceNameFromArn(Optional<String> stringArn) {
530+
Arn resourceArn = Arn.fromString(stringArn.get());
531+
return Optional.of(resourceArn.getResource().toString().split(":")[1]);
532+
}
533+
534+
private static Optional<String> getSfnResourceNameFromArn(Optional<String> stringArn) {
535+
Arn resourceArn = Arn.fromString(stringArn.get());
536+
return Optional.of(resourceArn.getResource().toString().split(":")[1]);
537+
}
538+
539+
private static Optional<String> getSnsResourceNameFromArn(Optional<String> stringArn) {
540+
Arn resourceArn = Arn.fromString(stringArn.get());
541+
return Optional.of(resourceArn.getResource().toString());
542+
}
543+
449544
/**
450545
* RemoteResourceIdentifier is populated with rule <code>
451546
* ^[{db.name}|]?{address}[|{port}]?

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessor.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
import io.opentelemetry.api.metrics.LongHistogram;
2323
import io.opentelemetry.api.trace.StatusCode;
2424
import io.opentelemetry.context.Context;
25+
import io.opentelemetry.sdk.common.CompletableResultCode;
2526
import io.opentelemetry.sdk.resources.Resource;
2627
import io.opentelemetry.sdk.trace.ReadWriteSpan;
2728
import io.opentelemetry.sdk.trace.ReadableSpan;
2829
import io.opentelemetry.sdk.trace.SpanProcessor;
2930
import io.opentelemetry.sdk.trace.data.SpanData;
3031
import java.util.Map;
32+
import java.util.function.Supplier;
3133
import javax.annotation.concurrent.Immutable;
3234

3335
/**
@@ -64,29 +66,38 @@ public final class AwsSpanMetricsProcessor implements SpanProcessor {
6466

6567
private final MetricAttributeGenerator generator;
6668
private final Resource resource;
69+
private final Supplier<CompletableResultCode> forceFlushAction;
6770

6871
/** Use {@link AwsSpanMetricsProcessorBuilder} to construct this processor. */
6972
static AwsSpanMetricsProcessor create(
7073
LongHistogram errorHistogram,
7174
LongHistogram faultHistogram,
7275
DoubleHistogram latencyHistogram,
7376
MetricAttributeGenerator generator,
74-
Resource resource) {
77+
Resource resource,
78+
Supplier<CompletableResultCode> forceFlushAction) {
7579
return new AwsSpanMetricsProcessor(
76-
errorHistogram, faultHistogram, latencyHistogram, generator, resource);
80+
errorHistogram, faultHistogram, latencyHistogram, generator, resource, forceFlushAction);
7781
}
7882

7983
private AwsSpanMetricsProcessor(
8084
LongHistogram errorHistogram,
8185
LongHistogram faultHistogram,
8286
DoubleHistogram latencyHistogram,
8387
MetricAttributeGenerator generator,
84-
Resource resource) {
88+
Resource resource,
89+
Supplier<CompletableResultCode> forceFlushAction) {
8590
this.errorHistogram = errorHistogram;
8691
this.faultHistogram = faultHistogram;
8792
this.latencyHistogram = latencyHistogram;
8893
this.generator = generator;
8994
this.resource = resource;
95+
this.forceFlushAction = forceFlushAction;
96+
}
97+
98+
@Override
99+
public CompletableResultCode forceFlush() {
100+
return forceFlushAction.get();
90101
}
91102

92103
@Override

awsagentprovider/src/main/java/software/amazon/opentelemetry/javaagent/providers/AwsSpanMetricsProcessorBuilder.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import io.opentelemetry.api.metrics.LongHistogram;
2323
import io.opentelemetry.api.metrics.Meter;
2424
import io.opentelemetry.api.metrics.MeterProvider;
25+
import io.opentelemetry.sdk.common.CompletableResultCode;
2526
import io.opentelemetry.sdk.resources.Resource;
27+
import java.util.function.Supplier;
2628

2729
/** A builder for {@link AwsSpanMetricsProcessor} */
2830
public final class AwsSpanMetricsProcessorBuilder {
@@ -42,18 +44,29 @@ public final class AwsSpanMetricsProcessorBuilder {
4244
private final MeterProvider meterProvider;
4345
private final Resource resource;
4446

47+
// ForceFlush action provided from {@link SdkMeterProvider#forceFlush()} so that when the
48+
// application exits The spanMetricProcessor calls the meterProvder.forceFlush to flush
49+
// any remaining metrics before shutdown
50+
private final Supplier<CompletableResultCode> forceFlushAction;
51+
4552
// Optional builder elements
4653
private MetricAttributeGenerator generator = DEFAULT_GENERATOR;
4754
private String scopeName = DEFAULT_SCOPE_NAME;
4855

4956
public static AwsSpanMetricsProcessorBuilder create(
50-
MeterProvider meterProvider, Resource resource) {
51-
return new AwsSpanMetricsProcessorBuilder(meterProvider, resource);
57+
MeterProvider meterProvider,
58+
Resource resource,
59+
Supplier<CompletableResultCode> forceFlushAction) {
60+
return new AwsSpanMetricsProcessorBuilder(meterProvider, resource, forceFlushAction);
5261
}
5362

54-
private AwsSpanMetricsProcessorBuilder(MeterProvider meterProvider, Resource resource) {
63+
private AwsSpanMetricsProcessorBuilder(
64+
MeterProvider meterProvider,
65+
Resource resource,
66+
Supplier<CompletableResultCode> forceFlushAction) {
5567
this.meterProvider = meterProvider;
5668
this.resource = resource;
69+
this.forceFlushAction = forceFlushAction;
5770
}
5871

5972
/**
@@ -86,6 +99,6 @@ public AwsSpanMetricsProcessor build() {
8699
meter.histogramBuilder(LATENCY).setUnit(LATENCY_UNITS).build();
87100

88101
return AwsSpanMetricsProcessor.create(
89-
errorHistogram, faultHistogram, latencyHistogram, generator, resource);
102+
errorHistogram, faultHistogram, latencyHistogram, generator, resource, forceFlushAction);
90103
}
91104
}

0 commit comments

Comments
 (0)