Skip to content

Commit e8f5615

Browse files
authored
Do not set OTel span error status for benign exceptions (#530)
Fixes #510
1 parent d4a0765 commit e8f5615

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

src/Temporalio.Extensions.OpenTelemetry/TracingInterceptor.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using OpenTelemetry.Trace;
99
using Temporalio.Activities;
1010
using Temporalio.Api.Common.V1;
11+
using Temporalio.Api.Enums.V1;
1112
using Temporalio.Client;
1213
using Temporalio.Client.Interceptors;
1314
using Temporalio.Converters;
@@ -198,7 +199,16 @@ protected virtual IDictionary<string, Payload> HeadersFromContext(
198199

199200
private static void RecordExceptionWithStatus(Activity? activity, Exception exception)
200201
{
201-
activity?.SetStatus(ActivityStatusCode.Error, exception.Message);
202+
// If the exception is a benign exception, we do not consider the status an error. Note,
203+
// we intentionally only consider benign exceptions as not errors directly, not
204+
// transitively. So when a client uses this helper for a benign exception from a
205+
// workflow, or when a workflow uses this helper for a benign exception from an activity
206+
// bubbled out, this will still be considered an error status because those are wrapped
207+
// forms given to callers.
208+
if ((exception as ApplicationFailureException)?.Category != ApplicationErrorCategory.Benign)
209+
{
210+
activity?.SetStatus(ActivityStatusCode.Error, exception.Message);
211+
}
202212
activity?.RecordException(exception);
203213
}
204214

tests/Temporalio.Tests/Extensions/OpenTelemetry/TracingInterceptorTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,30 @@ await client.ExecuteUpdateWithStartWorkflowAsync(
728728
"UpdateWithStartWorkflow:TracingWorkflow", null));
729729
}
730730

731+
[Fact]
732+
public async Task TracingInterceptor_BenignExceptions_DoNotHaveErrorStatus()
733+
{
734+
// Confirm non-benign fail shows up as error status
735+
var (_, activities) = await ExecuteTracingWorkflowAsync(
736+
new(new[] { new TracingWorkflowAction(AppFail: "Non-benign fail") }),
737+
expectFail: true);
738+
var act = activities.Single(act => act.OperationName == "CompleteWorkflow:TracingWorkflow");
739+
Assert.EndsWith(
740+
"Non-benign fail",
741+
act.Events.Single().Tags.Single(t => t.Key == "exception.message").Value!.ToString());
742+
Assert.Equal(ActivityStatusCode.Error, act.Status);
743+
744+
// Confirm benign fail is not error status
745+
(_, activities) = await ExecuteTracingWorkflowAsync(
746+
new(new[] { new TracingWorkflowAction(BenignAppFail: "Benign fail") }),
747+
expectFail: true);
748+
act = activities.Single(act => act.OperationName == "CompleteWorkflow:TracingWorkflow");
749+
Assert.EndsWith(
750+
"Benign fail",
751+
act.Events.Single().Tags.Single(t => t.Key == "exception.message").Value!.ToString());
752+
Assert.NotEqual(ActivityStatusCode.Error, act.Status);
753+
}
754+
731755
private static void AssertActivities(
732756
IReadOnlyCollection<Activity> activities, params ActivityAssertion[] assertions)
733757
{
@@ -907,6 +931,11 @@ public async Task RunAsync(TracingWorkflowParam param)
907931
{
908932
throw new ApplicationFailureException(action.AppFail);
909933
}
934+
if (action.BenignAppFail != null)
935+
{
936+
throw new ApplicationFailureException(
937+
action.BenignAppFail, category: ApplicationErrorCategory.Benign);
938+
}
910939
if (action.FailOnNonReplay != null)
911940
{
912941
await RaiseOnNonReplayAsync(action.FailOnNonReplay);
@@ -1078,6 +1107,7 @@ public record TracingWorkflowParam(
10781107

10791108
public record TracingWorkflowAction(
10801109
string? AppFail = null,
1110+
string? BenignAppFail = null,
10811111
string? FailOnNonReplay = null,
10821112
TracingWorkflowActionChildWorkflow? ChildWorkflow = null,
10831113
TracingWorkflowActionActivity? Activity = null,

0 commit comments

Comments
 (0)