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,73 @@ 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.app.signals.exporter.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 isApplicationSignalsEnabled (configProps )
112+ && configProps .getBoolean (APPLICATION_SIGNALS_RUNTIME_ENABLED_CONFIG , true );
113+ }
114+
115+ private Map <String , String > customizeProperties (ConfigProperties configProps ) {
116+ if (isApplicationSignalsRuntimeEnabled (configProps )) {
117+ List <String > list = configProps .getList (OTEL_JMX_TARGET_SYSTEM_CONFIG );
118+ if (list .contains ("jvm" )) {
119+ logger .log (Level .INFO , "Found jmx in {0}" , OTEL_JMX_TARGET_SYSTEM_CONFIG );
120+ return Collections .emptyMap ();
121+ } else {
122+ logger .log (Level .INFO , "Configure jmx in {0}" , OTEL_JMX_TARGET_SYSTEM_CONFIG );
123+ List <String > jmxTargets = new ArrayList <>(list );
124+ jmxTargets .add ("jvm" );
125+ Map <String , String > propsOverride = new HashMap <>(1 );
126+ propsOverride .put (OTEL_JMX_TARGET_SYSTEM_CONFIG , String .join ("," , jmxTargets ));
127+ return propsOverride ;
128+ }
129+ }
130+ return Collections .emptyMap ();
131+ }
132+
133+ private Resource customizeResource (Resource resource , ConfigProperties configProps ) {
134+ if (isApplicationSignalsEnabled (configProps )) {
135+ AttributesBuilder builder = Attributes .builder ();
136+ AwsResourceAttributeConfigurator .setServiceAttribute (
137+ resource ,
138+ builder ,
139+ () -> logger .log (Level .WARNING , "Service name is undefined, use UnknownService instead" ));
140+ Resource additionalResource = Resource .create ((builder .build ()));
141+ return resource .merge (additionalResource );
142+ }
143+ return resource ;
85144 }
86145
87146 private Sampler customizeSampler (Sampler sampler , ConfigProperties configProps ) {
@@ -95,20 +154,7 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
95154 SdkTracerProviderBuilder tracerProviderBuilder , ConfigProperties configProps ) {
96155 if (isApplicationSignalsEnabled (configProps )) {
97156 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- }
157+ Duration exportInterval = getMetricExportInterval (configProps );
112158 // Construct and set local and remote attributes span processor
113159 tracerProviderBuilder .addSpanProcessor (
114160 AttributePropagatingSpanProcessorBuilder .create ().build ());
@@ -133,6 +179,67 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
133179 return tracerProviderBuilder ;
134180 }
135181
182+ private SdkMeterProviderBuilder customizeMeterProvider (
183+ SdkMeterProviderBuilder sdkMeterProviderBuilder , ConfigProperties configProps ) {
184+
185+ if (isApplicationSignalsRuntimeEnabled (configProps )) {
186+ Set <String > registeredScopeNames = new HashSet <>(1 );
187+ String jmxRuntimeScopeName = "io.opentelemetry.jmx" ;
188+ registeredScopeNames .add (jmxRuntimeScopeName );
189+
190+ configureMetricFilter (configProps , sdkMeterProviderBuilder , registeredScopeNames );
191+
192+ MetricExporter metricsExporter =
193+ ApplicationSignalsExporterProvider .INSTANCE .createExporter (configProps );
194+ MetricReader metricReader =
195+ ScopeBasedPeriodicMetricReader .create (metricsExporter , registeredScopeNames )
196+ .setInterval (getMetricExportInterval (configProps ))
197+ .build ();
198+ sdkMeterProviderBuilder .registerMetricReader (metricReader );
199+
200+ logger .info ("AWS Application Signals runtime metric collection enabled" );
201+ }
202+ return sdkMeterProviderBuilder ;
203+ }
204+
205+ private static void configureMetricFilter (
206+ ConfigProperties configProps ,
207+ SdkMeterProviderBuilder sdkMeterProviderBuilder ,
208+ Set <String > registeredScopeNames ) {
209+ Set <String > exporterNames =
210+ DefaultConfigProperties .getSet (configProps , "otel.metrics.exporter" );
211+ if (exporterNames .contains ("none" )) {
212+ for (String scope : registeredScopeNames ) {
213+ sdkMeterProviderBuilder .registerView (
214+ InstrumentSelector .builder ().setMeterName (scope ).build (),
215+ View .builder ().setAggregation (Aggregation .defaultAggregation ()).build ());
216+
217+ logger .log (Level .FINE , "Registered scope {0}" , scope );
218+ }
219+ sdkMeterProviderBuilder .registerView (
220+ InstrumentSelector .builder ().setName ("*" ).build (),
221+ View .builder ().setAggregation (Aggregation .drop ()).build ());
222+ }
223+ }
224+
225+ private static Duration getMetricExportInterval (ConfigProperties configProps ) {
226+ Duration exportInterval =
227+ configProps .getDuration ("otel.metric.export.interval" , DEFAULT_METRIC_EXPORT_INTERVAL );
228+ logger .log (
229+ Level .FINE ,
230+ String .format ("AWS Application Signals Metrics export interval: %s" , exportInterval ));
231+ // Cap export interval to 60 seconds. This is currently required for metrics-trace correlation
232+ // to work correctly.
233+ if (exportInterval .compareTo (DEFAULT_METRIC_EXPORT_INTERVAL ) > 0 ) {
234+ exportInterval = DEFAULT_METRIC_EXPORT_INTERVAL ;
235+ logger .log (
236+ Level .INFO ,
237+ String .format (
238+ "AWS Application Signals metrics export interval capped to %s" , exportInterval ));
239+ }
240+ return exportInterval ;
241+ }
242+
136243 private SpanExporter customizeSpanExporter (
137244 SpanExporter spanExporter , ConfigProperties configProps ) {
138245 if (isApplicationSignalsEnabled (configProps )) {
@@ -159,33 +266,35 @@ public MetricExporter createExporter(ConfigProperties configProps) {
159266 configProps .getString (
160267 APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
161268 configProps .getString (
162- APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
269+ DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
163270 configProps .getString (
164- SMP_EXPORTER_ENDPOINT_CONFIG , "http://localhost:4316/v1/metrics" )));
271+ DEPRECATED_SMP_EXPORTER_ENDPOINT_CONFIG ,
272+ "http://localhost:4316/v1/metrics" )));
165273 logger .log (
166274 Level .FINE ,
167275 String .format (
168276 "AWS Application Signals export endpoint: %s" , applicationSignalsEndpoint ));
169277 return OtlpHttpMetricExporter .builder ()
170278 .setEndpoint (applicationSignalsEndpoint )
171279 .setDefaultAggregationSelector (this ::getAggregation )
172- .setAggregationTemporalitySelector (AggregationTemporalitySelector . deltaPreferred ())
280+ .setAggregationTemporalitySelector (CloudWatchTemporalitySelector . alwaysDelta ())
173281 .build ();
174282 } else if (protocol .equals (OtlpConfigUtil .PROTOCOL_GRPC )) {
175283 applicationSignalsEndpoint =
176284 configProps .getString (
177285 APPLICATION_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
178286 configProps .getString (
179- APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
180- configProps .getString (SMP_EXPORTER_ENDPOINT_CONFIG , "http://localhost:4315" )));
287+ DEPRECATED_APP_SIGNALS_EXPORTER_ENDPOINT_CONFIG ,
288+ configProps .getString (
289+ DEPRECATED_SMP_EXPORTER_ENDPOINT_CONFIG , "http://localhost:4315" )));
181290 logger .log (
182291 Level .FINE ,
183292 String .format (
184293 "AWS Application Signals export endpoint: %s" , applicationSignalsEndpoint ));
185294 return OtlpGrpcMetricExporter .builder ()
186295 .setEndpoint (applicationSignalsEndpoint )
187296 .setDefaultAggregationSelector (this ::getAggregation )
188- .setAggregationTemporalitySelector (AggregationTemporalitySelector . deltaPreferred ())
297+ .setAggregationTemporalitySelector (CloudWatchTemporalitySelector . alwaysDelta ())
189298 .build ();
190299 }
191300 throw new ConfigurationException (
0 commit comments