Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
af21cb2
added distributed tracing for entities
Mar 6, 2025
8846d70
change in how the distributed trace context is propagated in the case…
Mar 10, 2025
d3f25f3
slight style update
Mar 11, 2025
ed72bf7
some more tiny style things
Mar 12, 2025
1c271de
addressing two more PR comments
Mar 12, 2025
ffe061e
forgot to add one annotation
Mar 13, 2025
7462c40
yet another small style change
Mar 13, 2025
8871873
addressing PR comments
Mar 18, 2025
d49c005
forgot one file
Mar 18, 2025
7175737
addressing more PR comments
Mar 25, 2025
b2f859f
forgot two comments
Mar 25, 2025
869d1a2
addressing a few small comments
Mar 31, 2025
3116463
refactored most of the tracing into this repo to more accurately refl…
Apr 11, 2025
87776bc
fixing spacing
Apr 11, 2025
97cd8e6
slight change in formatting of the create orchestration trace
Apr 11, 2025
d01179f
addressing PR comments
Apr 15, 2025
30db2fb
adding back new lines at the ends of files
Apr 15, 2025
c4dc784
trying to fix these line endings
Apr 15, 2025
41b0280
dealing with new lines again
Apr 15, 2025
dcac8a8
tiny change
Apr 15, 2025
9a54fef
missed a null check
Apr 15, 2025
9aec0fc
reverting to old design
Apr 18, 2025
d8c10bb
missed some
Apr 18, 2025
6b2bce1
and missed some more
Apr 18, 2025
0b56873
missed even more
Apr 18, 2025
ac98d23
will it ever end
Apr 18, 2025
9ef781c
last one i think
Apr 18, 2025
ee86dd2
moved activity for entity starting an orchestration back into webjobs
Apr 22, 2025
2206569
as always missed some stuff
Apr 22, 2025
ba75851
added support for an entities enabled flag
Apr 25, 2025
92e5c26
added a null check for client span ID when creating the activity for …
Apr 25, 2025
13d56ad
getting rid of an extra line
Apr 25, 2025
9ad0099
addressing PR comment
Apr 28, 2025
69d968e
Merge branch 'main' into stevosyan/distributed-tracing-for-entities
May 6, 2025
e172546
addressing a few PR comments
May 6, 2025
5062030
addressing some PR comments, slightly changing the logic of the modif…
May 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/DurableTask.Core/OrchestrationTags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ public static class OrchestrationTags
/// </remarks>
public const string FireAndForget = "FireAndForget";

/// <summary>
/// The ID of the parent trace that created this orchestration instance (see https://www.w3.org/TR/trace-context/#traceparent-header)
/// </summary>
public const string TraceParent = "MS_Entities_TraceParent";

/// <summary>
/// The trace state of the parent trace that created this orchestration instance (see https://www.w3.org/TR/trace-context/#tracestate-header)
/// </summary>
public const string TraceState = "MS_Entities_TraceState";

/// <summary>
/// Check whether the given tags contain the fire and forget tag
/// </summary>
Expand Down
23 changes: 22 additions & 1 deletion src/DurableTask.Core/TaskHubClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,19 @@ void CreateAndTrackDependencyTelemetry(TraceContextBase? requestTraceContext)
/// <param name="eventName">Name of the event</param>
/// <param name="eventData">Data for the event</param>
public async Task RaiseEventAsync(OrchestrationInstance orchestrationInstance, string eventName, object eventData)
{
await this.RaiseEventAsync(orchestrationInstance, eventName, eventData, emitTraceActivity: true);
}

/// <summary>
/// Raises an event in the specified orchestration instance, which eventually causes the OnEvent() method in the
/// orchestration to fire.
/// </summary>
/// <param name="orchestrationInstance">Instance in which to raise the event</param>
/// <param name="eventName">Name of the event</param>
/// <param name="eventData">Data for the event</param>
/// <param name="emitTraceActivity">Whether or not to emit a trace activity for this event.</param>
public async Task RaiseEventAsync(OrchestrationInstance orchestrationInstance, string eventName, object eventData, bool emitTraceActivity = true)
{

if (string.IsNullOrWhiteSpace(orchestrationInstance.InstanceId))
Expand All @@ -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
{
Expand All @@ -776,6 +793,10 @@ public async Task RaiseEventAsync(OrchestrationInstance orchestrationInstance, s
TraceHelper.AddErrorDetailsToSpan(traceActivity, e);
throw;
}
finally
{
traceActivity?.Dispose();
}
}

/// <summary>
Expand Down
26 changes: 21 additions & 5 deletions src/DurableTask.Core/TaskOrchestrationDispatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ public async Task StopAsync(bool forced)
/// </summary>
public bool IncludeParameters { get; set; }

/// <summary>
/// Gets or sets the flag for whether or not entities are enabled
/// </summary>
public bool EntitiesEnabled { get; set; }

/// <summary>
/// Method to get the next work item to process within supplied timeout
/// </summary>
Expand Down Expand Up @@ -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();
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);

Expand Down
13 changes: 12 additions & 1 deletion src/DurableTask.Core/Tracing/TraceHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -348,15 +351,23 @@ internal static void EmitTraceActivityForSubOrchestrationFailed(
/// </summary>
/// <param name="eventRaisedEvent">The associated <see cref="EventRaisedEvent"/>.</param>
/// <param name="instance">The associated <see cref="OrchestrationInstance"/>.</param>
/// <param name="entitiesEnabled">Whether or not entities are enabled, meaning this event could possibly correspond to entity.</param>
/// <param name="targetInstanceId">The instance id of the orchestration that will receive the event.</param>
/// <returns>
/// Returns a newly started <see cref="Activity"/> with (task) activity and orchestration-specific metadata.
/// </returns>
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,
Expand Down
Loading