-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ActivitySource.CreateActivity methods #48374
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -1007,56 +1007,15 @@ public void SetCustomProperty(string propertyName, object? propertyValue) | |||||||||||
return ret; | ||||||||||||
} | ||||||||||||
|
||||||||||||
internal static Activity CreateAndStart(ActivitySource source, string name, ActivityKind kind, string? parentId, ActivityContext parentContext, | ||||||||||||
internal static Activity Create(ActivitySource source, string name, ActivityKind kind, string? parentId, ActivityContext parentContext, | ||||||||||||
IEnumerable<KeyValuePair<string, object?>>? tags, IEnumerable<ActivityLink>? links, | ||||||||||||
DateTimeOffset startTime, ActivityTagsCollection? samplerTags, ActivitySamplingResult request) | ||||||||||||
DateTimeOffset startTime, ActivityTagsCollection? samplerTags, ActivitySamplingResult request, bool startIt) | ||||||||||||
{ | ||||||||||||
Activity activity = new Activity(name); | ||||||||||||
|
||||||||||||
activity.Source = source; | ||||||||||||
activity.Kind = kind; | ||||||||||||
|
||||||||||||
activity._previousActiveActivity = Current; | ||||||||||||
if (parentId != null) | ||||||||||||
{ | ||||||||||||
activity._parentId = parentId; | ||||||||||||
} | ||||||||||||
else if (parentContext != default) | ||||||||||||
{ | ||||||||||||
activity._traceId = parentContext.TraceId.ToString(); | ||||||||||||
|
||||||||||||
if (parentContext.SpanId != default) | ||||||||||||
{ | ||||||||||||
activity._parentSpanId = parentContext.SpanId.ToString(); | ||||||||||||
} | ||||||||||||
|
||||||||||||
activity.ActivityTraceFlags = parentContext.TraceFlags; | ||||||||||||
activity._traceState = parentContext.TraceState; | ||||||||||||
} | ||||||||||||
else | ||||||||||||
{ | ||||||||||||
if (activity._previousActiveActivity != null) | ||||||||||||
{ | ||||||||||||
// The parent change should not form a loop. We are actually guaranteed this because | ||||||||||||
// 1. Un-started activities can't be 'Current' (thus can't be 'parent'), we throw if you try. | ||||||||||||
// 2. All started activities have a finite parent change (by inductive reasoning). | ||||||||||||
activity.Parent = activity._previousActiveActivity; | ||||||||||||
} | ||||||||||||
} | ||||||||||||
|
||||||||||||
activity.IdFormat = | ||||||||||||
ForceDefaultIdFormat ? DefaultIdFormat : | ||||||||||||
activity.Parent != null ? activity.Parent.IdFormat : | ||||||||||||
activity._parentSpanId != null ? ActivityIdFormat.W3C : | ||||||||||||
activity._parentId == null ? DefaultIdFormat : | ||||||||||||
IsW3CId(activity._parentId) ? ActivityIdFormat.W3C : | ||||||||||||
ActivityIdFormat.Hierarchical; | ||||||||||||
|
||||||||||||
if (activity.IdFormat == ActivityIdFormat.W3C) | ||||||||||||
activity.GenerateW3CId(); | ||||||||||||
else | ||||||||||||
activity._id = activity.GenerateHierarchicalId(); | ||||||||||||
|
||||||||||||
if (links != null) | ||||||||||||
{ | ||||||||||||
using (IEnumerator<ActivityLink> enumerator = links.GetEnumerator()) | ||||||||||||
|
@@ -1091,16 +1050,68 @@ internal static Activity CreateAndStart(ActivitySource source, string name, Acti | |||||||||||
} | ||||||||||||
} | ||||||||||||
|
||||||||||||
activity.StartTimeUtc = startTime == default ? GetUtcNow() : startTime.UtcDateTime; | ||||||||||||
|
||||||||||||
activity.IsAllDataRequested = request == ActivitySamplingResult.AllData || request == ActivitySamplingResult.AllDataAndRecorded; | ||||||||||||
|
||||||||||||
if (request == ActivitySamplingResult.AllDataAndRecorded) | ||||||||||||
{ | ||||||||||||
activity.ActivityTraceFlags |= ActivityTraceFlags.Recorded; | ||||||||||||
} | ||||||||||||
|
||||||||||||
SetCurrent(activity); | ||||||||||||
if (parentId != null) | ||||||||||||
{ | ||||||||||||
activity._parentId = parentId; | ||||||||||||
} | ||||||||||||
else if (parentContext != default) | ||||||||||||
{ | ||||||||||||
activity._traceId = parentContext.TraceId.ToString(); | ||||||||||||
|
||||||||||||
if (parentContext.SpanId != default) | ||||||||||||
{ | ||||||||||||
activity._parentSpanId = parentContext.SpanId.ToString(); | ||||||||||||
} | ||||||||||||
|
||||||||||||
activity.ActivityTraceFlags = parentContext.TraceFlags; | ||||||||||||
activity._traceState = parentContext.TraceState; | ||||||||||||
} | ||||||||||||
|
||||||||||||
if (startTime != default) | ||||||||||||
{ | ||||||||||||
activity.StartTimeUtc = startTime.UtcDateTime; | ||||||||||||
} | ||||||||||||
|
||||||||||||
if (startIt) | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does anything prevent us from doing?
Suggested change
It feels odd to be replicating all this start code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is possible. The only different case would be when someone calling StartActivity and passing ActivityContext with a default span Id. we used to keep There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In theory spanId = 0 is an invalid parent context. We should probably take a peak at the spec and chat with the OT folks to see if they have any input on what error handling behavior is desirable. I don't recall us ever defining the behavior very precisely but what I see the code currently do is give the bad id (in string or ActivityContext form) to the sampler as-is. Later in CreateAndStart we potentially ignore the id (if it was in string form) and create a new id based on IdFormat. This runs afoul of our sampler TraceId == Activity.TraceId invariant the same as above. I don't care too much about the factoring on its own, but I am glad thinking about it sussed out issues like this one : ) |
||||||||||||
{ | ||||||||||||
activity._previousActiveActivity = Current; | ||||||||||||
if (activity._parentId == null && activity._traceId == null && activity._previousActiveActivity != null) | ||||||||||||
{ | ||||||||||||
// The parent change should not form a loop. We are actually guaranteed this because | ||||||||||||
// 1. Un-started activities can't be 'Current' (thus can't be 'parent'), we throw if you try. | ||||||||||||
// 2. All started activities have a finite parent change (by inductive reasoning). | ||||||||||||
activity.Parent = activity._previousActiveActivity; | ||||||||||||
} | ||||||||||||
|
||||||||||||
activity.IdFormat = | ||||||||||||
ForceDefaultIdFormat ? DefaultIdFormat : | ||||||||||||
activity.Parent != null ? activity.Parent.IdFormat : | ||||||||||||
activity._parentSpanId != null ? ActivityIdFormat.W3C : | ||||||||||||
activity._parentId == null ? DefaultIdFormat : | ||||||||||||
IsW3CId(activity._parentId) ? ActivityIdFormat.W3C : | ||||||||||||
ActivityIdFormat.Hierarchical; | ||||||||||||
|
||||||||||||
if (activity.IdFormat == ActivityIdFormat.W3C) | ||||||||||||
activity.GenerateW3CId(); | ||||||||||||
else | ||||||||||||
activity._id = activity.GenerateHierarchicalId(); | ||||||||||||
|
||||||||||||
if (activity.StartTimeUtc == default) | ||||||||||||
{ | ||||||||||||
activity.StartTimeUtc = GetUtcNow(); | ||||||||||||
} | ||||||||||||
|
||||||||||||
SetCurrent(activity); | ||||||||||||
|
||||||||||||
source.NotifyActivityStart(activity); | ||||||||||||
} | ||||||||||||
|
||||||||||||
return activity; | ||||||||||||
} | ||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weren't we going to handle #43853 by adding an IdFormat parameter here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. After discussing this in the design review, @pakrym felt the other proposal is not needed and that can be handled by this CreateActivity proposal. After creating the activity, they can set the IdFormat on such created Activity before starting it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unforetunately that doesn't work. CreateActivity() calls the sampling callback, sampling callback has access to the ID, generating that ID has already fixed the id format. Using SetIdFormat() after CreateActivity() should probably throw an exception if it doesn't already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the Activity not started,
_id
and_spanId
would still be nulls. otherwise Activity.Start() would fail too. no?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@noahfalk I have addressed all comments. The remaining point is this one which related to IdFormat. I don't think we should fix the Ids before starting the Activity. Please let me know if you think otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This case seems very real. Think of a worker app uploading a blob. There is no parent and all spans are exported so TraceId is not accessed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, agree. But using CreateActivity with the current design will make it work. right? I mean users can use CreateActivity and SetIdFormat if they need to for this scenario.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pakrym I had offline discussion with @noahfalk and we propose adding extra Boolean parameter to the CreateActivity called
forceW3CId
. The reason we didn't have the parameter of ActivityIdFormat type because we want to promote W3C in general and not allow users to try the hierarchal explicitly. Please let's know if you have any concern. I'll send it anyway to the fxdc and will CC you there.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. If we want to promote W3C can we default the parameter to true? 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I discussed that with @noahfalk and he preferred not to default the value to W3C as he want to have consistent behavior with StartActivity when passing the exact same parameters.