Skip to content

Commit 0cdbba5

Browse files
committed
Configure sdk for Lambda environment
1 parent 2f6490b commit 0cdbba5

File tree

5 files changed

+60
-18
lines changed

5 files changed

+60
-18
lines changed

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

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@
2020
import io.opentelemetry.contrib.awsxray.AlwaysRecordSampler;
2121
import io.opentelemetry.contrib.awsxray.ResourceHolder;
2222
import io.opentelemetry.exporter.otlp.http.metrics.OtlpHttpMetricExporter;
23+
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
2324
import io.opentelemetry.exporter.otlp.internal.OtlpConfigUtil;
2425
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
26+
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
2527
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
2628
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
2729
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
@@ -39,13 +41,7 @@
3941
import io.opentelemetry.sdk.trace.export.SpanExporter;
4042
import io.opentelemetry.sdk.trace.samplers.Sampler;
4143
import java.time.Duration;
42-
import java.util.ArrayList;
43-
import java.util.Collections;
44-
import java.util.HashMap;
45-
import java.util.HashSet;
46-
import java.util.List;
47-
import java.util.Map;
48-
import java.util.Set;
44+
import java.util.*;
4945
import java.util.logging.Level;
5046
import java.util.logging.Logger;
5147

@@ -66,6 +62,8 @@
6662
*/
6763
public class AwsApplicationSignalsCustomizerProvider
6864
implements AutoConfigurationCustomizerProvider {
65+
static final String AWS_LAMBDA_FUNCTION_NAME_CONFIG = "AWS_LAMBDA_FUNCTION_NAME";
66+
6967
private static final Duration DEFAULT_METRIC_EXPORT_INTERVAL = Duration.ofMinutes(1);
7068
private static final Logger logger =
7169
Logger.getLogger(AwsApplicationSignalsCustomizerProvider.class.getName());
@@ -85,6 +83,11 @@ public class AwsApplicationSignalsCustomizerProvider
8583
"otel.aws.application.signals.exporter.endpoint";
8684

8785
private static final String OTEL_JMX_TARGET_SYSTEM_CONFIG = "otel.jmx.target.system";
86+
private static final String OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG =
87+
"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT";
88+
private static final String AWS_XRAY_DAEMON_ADDRESS_CONFIG = "AWS_XRAY_DAEMON_ADDRESS";
89+
90+
private static final String DEFAULT_UDP_ENDPOINT = "127.0.0.1:2000";
8891

8992
public void customize(AutoConfigurationCustomizer autoConfiguration) {
9093
autoConfiguration.addPropertiesCustomizer(this::customizeProperties);
@@ -95,6 +98,10 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
9598
autoConfiguration.addSpanExporterCustomizer(this::customizeSpanExporter);
9699
}
97100

101+
static boolean isLambdaEnvironment() {
102+
return System.getenv(AWS_LAMBDA_FUNCTION_NAME_CONFIG) != null;
103+
}
104+
98105
private boolean isApplicationSignalsEnabled(ConfigProperties configProps) {
99106
return configProps.getBoolean(
100107
APPLICATION_SIGNALS_ENABLED_CONFIG,
@@ -156,6 +163,15 @@ private SdkTracerProviderBuilder customizeTracerProviderBuilder(
156163
// Construct and set local and remote attributes span processor
157164
tracerProviderBuilder.addSpanProcessor(
158165
AttributePropagatingSpanProcessorBuilder.create().build());
166+
167+
// If running on Lambda, we just need to export 100% spans and skip generating any Application
168+
// Signals metrics.
169+
if (isLambdaEnvironment()) {
170+
tracerProviderBuilder.addSpanProcessor(
171+
AwsUnsampledOnlySpanProcessorBuilder.create().build());
172+
return tracerProviderBuilder;
173+
}
174+
159175
// Construct meterProvider
160176
MetricExporter metricsExporter =
161177
ApplicationSignalsExporterProvider.INSTANCE.createExporter(configProps);
@@ -207,6 +223,21 @@ private SdkMeterProviderBuilder customizeMeterProvider(
207223

208224
private SpanExporter customizeSpanExporter(
209225
SpanExporter spanExporter, ConfigProperties configProps) {
226+
// When running in Lambda, override the default OTLP exporter with UDP exporter
227+
if (isLambdaEnvironment()) {
228+
if (isOtlpSpanExporter(spanExporter)
229+
&& System.getenv(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT_CONFIG) == null) {
230+
String tracesEndpoint =
231+
Optional.ofNullable(System.getenv(AWS_XRAY_DAEMON_ADDRESS_CONFIG))
232+
.orElse(DEFAULT_UDP_ENDPOINT);
233+
spanExporter =
234+
new OtlpUdpSpanExporterBuilder()
235+
.setPayloadSampleDecision(TracePayloadSampleDecision.SAMPLED)
236+
.setEndpoint(tracesEndpoint)
237+
.build();
238+
}
239+
}
240+
210241
if (isApplicationSignalsEnabled(configProps)) {
211242
return AwsMetricAttributesSpanExporterBuilder.create(
212243
spanExporter, ResourceHolder.getResource())
@@ -216,6 +247,11 @@ private SpanExporter customizeSpanExporter(
216247
return spanExporter;
217248
}
218249

250+
private boolean isOtlpSpanExporter(SpanExporter spanExporter) {
251+
return spanExporter instanceof OtlpGrpcSpanExporter
252+
|| spanExporter instanceof OtlpHttpSpanExporter;
253+
}
254+
219255
private enum ApplicationSignalsExporterProvider {
220256
INSTANCE;
221257

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import static io.opentelemetry.semconv.SemanticAttributes.MESSAGING_OPERATION;
2424
import static io.opentelemetry.semconv.SemanticAttributes.MessagingOperationValues.PROCESS;
2525
import static io.opentelemetry.semconv.SemanticAttributes.RPC_SYSTEM;
26+
import static software.amazon.opentelemetry.javaagent.providers.AwsApplicationSignalsCustomizerProvider.AWS_LAMBDA_FUNCTION_NAME_CONFIG;
27+
import static software.amazon.opentelemetry.javaagent.providers.AwsApplicationSignalsCustomizerProvider.isLambdaEnvironment;
2628
import static software.amazon.opentelemetry.javaagent.providers.AwsAttributeKeys.AWS_LOCAL_OPERATION;
2729

2830
import com.fasterxml.jackson.core.type.TypeReference;
@@ -82,9 +84,13 @@ static List<String> getDialectKeywords() {
8284
/**
8385
* Ingress operation (i.e. operation for Server and Consumer spans) will be generated from
8486
* "http.method + http.target/with the first API path parameter" if the default span name equals
85-
* null, UnknownOperation or http.method value.
87+
* null, UnknownOperation or http.method value. If running in Lambda, the ingress operation will
88+
* be the function name + /FunctionHandler.
8689
*/
8790
static String getIngressOperation(SpanData span) {
91+
if (isLambdaEnvironment()) {
92+
return System.getenv(AWS_LAMBDA_FUNCTION_NAME_CONFIG) + "/FunctionHandler";
93+
}
8894
String operation = span.getName();
8995
if (shouldUseInternalOperation(span)) {
9096
operation = INTERNAL_OPERATION;

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,6 @@ final class AwsUnsampledOnlySpanProcessor implements SpanProcessor {
3434
this.delegate = delegate;
3535
}
3636

37-
public static AwsUnsampledOnlySpanProcessorBuilder builder() {
38-
return new AwsUnsampledOnlySpanProcessorBuilder();
39-
}
40-
4137
@Override
4238
public void onStart(Context parentContext, ReadWriteSpan span) {
4339
if (!span.getSpanContext().isSampled()) {

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
import io.opentelemetry.sdk.trace.export.SpanExporter;
2222

2323
final class AwsUnsampledOnlySpanProcessorBuilder {
24+
public static AwsUnsampledOnlySpanProcessorBuilder create() {
25+
return new AwsUnsampledOnlySpanProcessorBuilder();
26+
}
2427

2528
// Default exporter is OtlpUdpSpanExporter with unsampled payload prefix
2629
private SpanExporter exporter =

awsagentprovider/src/test/java/software/amazon/opentelemetry/javaagent/providers/AwsUnsampledOnlySpanProcessorTest.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,19 @@ public class AwsUnsampledOnlySpanProcessorTest {
3535

3636
@Test
3737
public void testIsStartRequired() {
38-
SpanProcessor processor = AwsUnsampledOnlySpanProcessor.builder().build();
38+
SpanProcessor processor = AwsUnsampledOnlySpanProcessorBuilder.create().build();
3939
assertThat(processor.isStartRequired()).isTrue();
4040
}
4141

4242
@Test
4343
public void testIsEndRequired() {
44-
SpanProcessor processor = AwsUnsampledOnlySpanProcessor.builder().build();
44+
SpanProcessor processor = AwsUnsampledOnlySpanProcessorBuilder.create().build();
4545
assertThat(processor.isEndRequired()).isTrue();
4646
}
4747

4848
@Test
4949
public void testDefaultSpanProcessor() {
50-
AwsUnsampledOnlySpanProcessorBuilder builder = AwsUnsampledOnlySpanProcessor.builder();
50+
AwsUnsampledOnlySpanProcessorBuilder builder = AwsUnsampledOnlySpanProcessorBuilder.create();
5151
AwsUnsampledOnlySpanProcessor unsampledSP = builder.build();
5252

5353
assertThat(builder.getSpanExporter()).isInstanceOf(OtlpUdpSpanExporter.class);
@@ -64,7 +64,8 @@ public void testDefaultSpanProcessor() {
6464
@Test
6565
public void testSpanProcessorWithExporter() {
6666
AwsUnsampledOnlySpanProcessorBuilder builder =
67-
AwsUnsampledOnlySpanProcessor.builder().setSpanExporter(InMemorySpanExporter.create());
67+
AwsUnsampledOnlySpanProcessorBuilder.create()
68+
.setSpanExporter(InMemorySpanExporter.create());
6869
AwsUnsampledOnlySpanProcessor unsampledSP = builder.build();
6970

7071
assertThat(builder.getSpanExporter()).isInstanceOf(InMemorySpanExporter.class);
@@ -85,7 +86,7 @@ public void testStartAddsAttributeToSampledSpan() {
8586
ReadWriteSpan spanMock = mock(ReadWriteSpan.class);
8687
when(spanMock.getSpanContext()).thenReturn(mockSpanContext);
8788

88-
AwsUnsampledOnlySpanProcessor processor = AwsUnsampledOnlySpanProcessor.builder().build();
89+
AwsUnsampledOnlySpanProcessor processor = AwsUnsampledOnlySpanProcessorBuilder.create().build();
8990
processor.onStart(parentContextMock, spanMock);
9091

9192
// verify setAttribute was never called
@@ -100,7 +101,7 @@ public void testStartAddsAttributeToUnsampledSpan() {
100101
ReadWriteSpan spanMock = mock(ReadWriteSpan.class);
101102
when(spanMock.getSpanContext()).thenReturn(mockSpanContext);
102103

103-
AwsUnsampledOnlySpanProcessor processor = AwsUnsampledOnlySpanProcessor.builder().build();
104+
AwsUnsampledOnlySpanProcessor processor = AwsUnsampledOnlySpanProcessorBuilder.create().build();
104105
processor.onStart(parentContextMock, spanMock);
105106

106107
// verify setAttribute was called with the correct arguments

0 commit comments

Comments
 (0)