From e7c02dc9b6968efc53aac2e429157cd32aa33aa7 Mon Sep 17 00:00:00 2001 From: Frank Chen <65260095+zhongkechen@users.noreply.github.com> Date: Tue, 4 Aug 2026 16:28:16 -0700 Subject: [PATCH] fix(otel): preserve configured service name --- .../durable/otel/ExecutionOtelPlugin.java | 8 ------ .../durable/otel/ExecutionOtelPluginTest.java | 25 ++++++++++++------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/otel-plugin/src/main/java/software/amazon/lambda/durable/otel/ExecutionOtelPlugin.java b/otel-plugin/src/main/java/software/amazon/lambda/durable/otel/ExecutionOtelPlugin.java index 885ec1dd8..22d816617 100644 --- a/otel-plugin/src/main/java/software/amazon/lambda/durable/otel/ExecutionOtelPlugin.java +++ b/otel-plugin/src/main/java/software/amazon/lambda/durable/otel/ExecutionOtelPlugin.java @@ -5,7 +5,6 @@ import static software.amazon.lambda.durable.otel.SpanAttributes.*; import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanBuilder; import io.opentelemetry.api.trace.SpanContext; @@ -17,10 +16,8 @@ import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; -import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder; -import io.opentelemetry.semconv.ServiceAttributes; import java.time.Instant; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -87,7 +84,6 @@ public class ExecutionOtelPlugin implements DurableExecutionPlugin { private static final Logger logger = LoggerFactory.getLogger(ExecutionOtelPlugin.class); private static final String INSTRUMENTATION_NAME = "aws-durable-execution-sdk-java"; private static final String DEFAULT_WORKFLOW_SPAN_NAME = "Workflow"; - private static final String SERVICE_NAME = "workflow"; private final SdkTracerProvider sdkTracerProvider; private final Tracer tracer; @@ -160,10 +156,6 @@ public ExecutionOtelPlugin( String workflowSpanName) { this.idGenerator = new DeterministicIdGenerator(); - // Set service.name so this plugin's spans group under a distinct "workflow" node in X-Ray/OTLP backends. - var resource = Resource.create(Attributes.of(ServiceAttributes.SERVICE_NAME, SERVICE_NAME)); - tracerProviderBuilder.addResource(resource); - this.sdkTracerProvider = tracerProviderBuilder.setIdGenerator(idGenerator).build(); this.tracer = sdkTracerProvider.get(INSTRUMENTATION_NAME); diff --git a/otel-plugin/src/test/java/software/amazon/lambda/durable/otel/ExecutionOtelPluginTest.java b/otel-plugin/src/test/java/software/amazon/lambda/durable/otel/ExecutionOtelPluginTest.java index ed6533e05..ca03c55f5 100644 --- a/otel-plugin/src/test/java/software/amazon/lambda/durable/otel/ExecutionOtelPluginTest.java +++ b/otel-plugin/src/test/java/software/amazon/lambda/durable/otel/ExecutionOtelPluginTest.java @@ -5,9 +5,12 @@ import static org.junit.jupiter.api.Assertions.*; import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; @@ -20,6 +23,8 @@ class ExecutionOtelPluginTest { private static final String ARN = "arn:aws:lambda:us-east-1:123:function:test:$LATEST/durable/exec1"; + private static final AttributeKey SERVICE_NAME = AttributeKey.stringKey("service.name"); + private static final String CONFIGURED_SERVICE_NAME = "durable-execution-conformance"; private InMemorySpanExporter spanExporter; private ExecutionOtelPlugin plugin; @@ -29,8 +34,11 @@ void setUp() { DeterministicIdGenerator.clearSharedStateForTest(); OtelPluginAutoConfigurationState.resetInstalledForTest(); spanExporter = InMemorySpanExporter.create(); + var resource = Resource.create(Attributes.of(SERVICE_NAME, CONFIGURED_SERVICE_NAME)); plugin = new ExecutionOtelPlugin( - SdkTracerProvider.builder().addSpanProcessor(SimpleSpanProcessor.create(spanExporter)), + SdkTracerProvider.builder() + .setResource(resource) + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)), () -> null, false, "Workflow"); @@ -97,17 +105,16 @@ void terminalInvocation_exportsWorkflowAndInvocationSpans() { } @Test - void spans_carryWorkflowServiceName() { + void spans_preserveConfiguredServiceName() { plugin.onInvocationStart(new InvocationInfo("req-1", ARN, true, Instant.now())); plugin.onInvocationEnd(new InvocationEndInfo("req-1", ARN, true, InvocationStatus.SUCCEEDED, null)); - var workflowSpan = spanByName(spanExporter.getFinishedSpanItems(), "Workflow"); - assertEquals( - "workflow", - workflowSpan - .getResource() - .getAttribute(io.opentelemetry.api.common.AttributeKey.stringKey("service.name")), - "Spans should carry service.name=workflow"); + for (var span : spanExporter.getFinishedSpanItems()) { + assertEquals( + CONFIGURED_SERVICE_NAME, + span.getResource().getAttribute(SERVICE_NAME), + "Plugin must preserve the caller-configured service.name"); + } } @Test