Skip to content

Commit

Permalink
Metric Schema and config name changes
Browse files Browse the repository at this point in the history
In this commit, we are removing RemoteTarget and replacing with RemoteResourceIdentifier and RemoteResourceType. Further, we are formatting RemoteService, and the content of the RemoteResource attributes such that they align with AWS Cloud Control resource names.

In addition to these changes, we are modifying the code and config names used for enabling and configuring Application Signals to use the full feature name, "application.signals"/"Application Signals".

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
  • Loading branch information
thpierce authored May 9, 2024
2 parents a7d7adf + b61037f commit e452352
Show file tree
Hide file tree
Showing 12 changed files with 504 additions and 501 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,6 @@ protected String getKinesisSpanNamePrefix() {
return "Kinesis";
}

@Override
protected String getS3ServiceName() {
return "AWS.SDK.Amazon S3";
}

@Override
protected String getDynamoDbServiceName() {
return "AWS.SDK.AmazonDynamoDBv2";
}

@Override
protected String getSqsServiceName() {
return "AWS.SDK.AmazonSQS";
}

@Override
protected String getKinesisServiceName() {
return "AWS.SDK.AmazonKinesis";
}

protected String getS3RpcServiceName() {
return "Amazon S3";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,6 @@ protected String getKinesisSpanNamePrefix() {
return "Kinesis";
}

@Override
protected String getS3ServiceName() {
return "AWS.SDK.S3";
}

@Override
protected String getDynamoDbServiceName() {
return "AWS.SDK.DynamoDb";
}

@Override
protected String getSqsServiceName() {
return "AWS.SDK.Sqs";
}

protected String getKinesisServiceName() {
return "AWS.SDK.Kinesis";
}

@Override
protected String getS3RpcServiceName() {
return "S3";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ public abstract class ContractTestBase {
.waitingFor(getApplicationWaitCondition())
.withEnv("JAVA_TOOL_OPTIONS", "-javaagent:/opentelemetry-javaagent-all.jar")
.withEnv("OTEL_METRIC_EXPORT_INTERVAL", "100") // 100 ms
.withEnv("OTEL_AWS_APP_SIGNALS_ENABLED", "true")
.withEnv("OTEL_AWS_APPLICATION_SIGNALS_ENABLED", "true")
.withEnv("OTEL_METRICS_EXPORTER", "none")
.withEnv("OTEL_BSP_SCHEDULE_DELAY", "0") // Don't wait to export spans to the collector
.withEnv(
"OTEL_AWS_APP_SIGNALS_EXPORTER_ENDPOINT",
"OTEL_AWS_APPLICATION_SIGNALS_EXPORTER_ENDPOINT",
"http://" + COLLECTOR_HOSTNAME + ":" + COLLECTOR_PORT)
.withEnv(
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class AppSignalsConstants {
public static final String AWS_LOCAL_OPERATION = "aws.local.operation";
public static final String AWS_REMOTE_SERVICE = "aws.remote.service";
public static final String AWS_REMOTE_OPERATION = "aws.remote.operation";
public static final String AWS_REMOTE_TARGET = "aws.remote.target";
public static final String AWS_REMOTE_RESOURCE_TYPE = "aws.remote.resource.type";
public static final String AWS_REMOTE_RESOURCE_IDENTIFIER = "aws.remote.resource.identifier";
public static final String AWS_SPAN_KIND = "aws.span.kind";
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,54 +52,69 @@
* </ul>
*
* <p>You can control when these customizations are applied using the property
* otel.aws.app.signals.enabled or the environment variable OTEL_AWS_APP_SIGNALS_ENABLED. This flag
* is disabled by default.
* otel.aws.application.signals.enabled or the environment variable
* OTEL_AWS_APPLICATION_SIGNALS_ENABLED. This flag is disabled by default.
*/
public class AwsAppSignalsCustomizerProvider implements AutoConfigurationCustomizerProvider {
public class AwsApplicationSignalsCustomizerProvider
implements AutoConfigurationCustomizerProvider {
private static final Duration DEFAULT_METRIC_EXPORT_INTERVAL = Duration.ofMinutes(1);
private static final Logger logger =
Logger.getLogger(AwsAppSignalsCustomizerProvider.class.getName());
Logger.getLogger(AwsApplicationSignalsCustomizerProvider.class.getName());

private static final String SMP_ENABLED_CONFIG = "otel.smp.enabled";
private static final String APP_SIGNALS_ENABLED_CONFIG = "otel.aws.app.signals.enabled";
private static final String APPLICATION_SIGNALS_ENABLED_CONFIG =
"otel.aws.application.signals.enabled";
private static final String SMP_EXPORTER_ENDPOINT_CONFIG = "otel.aws.smp.exporter.endpoint";
private static final String APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG =
"otel.aws.app.signals.exporter.endpoint";
private static final String APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG =
"otel.aws.application.signals.exporter.endpoint";

public void customize(AutoConfigurationCustomizer autoConfiguration) {
autoConfiguration.addSamplerCustomizer(this::customizeSampler);
autoConfiguration.addTracerProviderCustomizer(this::customizeTracerProviderBuilder);
autoConfiguration.addSpanExporterCustomizer(this::customizeSpanExporter);
}

private boolean isAppSignalsEnabled(ConfigProperties configProps) {
private boolean isApplicationSignalsEnabled(ConfigProperties configProps) {
return configProps.getBoolean(
"otel.aws.app.signals.enabled", configProps.getBoolean("otel.smp.enabled", false));
APPLICATION_SIGNALS_ENABLED_CONFIG,
configProps.getBoolean(
APP_SIGNALS_ENABLED_CONFIG, configProps.getBoolean(SMP_ENABLED_CONFIG, false)));
}

private Sampler customizeSampler(Sampler sampler, ConfigProperties configProps) {
if (isAppSignalsEnabled(configProps)) {
if (isApplicationSignalsEnabled(configProps)) {
return AlwaysRecordSampler.create(sampler);
}
return sampler;
}

private SdkTracerProviderBuilder customizeTracerProviderBuilder(
SdkTracerProviderBuilder tracerProviderBuilder, ConfigProperties configProps) {
if (isAppSignalsEnabled(configProps)) {
logger.info("AWS AppSignals enabled");
if (isApplicationSignalsEnabled(configProps)) {
logger.info("AWS Application Signals enabled");
Duration exportInterval =
configProps.getDuration("otel.metric.export.interval", DEFAULT_METRIC_EXPORT_INTERVAL);
logger.log(
Level.FINE, String.format("AppSignals Metrics export interval: %s", exportInterval));
Level.FINE,
String.format("AWS Application Signals Metrics export interval: %s", exportInterval));
// Cap export interval to 60 seconds. This is currently required for metrics-trace correlation
// to work correctly.
if (exportInterval.compareTo(DEFAULT_METRIC_EXPORT_INTERVAL) > 0) {
exportInterval = DEFAULT_METRIC_EXPORT_INTERVAL;
logger.log(
Level.INFO,
String.format("AWS AppSignals metrics export interval capped to %s", exportInterval));
String.format(
"AWS Application Signals metrics export interval capped to %s", exportInterval));
}
// Construct and set local and remote attributes span processor
tracerProviderBuilder.addSpanProcessor(
AttributePropagatingSpanProcessorBuilder.create().build());
// Construct meterProvider
MetricExporter metricsExporter =
AppSignalsExporterProvider.INSTANCE.createExporter(configProps);
ApplicationSignalsExporterProvider.INSTANCE.createExporter(configProps);

MetricReader metricReader =
PeriodicMetricReader.builder(metricsExporter).setInterval(exportInterval).build();
Expand All @@ -109,7 +124,7 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
.setResource(ResourceHolder.getResource())
.registerMetricReader(metricReader)
.build();
// Construct and set AppSignals metrics processor
// Construct and set application signals metrics processor
SpanProcessor spanMetricsProcessor =
AwsSpanMetricsProcessorBuilder.create(meterProvider, ResourceHolder.getResource())
.build();
Expand All @@ -120,7 +135,7 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(

private SpanExporter customizeSpanExporter(
SpanExporter spanExporter, ConfigProperties configProps) {
if (isAppSignalsEnabled(configProps)) {
if (isApplicationSignalsEnabled(configProps)) {
return AwsMetricAttributesSpanExporterBuilder.create(
spanExporter, ResourceHolder.getResource())
.build();
Expand All @@ -129,40 +144,52 @@ private SpanExporter customizeSpanExporter(
return spanExporter;
}

private enum AppSignalsExporterProvider {
private enum ApplicationSignalsExporterProvider {
INSTANCE;

public MetricExporter createExporter(ConfigProperties configProps) {
String protocol =
OtlpConfigUtil.getOtlpProtocol(OtlpConfigUtil.DATA_TYPE_METRICS, configProps);
logger.log(Level.FINE, String.format("AppSignals export protocol: %s", protocol));
logger.log(
Level.FINE, String.format("AWS Application Signals export protocol: %s", protocol));

String appSignalsEndpoint;
String applicationSignalsEndpoint;
if (protocol.equals(OtlpConfigUtil.PROTOCOL_HTTP_PROTOBUF)) {
appSignalsEndpoint =
applicationSignalsEndpoint =
configProps.getString(
"otel.aws.app.signals.exporter.endpoint",
APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG,
configProps.getString(
"otel.aws.smp.exporter.endpoint", "http://localhost:4316/v1/metrics"));
logger.log(Level.FINE, String.format("AppSignals export endpoint: %s", appSignalsEndpoint));
APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG,
configProps.getString(
SMP_EXPORTER_ENDPOINT_CONFIG, "http://localhost:4316/v1/metrics")));
logger.log(
Level.FINE,
String.format(
"AWS Application Signals export endpoint: %s", applicationSignalsEndpoint));
return OtlpHttpMetricExporter.builder()
.setEndpoint(appSignalsEndpoint)
.setEndpoint(applicationSignalsEndpoint)
.setDefaultAggregationSelector(this::getAggregation)
.setAggregationTemporalitySelector(AggregationTemporalitySelector.deltaPreferred())
.build();
} else if (protocol.equals(OtlpConfigUtil.PROTOCOL_GRPC)) {
appSignalsEndpoint =
applicationSignalsEndpoint =
configProps.getString(
"otel.aws.app.signals.exporter.endpoint",
configProps.getString("otel.aws.smp.exporter.endpoint", "http://localhost:4315"));
logger.log(Level.FINE, String.format("AppSignals export endpoint: %s", appSignalsEndpoint));
APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG,
configProps.getString(
APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG,
configProps.getString(SMP_EXPORTER_ENDPOINT_CONFIG, "http://localhost:4315")));
logger.log(
Level.FINE,
String.format(
"AWS Application Signals export endpoint: %s", applicationSignalsEndpoint));
return OtlpGrpcMetricExporter.builder()
.setEndpoint(appSignalsEndpoint)
.setEndpoint(applicationSignalsEndpoint)
.setDefaultAggregationSelector(this::getAggregation)
.setAggregationTemporalitySelector(AggregationTemporalitySelector.deltaPreferred())
.build();
}
throw new ConfigurationException("Unsupported AppSignals export protocol: " + protocol);
throw new ConfigurationException(
"Unsupported AWS Application Signals export protocol: " + protocol);
}

private Aggregation getAggregation(InstrumentType instrumentType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,21 +35,25 @@ private AwsAttributeKeys() {}
static final AttributeKey<String> AWS_REMOTE_OPERATION =
AttributeKey.stringKey("aws.remote.operation");

static final AttributeKey<String> AWS_REMOTE_TARGET = AttributeKey.stringKey("aws.remote.target");
static final AttributeKey<String> AWS_REMOTE_RESOURCE_IDENTIFIER =
AttributeKey.stringKey("aws.remote.resource.identifier");

static final AttributeKey<String> AWS_REMOTE_RESOURCE_TYPE =
AttributeKey.stringKey("aws.remote.resource.type");

static final AttributeKey<String> AWS_SDK_DESCENDANT =
AttributeKey.stringKey("aws.sdk.descendant");

static final AttributeKey<String> AWS_CONSUMER_PARENT_SPAN_KIND =
AttributeKey.stringKey("aws.consumer.parent.span.kind");

// use the same AWS Resource attribute name defined by OTel java auto-instr for aws_sdk_v_1_1
// TODO: all AWS specific attributes should be defined in semconv package and reused cross all
// otel packages. Related sim -
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/8710

static final AttributeKey<String> AWS_BUCKET_NAME = AttributeKey.stringKey("aws.bucket.name");
static final AttributeKey<String> AWS_QUEUE_URL = AttributeKey.stringKey("aws.queue.url");
static final AttributeKey<String> AWS_QUEUE_NAME = AttributeKey.stringKey("aws.queue.name");
static final AttributeKey<String> AWS_STREAM_NAME = AttributeKey.stringKey("aws.stream.name");
static final AttributeKey<String> AWS_TABLE_NAME = AttributeKey.stringKey("aws.table.name");
static final AttributeKey<String> AWS_CONSUMER_PARENT_SPAN_KIND =
AttributeKey.stringKey("aws.consumer.parent.span.kind");
}
Loading

0 comments on commit e452352

Please sign in to comment.