Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions examples/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@
<version>1.63.0</version>
</dependency>

<!-- OTLP gRPC exporter (required for X-Ray via ADOT collector) -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
<version>1.63.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.72.0</version>
</dependency>

<!-- AWS Lambda Java Core -->
<dependency>
<groupId>com.amazonaws</groupId>
Expand Down Expand Up @@ -91,6 +103,11 @@
<artifactId>sts</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>xray</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package software.amazon.lambda.durable.examples.otel;

import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import software.amazon.lambda.durable.DurableConfig;
import software.amazon.lambda.durable.DurableContext;
import software.amazon.lambda.durable.DurableHandler;
import software.amazon.lambda.durable.examples.types.GreetingRequest;
import software.amazon.lambda.durable.otel.OpenTelemetryDurablePlugin;

/**
* OTel + X-Ray example: simple steps in a single invocation.
*
* <p>Exports spans via OTLP gRPC to the ADOT collector extension (Lambda layer), which forwards to X-Ray. Used by
* {@code OtelXRayIntegrationTest} to verify spans appear correctly in X-Ray.
*
* <p>Expected trace structure in X-Ray:
*
* <pre>
* durable.invocation
* ├── durable.step:create-greeting
* │ └── durable.step:create-greeting [attempt 1]
* └── durable.step:transform
* └── durable.step:transform [attempt 1]
* </pre>
*/
public class OtelXRayStepExample extends DurableHandler<GreetingRequest, String> {

@Override
protected DurableConfig createConfiguration() {
var otlpExporter = OtlpGrpcSpanExporter.builder()
.setEndpoint("http://localhost:4317")
.build();

var otelPlugin = new OpenTelemetryDurablePlugin(
SdkTracerProvider.builder().addSpanProcessor(SimpleSpanProcessor.create(otlpExporter)));

return DurableConfig.builder().withPlugins(otelPlugin).build();
}

@Override
public String handleRequest(GreetingRequest input, DurableContext context) {
context.getLogger().info("Starting OTel X-Ray step example for {}", input.getName());

var greeting = context.step("create-greeting", String.class, stepCtx -> "Hello, " + input.getName());

var result = context.step("transform", String.class, stepCtx -> greeting.toUpperCase() + "!");

context.getLogger().info("OTel X-Ray step example complete: {}", result);
return result;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package software.amazon.lambda.durable.examples.otel;

import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import java.time.Duration;
import software.amazon.lambda.durable.DurableConfig;
import software.amazon.lambda.durable.DurableContext;
import software.amazon.lambda.durable.DurableHandler;
import software.amazon.lambda.durable.examples.types.GreetingRequest;
import software.amazon.lambda.durable.otel.OpenTelemetryDurablePlugin;

/**
* OTel + X-Ray example: step → wait → step pattern that forces multiple Lambda invocations.
*
* <p>This handler exercises the critical multi-invocation tracing scenario:
*
* <ol>
* <li>Invocation 1: "before-wait" step completes → wait suspends execution
* <li>Invocation 2: replays "before-wait" (no-op) → wait completes → "after-wait" step runs
* </ol>
*
* <p>Exports spans via OTLP gRPC to the ADOT collector extension (Lambda layer), which forwards to X-Ray.
*
* <p>Used by {@code OtelXRayIntegrationTest} to verify that deterministic trace IDs correctly stitch spans from
* multiple invocations into a single X-Ray trace.
*
* <p>Expected trace structure in X-Ray:
*
* <pre>
* Trace (single trace ID across both invocations)
* ├── durable.invocation (invocation 1)
* │ ├── durable.step:before-wait
* │ │ └── durable.step:before-wait [attempt 1]
* │ └── durable.wait:pause (ended as PENDING)
* └── durable.invocation (invocation 2)
* ├── durable.wait:pause (completed)
* └── durable.step:after-wait
* └── durable.step:after-wait [attempt 1]
* </pre>
*
* <p>All spans share the same deterministic trace ID derived from the execution ARN.
*/
public class OtelXRayWaitExample extends DurableHandler<GreetingRequest, String> {

@Override
protected DurableConfig createConfiguration() {
var otlpExporter = OtlpGrpcSpanExporter.builder()
.setEndpoint("http://localhost:4317")
.build();

var otelPlugin = new OpenTelemetryDurablePlugin(
SdkTracerProvider.builder().addSpanProcessor(SimpleSpanProcessor.create(otlpExporter)));

return DurableConfig.builder().withPlugins(otelPlugin).build();
}

@Override
public String handleRequest(GreetingRequest input, DurableContext context) {
context.getLogger().info("Starting OTel X-Ray wait example for {}", input.getName());

var before = context.step("before-wait", String.class, stepCtx -> "Prepared: " + input.getName());

// This wait forces Lambda to suspend and re-invoke after the duration
context.wait("pause", Duration.ofSeconds(5));

var after = context.step("after-wait", String.class, stepCtx -> before + " | Resumed and completed");

context.getLogger().info("OTel X-Ray wait example complete: {}", after);
return after;
}
}
16 changes: 16 additions & 0 deletions examples/src/main/resources/collector.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
receivers:
otlp:
protocols:
grpc:
endpoint: "localhost:4317"
http:
endpoint: "localhost:4318"

exporters:
awsxray:

service:
pipelines:
traces:
receivers: [otlp]
exporters: [awsxray]
Loading
Loading