diff --git a/src/DurableTask.Core/OrchestrationTags.cs b/src/DurableTask.Core/OrchestrationTags.cs
index 960297143..c3065de46 100644
--- a/src/DurableTask.Core/OrchestrationTags.cs
+++ b/src/DurableTask.Core/OrchestrationTags.cs
@@ -36,6 +36,16 @@ public static class OrchestrationTags
///
public const string FireAndForget = "FireAndForget";
+ ///
+ /// The ID of the parent trace that created this orchestration instance (see https://www.w3.org/TR/trace-context/#traceparent-header)
+ ///
+ public const string TraceParent = "MS_Entities_TraceParent";
+
+ ///
+ /// The trace state of the parent trace that created this orchestration instance (see https://www.w3.org/TR/trace-context/#tracestate-header)
+ ///
+ public const string TraceState = "MS_Entities_TraceState";
+
///
/// Check whether the given tags contain the fire and forget tag
///
diff --git a/src/DurableTask.Core/TaskHubClient.cs b/src/DurableTask.Core/TaskHubClient.cs
index eb55d1936..7cf2bc064 100644
--- a/src/DurableTask.Core/TaskHubClient.cs
+++ b/src/DurableTask.Core/TaskHubClient.cs
@@ -746,6 +746,19 @@ void CreateAndTrackDependencyTelemetry(TraceContextBase? requestTraceContext)
/// Name of the event
/// Data for the event
public async Task RaiseEventAsync(OrchestrationInstance orchestrationInstance, string eventName, object eventData)
+ {
+ await this.RaiseEventAsync(orchestrationInstance, eventName, eventData, emitTraceActivity: true);
+ }
+
+ ///
+ /// Raises an event in the specified orchestration instance, which eventually causes the OnEvent() method in the
+ /// orchestration to fire.
+ ///
+ /// Instance in which to raise the event
+ /// Name of the event
+ /// Data for the event
+ /// Whether or not to emit a trace activity for this event.
+ public async Task RaiseEventAsync(OrchestrationInstance orchestrationInstance, string eventName, object eventData, bool emitTraceActivity = true)
{
if (string.IsNullOrWhiteSpace(orchestrationInstance.InstanceId))
@@ -757,7 +770,11 @@ public async Task RaiseEventAsync(OrchestrationInstance orchestrationInstance, s
// Distributed Tracing
EventRaisedEvent eventRaisedEvent = new EventRaisedEvent(-1, serializedInput) { Name = eventName };
- using Activity? traceActivity = TraceHelper.StartActivityForNewEventRaisedFromClient(eventRaisedEvent, orchestrationInstance);
+ Activity? traceActivity = null;
+ if (emitTraceActivity)
+ {
+ traceActivity = TraceHelper.StartActivityForNewEventRaisedFromClient(eventRaisedEvent, orchestrationInstance);
+ }
var taskMessage = new TaskMessage
{
@@ -776,6 +793,10 @@ public async Task RaiseEventAsync(OrchestrationInstance orchestrationInstance, s
TraceHelper.AddErrorDetailsToSpan(traceActivity, e);
throw;
}
+ finally
+ {
+ traceActivity?.Dispose();
+ }
}
///
diff --git a/src/DurableTask.Core/TaskOrchestrationDispatcher.cs b/src/DurableTask.Core/TaskOrchestrationDispatcher.cs
index d1cb03f87..dd1663e74 100644
--- a/src/DurableTask.Core/TaskOrchestrationDispatcher.cs
+++ b/src/DurableTask.Core/TaskOrchestrationDispatcher.cs
@@ -116,6 +116,11 @@ public async Task StopAsync(bool forced)
///
public bool IncludeParameters { get; set; }
+ ///
+ /// Gets or sets the flag for whether or not entities are enabled
+ ///
+ public bool EntitiesEnabled { get; set; }
+
///
/// Method to get the next work item to process within supplied timeout
///
@@ -1140,9 +1145,6 @@ TaskMessage ProcessCreateSubOrchestrationInstanceDecision(
historyEvent.Input = createSubOrchestrationAction.Input;
}
- ActivitySpanId clientSpanId = ActivitySpanId.CreateRandom();
- historyEvent.ClientSpanId = clientSpanId.ToString();
-
runtimeState.AddEvent(historyEvent);
var taskMessage = new TaskMessage();
@@ -1166,8 +1168,22 @@ TaskMessage ProcessCreateSubOrchestrationInstanceDecision(
Version = createSubOrchestrationAction.Version
};
- if (parentTraceActivity != null)
+ // If a parent trace context was provided via the CreateSubOrchestrationAction.Tags, we will use this as the parent trace context of the suborchestration execution Activity rather than Activity.Current.Context.
+ if (createSubOrchestrationAction.Tags != null
+ && createSubOrchestrationAction.Tags.TryGetValue(OrchestrationTags.TraceParent, out string traceParent))
+ {
+ // If a parent trace context was provided but we fail to parse it, we don't want to attach any parent trace context to the start event since that will incorrectly link the trace corresponding to the orchestration execution
+ // as a child of Activity.Current, which is not truly the parent of the request
+ if (createSubOrchestrationAction.Tags.TryGetValue(OrchestrationTags.TraceState, out string traceState)
+ && ActivityContext.TryParse(traceParent, traceState, out ActivityContext parentTraceContext))
+ {
+ startedEvent.SetParentTraceContext(parentTraceContext);
+ }
+ }
+ else if (parentTraceActivity != null)
{
+ ActivitySpanId clientSpanId = ActivitySpanId.CreateRandom();
+ historyEvent.ClientSpanId = clientSpanId.ToString();
ActivityContext activityContext = new ActivityContext(parentTraceActivity.TraceId, clientSpanId, parentTraceActivity.ActivityTraceFlags, parentTraceActivity.TraceStateString);
startedEvent.SetParentTraceContext(activityContext);
}
@@ -1201,7 +1217,7 @@ TaskMessage ProcessSendEventDecision(
// Distributed Tracing: start a new trace activity derived from the orchestration
// for an EventRaisedEvent (external event)
- using Activity? traceActivity = TraceHelper.StartTraceActivityForEventRaisedFromWorker(eventRaisedEvent, runtimeState.OrchestrationInstance, sendEventAction.Instance?.InstanceId);
+ using Activity? traceActivity = TraceHelper.StartTraceActivityForEventRaisedFromWorker(eventRaisedEvent, runtimeState.OrchestrationInstance, this.EntitiesEnabled, sendEventAction.Instance?.InstanceId);
this.logHelper.RaisingEvent(runtimeState.OrchestrationInstance!, historyEvent);
diff --git a/src/DurableTask.Core/Tracing/TraceHelper.cs b/src/DurableTask.Core/Tracing/TraceHelper.cs
index 37f09c9d5..8df8c0fa4 100644
--- a/src/DurableTask.Core/Tracing/TraceHelper.cs
+++ b/src/DurableTask.Core/Tracing/TraceHelper.cs
@@ -284,7 +284,10 @@ internal static void EmitTraceActivityForTaskFailed(
return null;
}
- activity.SetSpanId(createdEvent.ClientSpanId);
+ if (!string.IsNullOrEmpty(createdEvent.ClientSpanId))
+ {
+ activity.SetSpanId(createdEvent.ClientSpanId);
+ }
activity.SetTag(Schema.Task.Type, TraceActivityConstants.Orchestration);
activity.SetTag(Schema.Task.Name, createdEvent.Name);
@@ -348,6 +351,7 @@ internal static void EmitTraceActivityForSubOrchestrationFailed(
///
/// The associated .
/// The associated .
+ /// Whether or not entities are enabled, meaning this event could possibly correspond to entity.
/// The instance id of the orchestration that will receive the event.
///
/// Returns a newly started with (task) activity and orchestration-specific metadata.
@@ -355,8 +359,15 @@ internal static void EmitTraceActivityForSubOrchestrationFailed(
internal static Activity? StartTraceActivityForEventRaisedFromWorker(
EventRaisedEvent eventRaisedEvent,
OrchestrationInstance? instance,
+ bool entitiesEnabled,
string? targetInstanceId)
{
+ // We don't want to emit tracing for external events when they are related to entities
+ if (entitiesEnabled && (Entities.IsEntityInstance(targetInstanceId ?? string.Empty) || Entities.IsEntityInstance(instance?.InstanceId ?? string.Empty)))
+ {
+ return null;
+ }
+
Activity? newActivity = ActivityTraceSource.StartActivity(
CreateSpanName(TraceActivityConstants.OrchestrationEvent, eventRaisedEvent.Name, null),
kind: ActivityKind.Producer,