Skip to content

Commit 69a1326

Browse files
committed
Don't set error status on otel spans for benign exceptions
1 parent c67ca60 commit 69a1326

File tree

2 files changed

+110
-2
lines changed

2 files changed

+110
-2
lines changed

temporal-opentracing/src/main/java/io/temporal/opentracing/internal/SpanFactory.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.opentracing.Tracer.SpanBuilder;
1010
import io.opentracing.log.Fields;
1111
import io.opentracing.tag.Tags;
12+
import io.temporal.internal.common.FailureUtils;
1213
import io.temporal.opentracing.OpenTracingOptions;
1314
import io.temporal.opentracing.SpanCreationContext;
1415
import io.temporal.opentracing.SpanOperationType;
@@ -238,8 +239,9 @@ public Tracer.SpanBuilder createWorkflowHandleQuerySpan(
238239
@SuppressWarnings("deprecation")
239240
public void logFail(Span toSpan, Throwable failReason) {
240241
toSpan.setTag(StandardTagNames.FAILED, true);
241-
toSpan.setTag(Tags.ERROR, options.getIsErrorPredicate().test(failReason));
242-
242+
if (!FailureUtils.isBenignApplicationFailure(failReason)) {
243+
toSpan.setTag(Tags.ERROR, options.getIsErrorPredicate().test(failReason));
244+
}
243245
Map<String, Object> logPayload = new HashMap<>();
244246
logPayload.put(Fields.EVENT, "error");
245247
logPayload.put(Fields.ERROR_KIND, failReason.getClass().getName());

temporal-opentracing/src/test/java/io/temporal/opentracing/ActivityFailureTest.java

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
import io.opentracing.mock.MockTracer;
88
import io.opentracing.tag.Tags;
99
import io.opentracing.util.ThreadLocalScopeManager;
10+
import io.temporal.activity.Activity;
1011
import io.temporal.activity.ActivityInterface;
1112
import io.temporal.activity.ActivityMethod;
1213
import io.temporal.activity.ActivityOptions;
1314
import io.temporal.client.WorkflowClient;
1415
import io.temporal.client.WorkflowClientOptions;
1516
import io.temporal.client.WorkflowOptions;
1617
import io.temporal.common.RetryOptions;
18+
import io.temporal.failure.ApplicationErrorCategory;
1719
import io.temporal.failure.ApplicationFailure;
1820
import io.temporal.testing.internal.SDKTestWorkflowRule;
1921
import io.temporal.worker.WorkerFactoryOptions;
@@ -152,4 +154,108 @@ public void testActivityFailureSpanStructure() {
152154
assertEquals(activityStartSpan.context().spanId(), activitySuccessfulRunSpan.parentId());
153155
assertEquals("RunActivity:Activity", activitySuccessfulRunSpan.operationName());
154156
}
157+
158+
@Rule
159+
public SDKTestWorkflowRule benignTestRule =
160+
SDKTestWorkflowRule.newBuilder()
161+
.setWorkerFactoryOptions(
162+
WorkerFactoryOptions.newBuilder()
163+
.setWorkerInterceptors(new OpenTracingWorkerInterceptor(OT_OPTIONS))
164+
.validateAndBuildWithDefaults())
165+
.setWorkflowTypes(BenignWorkflowImpl.class)
166+
.setActivityImplementations(new BenignFailingActivityImpl())
167+
.build();
168+
169+
@ActivityInterface
170+
public interface BenignTestActivity {
171+
@ActivityMethod
172+
String throwMaybeBenign();
173+
}
174+
175+
@WorkflowInterface
176+
public interface BenignTestWorkflow {
177+
@WorkflowMethod
178+
String workflow();
179+
}
180+
181+
public static class BenignFailingActivityImpl implements BenignTestActivity {
182+
@Override
183+
public String throwMaybeBenign() {
184+
int attempt = Activity.getExecutionContext().getInfo().getAttempt();
185+
if (attempt == 1) {
186+
// First attempt: regular failure
187+
throw ApplicationFailure.newFailure("not benign", "TestFailure");
188+
} else if (attempt == 2) {
189+
// Second attempt: benign failure
190+
throw ApplicationFailure.newBuilder()
191+
.setMessage("benign")
192+
.setType("TestFailure")
193+
.setCategory(ApplicationErrorCategory.BENIGN)
194+
.build();
195+
} else {
196+
// Third attempt: success
197+
return "success";
198+
}
199+
}
200+
}
201+
202+
public static class BenignWorkflowImpl implements BenignTestWorkflow {
203+
private final BenignTestActivity activity =
204+
Workflow.newActivityStub(
205+
BenignTestActivity.class,
206+
ActivityOptions.newBuilder()
207+
.setStartToCloseTimeout(Duration.ofMinutes(1))
208+
.setRetryOptions(
209+
RetryOptions.newBuilder()
210+
.setMaximumAttempts(3)
211+
.setBackoffCoefficient(1)
212+
.setInitialInterval(Duration.ofMillis(100))
213+
.build())
214+
.validateAndBuildWithDefaults());
215+
216+
@Override
217+
public String workflow() {
218+
return activity.throwMaybeBenign();
219+
}
220+
}
221+
222+
@Test
223+
public void testBenignApplicationFailureSpanBehavior() {
224+
MockSpan span = mockTracer.buildSpan("BenignTestFunction").start();
225+
226+
WorkflowClient client = benignTestRule.getWorkflowClient();
227+
try (Scope scope = mockTracer.scopeManager().activate(span)) {
228+
BenignTestWorkflow workflow =
229+
client.newWorkflowStub(
230+
BenignTestWorkflow.class,
231+
WorkflowOptions.newBuilder()
232+
.setTaskQueue(benignTestRule.getTaskQueue())
233+
.validateBuildWithDefaults());
234+
assertEquals("success", workflow.workflow());
235+
} finally {
236+
span.finish();
237+
}
238+
239+
List<MockSpan> allSpans = mockTracer.finishedSpans();
240+
241+
// Filter to only activity execution spans (RunActivity spans created by worker interceptor)
242+
List<MockSpan> activityRunSpans =
243+
allSpans.stream()
244+
.filter(s -> s.operationName().startsWith("RunActivity:"))
245+
.collect(java.util.stream.Collectors.toList());
246+
247+
assertEquals(3, activityRunSpans.size());
248+
249+
// First attempt: regular failure - should have ERROR tag
250+
MockSpan firstAttemptSpan = activityRunSpans.get(0);
251+
assertEquals(true, firstAttemptSpan.tags().get(Tags.ERROR.getKey()));
252+
253+
// Second attempt: benign failure - should NOT have ERROR tag
254+
MockSpan secondAttemptSpan = activityRunSpans.get(1);
255+
assertEquals(null, secondAttemptSpan.tags().get(Tags.ERROR.getKey()));
256+
257+
// Third attempt: success - should not have ERROR tag
258+
MockSpan thirdAttemptSpan = activityRunSpans.get(2);
259+
assertEquals(null, thirdAttemptSpan.tags().get(Tags.ERROR.getKey()));
260+
}
155261
}

0 commit comments

Comments
 (0)