20
20
import io .opentelemetry .contrib .awsxray .AlwaysRecordSampler ;
21
21
import io .opentelemetry .contrib .awsxray .ResourceHolder ;
22
22
import io .opentelemetry .exporter .otlp .http .metrics .OtlpHttpMetricExporter ;
23
+ import io .opentelemetry .exporter .otlp .http .trace .OtlpHttpSpanExporter ;
23
24
import io .opentelemetry .exporter .otlp .internal .OtlpConfigUtil ;
24
25
import io .opentelemetry .exporter .otlp .metrics .OtlpGrpcMetricExporter ;
26
+ import io .opentelemetry .exporter .otlp .trace .OtlpGrpcSpanExporter ;
25
27
import io .opentelemetry .sdk .autoconfigure .spi .AutoConfigurationCustomizer ;
26
28
import io .opentelemetry .sdk .autoconfigure .spi .AutoConfigurationCustomizerProvider ;
27
29
import io .opentelemetry .sdk .autoconfigure .spi .ConfigProperties ;
45
47
import java .util .HashSet ;
46
48
import java .util .List ;
47
49
import java .util .Map ;
50
+ import java .util .Optional ;
48
51
import java .util .Set ;
49
52
import java .util .logging .Level ;
50
53
import java .util .logging .Logger ;
66
69
*/
67
70
public class AwsApplicationSignalsCustomizerProvider
68
71
implements AutoConfigurationCustomizerProvider {
72
+ static final String AWS_LAMBDA_FUNCTION_NAME_CONFIG = "AWS_LAMBDA_FUNCTION_NAME" ;
73
+
69
74
private static final Duration DEFAULT_METRIC_EXPORT_INTERVAL = Duration .ofMinutes (1 );
70
75
private static final Logger logger =
71
76
Logger .getLogger (AwsApplicationSignalsCustomizerProvider .class .getName ());
@@ -85,16 +90,34 @@ public class AwsApplicationSignalsCustomizerProvider
85
90
"otel.aws.application.signals.exporter.endpoint" ;
86
91
87
92
private static final String OTEL_JMX_TARGET_SYSTEM_CONFIG = "otel.jmx.target.system" ;
93
+ private static final String OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG =
94
+ "OTEL_EXPORTER_OTLP_TRACES_ENDPOINT" ;
95
+ private static final String AWS_XRAY_DAEMON_ADDRESS_CONFIG = "AWS_XRAY_DAEMON_ADDRESS" ;
96
+ private static final String DEFAULT_UDP_ENDPOINT = "127.0.0.1:2000" ;
97
+ private static final String OTEL_DISABLED_RESOURCE_PROVIDERS_CONFIG =
98
+ "otel.java.disabled.resource.providers" ;
99
+ private static final String OTEL_BSP_MAX_EXPORT_BATCH_SIZE_CONFIG =
100
+ "otel.bsp.max.export.batch.size" ;
101
+
102
+ // UDP packet can be upto 64KB. To limit the packet size, we limit the exported batch size.
103
+ // This is a bit of a magic number, as there is no simple way to tell how many spans can make a
104
+ // 64KB batch since spans can vary in size.
105
+ private static final int LAMBDA_SPAN_EXPORT_BATCH_SIZE = 10 ;
88
106
89
107
public void customize (AutoConfigurationCustomizer autoConfiguration ) {
90
108
autoConfiguration .addPropertiesCustomizer (this ::customizeProperties );
109
+ autoConfiguration .addPropertiesCustomizer (this ::customizeLambdaEnvProperties );
91
110
autoConfiguration .addResourceCustomizer (this ::customizeResource );
92
111
autoConfiguration .addSamplerCustomizer (this ::customizeSampler );
93
112
autoConfiguration .addTracerProviderCustomizer (this ::customizeTracerProviderBuilder );
94
113
autoConfiguration .addMeterProviderCustomizer (this ::customizeMeterProvider );
95
114
autoConfiguration .addSpanExporterCustomizer (this ::customizeSpanExporter );
96
115
}
97
116
117
+ static boolean isLambdaEnvironment () {
118
+ return System .getenv (AWS_LAMBDA_FUNCTION_NAME_CONFIG ) != null ;
119
+ }
120
+
98
121
private boolean isApplicationSignalsEnabled (ConfigProperties configProps ) {
99
122
return configProps .getBoolean (
100
123
APPLICATION_SIGNALS_ENABLED_CONFIG ,
@@ -126,6 +149,30 @@ private Map<String, String> customizeProperties(ConfigProperties configProps) {
126
149
return Collections .emptyMap ();
127
150
}
128
151
152
+ private Map <String , String > customizeLambdaEnvProperties (ConfigProperties configProperties ) {
153
+ if (isLambdaEnvironment ()) {
154
+ Map <String , String > propsOverride = new HashMap <>(2 );
155
+
156
+ // Disable other AWS Resource Providers
157
+ List <String > list = configProperties .getList (OTEL_DISABLED_RESOURCE_PROVIDERS_CONFIG );
158
+ List <String > disabledResourceProviders = new ArrayList <>(list );
159
+ disabledResourceProviders .add (
160
+ "io.opentelemetry.contrib.aws.resource.BeanstalkResourceProvider" );
161
+ disabledResourceProviders .add ("io.opentelemetry.contrib.aws.resource.Ec2ResourceProvider" );
162
+ disabledResourceProviders .add ("io.opentelemetry.contrib.aws.resource.EcsResourceProvider" );
163
+ disabledResourceProviders .add ("io.opentelemetry.contrib.aws.resource.EksResourceProvider" );
164
+ propsOverride .put (
165
+ OTEL_DISABLED_RESOURCE_PROVIDERS_CONFIG , String .join ("," , disabledResourceProviders ));
166
+
167
+ // Set the max export batch size for BatchSpanProcessors
168
+ propsOverride .put (
169
+ OTEL_BSP_MAX_EXPORT_BATCH_SIZE_CONFIG , String .valueOf (LAMBDA_SPAN_EXPORT_BATCH_SIZE ));
170
+
171
+ return propsOverride ;
172
+ }
173
+ return Collections .emptyMap ();
174
+ }
175
+
129
176
private Resource customizeResource (Resource resource , ConfigProperties configProps ) {
130
177
if (isApplicationSignalsEnabled (configProps )) {
131
178
AttributesBuilder builder = Attributes .builder ();
@@ -156,6 +203,17 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
156
203
// Construct and set local and remote attributes span processor
157
204
tracerProviderBuilder .addSpanProcessor (
158
205
AttributePropagatingSpanProcessorBuilder .create ().build ());
206
+
207
+ // If running on Lambda, we just need to export 100% spans and skip generating any Application
208
+ // Signals metrics.
209
+ if (isLambdaEnvironment ()) {
210
+ tracerProviderBuilder .addSpanProcessor (
211
+ AwsUnsampledOnlySpanProcessorBuilder .create ()
212
+ .setMaxExportBatchSize (LAMBDA_SPAN_EXPORT_BATCH_SIZE )
213
+ .build ());
214
+ return tracerProviderBuilder ;
215
+ }
216
+
159
217
// Construct meterProvider
160
218
MetricExporter metricsExporter =
161
219
ApplicationSignalsExporterProvider .INSTANCE .createExporter (configProps );
@@ -207,6 +265,21 @@ private SdkMeterProviderBuilder customizeMeterProvider(
207
265
208
266
private SpanExporter customizeSpanExporter (
209
267
SpanExporter spanExporter , ConfigProperties configProps ) {
268
+ // When running in Lambda, override the default OTLP exporter with UDP exporter
269
+ if (isLambdaEnvironment ()) {
270
+ if (isOtlpSpanExporter (spanExporter )
271
+ && System .getenv (OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG ) == null ) {
272
+ String tracesEndpoint =
273
+ Optional .ofNullable (System .getenv (AWS_XRAY_DAEMON_ADDRESS_CONFIG ))
274
+ .orElse (DEFAULT_UDP_ENDPOINT );
275
+ spanExporter =
276
+ new OtlpUdpSpanExporterBuilder ()
277
+ .setPayloadSampleDecision (TracePayloadSampleDecision .SAMPLED )
278
+ .setEndpoint (tracesEndpoint )
279
+ .build ();
280
+ }
281
+ }
282
+
210
283
if (isApplicationSignalsEnabled (configProps )) {
211
284
return AwsMetricAttributesSpanExporterBuilder .create (
212
285
spanExporter , ResourceHolder .getResource ())
@@ -216,6 +289,11 @@ private SpanExporter customizeSpanExporter(
216
289
return spanExporter ;
217
290
}
218
291
292
+ private boolean isOtlpSpanExporter (SpanExporter spanExporter ) {
293
+ return spanExporter instanceof OtlpGrpcSpanExporter
294
+ || spanExporter instanceof OtlpHttpSpanExporter ;
295
+ }
296
+
219
297
private enum ApplicationSignalsExporterProvider {
220
298
INSTANCE ;
221
299
0 commit comments