1111import io .opentelemetry .api .trace .TraceFlags ;
1212import io .opentelemetry .api .trace .TraceState ;
1313import io .opentelemetry .api .trace .Tracer ;
14- import io .opentelemetry .api .trace .TracerProvider ;
1514import io .opentelemetry .context .Context ;
1615import io .opentelemetry .context .Scope ;
1716import io .opentelemetry .sdk .trace .SdkTracerProvider ;
17+ import io .opentelemetry .sdk .trace .SdkTracerProviderBuilder ;
1818import java .time .Instant ;
1919import java .util .concurrent .ConcurrentHashMap ;
2020import org .slf4j .Logger ;
@@ -52,17 +52,15 @@ public class OpenTelemetryDurablePlugin implements DurableExecutionPlugin {
5252 private static final Logger logger = LoggerFactory .getLogger (OpenTelemetryDurablePlugin .class );
5353 private static final String INSTRUMENTATION_NAME = "aws-durable-execution-sdk-java" ;
5454
55- private final TracerProvider tracerProvider ;
55+ private final SdkTracerProvider tracerProvider ;
5656 private final Tracer tracer ;
5757 private final DeterministicIdGenerator idGenerator ;
5858 private final ContextExtractor contextExtractor ;
59- private final double samplingRate ;
6059 private final boolean enableMdc ;
6160
6261 // Per-invocation state
6362 private volatile Span invocationSpan ;
6463 private volatile String executionArn ;
65- private volatile boolean sampled = true ;
6664
6765 // Thread-safe storage for operation spans (keyed by operationId) — open spans that need ending
6866 private final ConcurrentHashMap <String , Span > operationSpans = new ConcurrentHashMap <>();
@@ -75,75 +73,52 @@ public class OpenTelemetryDurablePlugin implements DurableExecutionPlugin {
7573 private final ConcurrentHashMap <String , SpanContext > operationContexts = new ConcurrentHashMap <>();
7674
7775 /**
78- * Creates an OTel plugin with default settings: X-Ray context extraction, 100% sampling, MDC enabled.
76+ * Creates an OTel plugin with default settings: X-Ray context extraction, MDC enabled.
7977 *
80- * @param tracerProvider the OTel tracer provider (should use {@link DeterministicIdGenerator})
81- * @param idGenerator the deterministic ID generator (same instance configured in the tracer provider)
78+ * @param tracerProviderBuilder the tracer provider builder (ID generator will be overridden)
8279 */
83- public OpenTelemetryDurablePlugin (TracerProvider tracerProvider , DeterministicIdGenerator idGenerator ) {
84- this (tracerProvider , idGenerator , new XRayContextExtractor (), 1.0 , true );
80+ public OpenTelemetryDurablePlugin (SdkTracerProviderBuilder tracerProviderBuilder ) {
81+ this (tracerProviderBuilder , new XRayContextExtractor (), true );
8582 }
8683
8784 /**
88- * Creates an OTel plugin with a custom context extractor and sampling rate , MDC enabled.
85+ * Creates an OTel plugin with a custom context extractor, MDC enabled.
8986 *
90- * @param tracerProvider the OTel tracer provider
91- * @param idGenerator the deterministic ID generator
87+ * @param tracerProviderBuilder the tracer provider builder (ID generator will be overridden)
9288 * @param contextExtractor extracts parent trace context from the Lambda environment
93- * @param samplingRate value between 0.0 and 1.0 — fraction of executions to trace
9489 */
9590 public OpenTelemetryDurablePlugin (
96- TracerProvider tracerProvider ,
97- DeterministicIdGenerator idGenerator ,
98- ContextExtractor contextExtractor ,
99- double samplingRate ) {
100- this (tracerProvider , idGenerator , contextExtractor , samplingRate , true );
91+ SdkTracerProviderBuilder tracerProviderBuilder , ContextExtractor contextExtractor ) {
92+ this (tracerProviderBuilder , contextExtractor , true );
10193 }
10294
10395 /**
10496 * Creates an OTel plugin with full configuration.
10597 *
106- * @param tracerProvider the OTel tracer provider
107- * @param idGenerator the deterministic ID generator
98+ * <p>The plugin internally creates a {@link DeterministicIdGenerator} and sets it on the provided builder before
99+ * building the tracer provider. Customers configure exporters, span processors, and samplers on the builder — the
100+ * plugin handles ID generation.
101+ *
102+ * @param tracerProviderBuilder the tracer provider builder (ID generator will be overridden)
108103 * @param contextExtractor extracts parent trace context from the Lambda environment
109- * @param samplingRate value between 0.0 and 1.0 — fraction of executions to trace
110104 * @param enableMdc if true, injects trace_id/span_id into SLF4J MDC for log correlation
111105 */
112106 public OpenTelemetryDurablePlugin (
113- TracerProvider tracerProvider ,
114- DeterministicIdGenerator idGenerator ,
115- ContextExtractor contextExtractor ,
116- double samplingRate ,
117- boolean enableMdc ) {
118- this .tracerProvider = tracerProvider ;
119- this .idGenerator = idGenerator ;
107+ SdkTracerProviderBuilder tracerProviderBuilder , ContextExtractor contextExtractor , boolean enableMdc ) {
108+ this .idGenerator = new DeterministicIdGenerator ();
109+ this .tracerProvider = tracerProviderBuilder .setIdGenerator (idGenerator ).build ();
120110 this .tracer = tracerProvider .get (INSTRUMENTATION_NAME );
121111 this .contextExtractor = contextExtractor ;
122- this .samplingRate = samplingRate ;
123112 this .enableMdc = enableMdc ;
124113 }
125114
126- /**
127- * Creates an OTel plugin using a pre-configured {@link SdkTracerProvider}.
128- *
129- * @param sdkTracerProvider the SDK tracer provider
130- * @param idGenerator the deterministic ID generator
131- */
132- public OpenTelemetryDurablePlugin (SdkTracerProvider sdkTracerProvider , DeterministicIdGenerator idGenerator ) {
133- this ((TracerProvider ) sdkTracerProvider , idGenerator );
134- }
135-
136115 // ─── Invocation hooks ────────────────────────────────────────────────
137116
138117 @ Override
139118 public void onInvocationStart (InvocationInfo info ) {
140119 this .executionArn = info .executionArn ();
141120 idGenerator .setExecutionArn (info .executionArn ());
142121
143- // Determine sampling (consistent across all invocations of same execution)
144- this .sampled = SamplingUtil .shouldSampleExecution (info .executionArn (), samplingRate );
145- if (!sampled ) return ;
146-
147122 // Extract parent context from Lambda environment (X-Ray, W3C, etc.)
148123 var extractedParentContext = contextExtractor .extract ();
149124
@@ -162,7 +137,7 @@ public void onInvocationStart(InvocationInfo info) {
162137
163138 @ Override
164139 public void onInvocationEnd (InvocationEndInfo info ) {
165- if (! sampled || invocationSpan == null ) return ;
140+ if (invocationSpan == null ) return ;
166141
167142 // End any operation spans that are still open (operations that didn't complete in this invocation)
168143 for (var entry : operationSpans .entrySet ()) {
@@ -196,19 +171,17 @@ public void onInvocationEnd(InvocationEndInfo info) {
196171 invocationSpan = null ;
197172
198173 // Flush spans before Lambda freezes
199- if (tracerProvider instanceof SdkTracerProvider sdkProvider ) {
200- var flushResult = sdkProvider .forceFlush ().join (5 , java .util .concurrent .TimeUnit .SECONDS );
201- if (!flushResult .isSuccess ()) {
202- logger .warn ("OTel span flush failed or timed out — some spans may be lost" );
203- }
174+ var flushResult = tracerProvider .forceFlush ().join (5 , java .util .concurrent .TimeUnit .SECONDS );
175+ if (!flushResult .isSuccess ()) {
176+ logger .warn ("OTel span flush failed or timed out — some spans may be lost" );
204177 }
205178 }
206179
207180 // ─── Operation hooks ─────────────────────────────────────────────────
208181
209182 @ Override
210183 public void onOperationStart (OperationInfo info ) {
211- if (! sampled || info .id () == null ) return ;
184+ if (info .id () == null ) return ;
212185
213186 idGenerator .setNextSpanOperationId (info .id ());
214187
@@ -239,7 +212,7 @@ public void onOperationStart(OperationInfo info) {
239212
240213 @ Override
241214 public void onOperationEnd (OperationEndInfo info ) {
242- if (! sampled || info .id () == null ) return ;
215+ if (info .id () == null ) return ;
243216
244217 // End the operation span that was started in onOperationStart
245218 var span = operationSpans .remove (info .id ());
@@ -257,7 +230,6 @@ public void onOperationEnd(OperationEndInfo info) {
257230
258231 @ Override
259232 public void onUserFunctionStart (UserFunctionStartInfo info ) {
260- if (!sampled ) return ;
261233 var key = attemptKey (info .id (), info .attempt ());
262234
263235 // Use the operation span as parent for the attempt span
@@ -295,7 +267,6 @@ public void onUserFunctionStart(UserFunctionStartInfo info) {
295267
296268 @ Override
297269 public void onUserFunctionEnd (UserFunctionEndInfo info ) {
298- if (!sampled ) return ;
299270 var key = attemptKey (info .id (), info .attempt ());
300271
301272 // Close scope first (must happen on same thread as makeCurrent)
0 commit comments