1515
1616package software .amazon .opentelemetry .javaagent .providers ;
1717
18+ import io .opentelemetry .api .common .Attributes ;
19+ import io .opentelemetry .api .common .AttributesBuilder ;
1820import io .opentelemetry .api .metrics .MeterProvider ;
1921import io .opentelemetry .contrib .awsxray .AlwaysRecordSampler ;
2022import io .opentelemetry .contrib .awsxray .ResourceHolder ;
2527import io .opentelemetry .sdk .autoconfigure .spi .AutoConfigurationCustomizerProvider ;
2628import io .opentelemetry .sdk .autoconfigure .spi .ConfigProperties ;
2729import io .opentelemetry .sdk .autoconfigure .spi .ConfigurationException ;
30+ import io .opentelemetry .sdk .autoconfigure .spi .internal .DefaultConfigProperties ;
2831import io .opentelemetry .sdk .metrics .Aggregation ;
32+ import io .opentelemetry .sdk .metrics .InstrumentSelector ;
2933import io .opentelemetry .sdk .metrics .InstrumentType ;
3034import io .opentelemetry .sdk .metrics .SdkMeterProvider ;
31- import io .opentelemetry .sdk .metrics .export .AggregationTemporalitySelector ;
35+ import io .opentelemetry .sdk .metrics .SdkMeterProviderBuilder ;
36+ import io .opentelemetry .sdk .metrics .View ;
3237import io .opentelemetry .sdk .metrics .export .MetricExporter ;
3338import io .opentelemetry .sdk .metrics .export .MetricReader ;
3439import io .opentelemetry .sdk .metrics .export .PeriodicMetricReader ;
40+ import io .opentelemetry .sdk .resources .Resource ;
3541import io .opentelemetry .sdk .trace .SdkTracerProviderBuilder ;
3642import io .opentelemetry .sdk .trace .SpanProcessor ;
3743import io .opentelemetry .sdk .trace .export .SpanExporter ;
3844import io .opentelemetry .sdk .trace .samplers .Sampler ;
3945import java .time .Duration ;
46+ import java .util .ArrayList ;
47+ import java .util .Collections ;
48+ import java .util .HashMap ;
49+ import java .util .HashSet ;
50+ import java .util .List ;
51+ import java .util .Map ;
52+ import java .util .Set ;
4053import java .util .logging .Level ;
4154import java .util .logging .Logger ;
4255
@@ -61,27 +74,72 @@ public class AwsApplicationSignalsCustomizerProvider
6174 private static final Logger logger =
6275 Logger .getLogger (AwsApplicationSignalsCustomizerProvider .class .getName ());
6376
64- private static final String SMP_ENABLED_CONFIG = "otel.smp.enabled" ;
65- private static final String APP_SIGNALS_ENABLED_CONFIG = "otel.aws.app.signals.enabled" ;
77+ private static final String DEPRECATED_SMP_ENABLED_CONFIG = "otel.smp.enabled" ;
78+ private static final String DEPRECATED_APP_SIGNALS_ENABLED_CONFIG =
79+ "otel.aws.app.signals.enabled" ;
6680 private static final String APPLICATION_SIGNALS_ENABLED_CONFIG =
6781 "otel.aws.application.signals.enabled" ;
68- private static final String SMP_EXPORTER_ENDPOINT_CONFIG = "otel.aws.smp.exporter.endpoint" ;
69- private static final String APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG =
82+ private static final String APPLICATION_SIGNALS_RUNTIME_ENABLED_CONFIG =
83+ "otel.aws.application.signals.runtime.enabled" ;
84+ private static final String DEPRECATED_SMP_EXPORTER_ENDPOINT_CONFIG =
85+ "otel.aws.smp.exporter.endpoint" ;
86+ private static final String DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG =
7087 "otel.aws.app.signals.exporter.endpoint" ;
7188 private static final String APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG =
7289 "otel.aws.application.signals.exporter.endpoint" ;
7390
91+ private static final String OTEL_JMX_TARGET_SYSTEM_CONFIG = "otel.jmx.target.system" ;
92+
7493 public void customize (AutoConfigurationCustomizer autoConfiguration ) {
94+ autoConfiguration .addPropertiesCustomizer (this ::customizeProperties );
95+ autoConfiguration .addResourceCustomizer (this ::customizeResource );
7596 autoConfiguration .addSamplerCustomizer (this ::customizeSampler );
7697 autoConfiguration .addTracerProviderCustomizer (this ::customizeTracerProviderBuilder );
98+ autoConfiguration .addMeterProviderCustomizer (this ::customizeMeterProvider );
7799 autoConfiguration .addSpanExporterCustomizer (this ::customizeSpanExporter );
78100 }
79101
80102 private boolean isApplicationSignalsEnabled (ConfigProperties configProps ) {
81103 return configProps .getBoolean (
82104 APPLICATION_SIGNALS_ENABLED_CONFIG ,
83105 configProps .getBoolean (
84- APP_SIGNALS_ENABLED_CONFIG , configProps .getBoolean (SMP_ENABLED_CONFIG , false )));
106+ DEPRECATED_APP_SIGNALS_ENABLED_CONFIG ,
107+ configProps .getBoolean (DEPRECATED_SMP_ENABLED_CONFIG , false )));
108+ }
109+
110+ private boolean isApplicationSignalsRuntimeEnabled (ConfigProperties configProps ) {
111+ return false ;
112+ }
113+
114+ private Map <String , String > customizeProperties (ConfigProperties configProps ) {
115+ if (isApplicationSignalsRuntimeEnabled (configProps )) {
116+ List <String > list = configProps .getList (OTEL_JMX_TARGET_SYSTEM_CONFIG );
117+ if (list .contains ("jvm" )) {
118+ logger .log (Level .INFO , "Found jmx in {0}" , OTEL_JMX_TARGET_SYSTEM_CONFIG );
119+ return Collections .emptyMap ();
120+ } else {
121+ logger .log (Level .INFO , "Configure jmx in {0}" , OTEL_JMX_TARGET_SYSTEM_CONFIG );
122+ List <String > jmxTargets = new ArrayList <>(list );
123+ jmxTargets .add ("jvm" );
124+ Map <String , String > propsOverride = new HashMap <>(1 );
125+ propsOverride .put (OTEL_JMX_TARGET_SYSTEM_CONFIG , String .join ("," , jmxTargets ));
126+ return propsOverride ;
127+ }
128+ }
129+ return Collections .emptyMap ();
130+ }
131+
132+ private Resource customizeResource (Resource resource , ConfigProperties configProps ) {
133+ if (isApplicationSignalsEnabled (configProps )) {
134+ AttributesBuilder builder = Attributes .builder ();
135+ AwsResourceAttributeConfigurator .setServiceAttribute (
136+ resource ,
137+ builder ,
138+ () -> logger .log (Level .WARNING , "Service name is undefined, use UnknownService instead" ));
139+ Resource additionalResource = Resource .create ((builder .build ()));
140+ return resource .merge (additionalResource );
141+ }
142+ return resource ;
85143 }
86144
87145 private Sampler customizeSampler (Sampler sampler , ConfigProperties configProps ) {
@@ -95,20 +153,7 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
95153 SdkTracerProviderBuilder tracerProviderBuilder , ConfigProperties configProps ) {
96154 if (isApplicationSignalsEnabled (configProps )) {
97155 logger .info ("AWS Application Signals enabled" );
98- Duration exportInterval =
99- configProps .getDuration ("otel.metric.export.interval" , DEFAULT_METRIC_EXPORT_INTERVAL );
100- logger .log (
101- Level .FINE ,
102- String .format ("AWS Application Signals Metrics export interval: %s" , exportInterval ));
103- // Cap export interval to 60 seconds. This is currently required for metrics-trace correlation
104- // to work correctly.
105- if (exportInterval .compareTo (DEFAULT_METRIC_EXPORT_INTERVAL ) > 0 ) {
106- exportInterval = DEFAULT_METRIC_EXPORT_INTERVAL ;
107- logger .log (
108- Level .INFO ,
109- String .format (
110- "AWS Application Signals metrics export interval capped to %s" , exportInterval ));
111- }
156+ Duration exportInterval = getMetricExportInterval (configProps );
112157 // Construct and set local and remote attributes span processor
113158 tracerProviderBuilder .addSpanProcessor (
114159 AttributePropagatingSpanProcessorBuilder .create ().build ());
@@ -133,6 +178,67 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
133178 return tracerProviderBuilder ;
134179 }
135180
181+ private SdkMeterProviderBuilder customizeMeterProvider (
182+ SdkMeterProviderBuilder sdkMeterProviderBuilder , ConfigProperties configProps ) {
183+
184+ if (isApplicationSignalsRuntimeEnabled (configProps )) {
185+ Set <String > registeredScopeNames = new HashSet <>(1 );
186+ String jmxRuntimeScopeName = "io.opentelemetry.jmx" ;
187+ registeredScopeNames .add (jmxRuntimeScopeName );
188+
189+ configureMetricFilter (configProps , sdkMeterProviderBuilder , registeredScopeNames );
190+
191+ MetricExporter metricsExporter =
192+ ApplicationSignalsExporterProvider .INSTANCE .createExporter (configProps );
193+ MetricReader metricReader =
194+ ScopeBasedPeriodicMetricReader .create (metricsExporter , registeredScopeNames )
195+ .setInterval (getMetricExportInterval (configProps ))
196+ .build ();
197+ sdkMeterProviderBuilder .registerMetricReader (metricReader );
198+
199+ logger .info ("AWS Application Signals runtime metric collection enabled" );
200+ }
201+ return sdkMeterProviderBuilder ;
202+ }
203+
204+ private static void configureMetricFilter (
205+ ConfigProperties configProps ,
206+ SdkMeterProviderBuilder sdkMeterProviderBuilder ,
207+ Set <String > registeredScopeNames ) {
208+ Set <String > exporterNames =
209+ DefaultConfigProperties .getSet (configProps , "otel.metrics.exporter" );
210+ if (exporterNames .contains ("none" )) {
211+ for (String scope : registeredScopeNames ) {
212+ sdkMeterProviderBuilder .registerView (
213+ InstrumentSelector .builder ().setMeterName (scope ).build (),
214+ View .builder ().setAggregation (Aggregation .defaultAggregation ()).build ());
215+
216+ logger .log (Level .FINE , "Registered scope {0}" , scope );
217+ }
218+ sdkMeterProviderBuilder .registerView (
219+ InstrumentSelector .builder ().setName ("*" ).build (),
220+ View .builder ().setAggregation (Aggregation .drop ()).build ());
221+ }
222+ }
223+
224+ private static Duration getMetricExportInterval (ConfigProperties configProps ) {
225+ Duration exportInterval =
226+ configProps .getDuration ("otel.metric.export.interval" , DEFAULT_METRIC_EXPORT_INTERVAL );
227+ logger .log (
228+ Level .FINE ,
229+ String .format ("AWS Application Signals Metrics export interval: %s" , exportInterval ));
230+ // Cap export interval to 60 seconds. This is currently required for metrics-trace correlation
231+ // to work correctly.
232+ if (exportInterval .compareTo (DEFAULT_METRIC_EXPORT_INTERVAL ) > 0 ) {
233+ exportInterval = DEFAULT_METRIC_EXPORT_INTERVAL ;
234+ logger .log (
235+ Level .INFO ,
236+ String .format (
237+ "AWS Application Signals metrics export interval capped to %s" , exportInterval ));
238+ }
239+ return exportInterval ;
240+ }
241+
136242 private SpanExporter customizeSpanExporter (
137243 SpanExporter spanExporter , ConfigProperties configProps ) {
138244 if (isApplicationSignalsEnabled (configProps )) {
@@ -159,33 +265,35 @@ public MetricExporter createExporter(ConfigProperties configProps) {
159265 configProps .getString (
160266 APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
161267 configProps .getString (
162- APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
268+ DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
163269 configProps .getString (
164- SMP_EXPORTER_ENDPOINT_CONFIG , "http://localhost:4316/v1/metrics" )));
270+ DEPRECATED_SMP_EXPORTER_ENDPOINT_CONFIG ,
271+ "http://localhost:4316/v1/metrics" )));
165272 logger .log (
166273 Level .FINE ,
167274 String .format (
168275 "AWS Application Signals export endpoint: %s" , applicationSignalsEndpoint ));
169276 return OtlpHttpMetricExporter .builder ()
170277 .setEndpoint (applicationSignalsEndpoint )
171278 .setDefaultAggregationSelector (this ::getAggregation )
172- .setAggregationTemporalitySelector (AggregationTemporalitySelector . deltaPreferred ())
279+ .setAggregationTemporalitySelector (CloudWatchTemporalitySelector . alwaysDelta ())
173280 .build ();
174281 } else if (protocol .equals (OtlpConfigUtil .PROTOCOL_GRPC )) {
175282 applicationSignalsEndpoint =
176283 configProps .getString (
177284 APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
178285 configProps .getString (
179- APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
180- configProps .getString (SMP_EXPORTER_ENDPOINT_CONFIG , "http://localhost:4315" )));
286+ DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
287+ configProps .getString (
288+ DEPRECATED_SMP_EXPORTER_ENDPOINT_CONFIG , "http://localhost:4315" )));
181289 logger .log (
182290 Level .FINE ,
183291 String .format (
184292 "AWS Application Signals export endpoint: %s" , applicationSignalsEndpoint ));
185293 return OtlpGrpcMetricExporter .builder ()
186294 .setEndpoint (applicationSignalsEndpoint )
187295 .setDefaultAggregationSelector (this ::getAggregation )
188- .setAggregationTemporalitySelector (AggregationTemporalitySelector . deltaPreferred ())
296+ .setAggregationTemporalitySelector (CloudWatchTemporalitySelector . alwaysDelta ())
189297 .build ();
190298 }
191299 throw new ConfigurationException (
0 commit comments