Skip to content

Add ActivitySource.StartActivity overload and support CallerMemberNameAttribute for name parameter #47192

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

Merged
merged 2 commits into from
Jan 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,10 @@ public sealed class ActivitySource : IDisposable
public string Name { get { throw null; } }
public string? Version { get { throw null; } }
public bool HasListeners() { throw null; }
public System.Diagnostics.Activity? StartActivity(string name, System.Diagnostics.ActivityKind kind = ActivityKind.Internal) { throw null; }
public System.Diagnostics.Activity? StartActivity([System.Runtime.CompilerServices.CallerMemberName] string name = "", System.Diagnostics.ActivityKind kind = ActivityKind.Internal) { throw null; }
public System.Diagnostics.Activity? StartActivity(string name, System.Diagnostics.ActivityKind kind, System.Diagnostics.ActivityContext parentContext, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object?>>? tags = null, System.Collections.Generic.IEnumerable<System.Diagnostics.ActivityLink>? links = null, System.DateTimeOffset startTime = default) { throw null; }
public System.Diagnostics.Activity? StartActivity(string name, System.Diagnostics.ActivityKind kind, string parentId, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object?>>? tags = null, System.Collections.Generic.IEnumerable<System.Diagnostics.ActivityLink>? links = null, System.DateTimeOffset startTime = default) { throw null; }
public System.Diagnostics.Activity? StartActivity(System.Diagnostics.ActivityKind kind, System.Diagnostics.ActivityContext parentContext = default, System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, object?>>? tags = null, System.Collections.Generic.IEnumerable<System.Diagnostics.ActivityLink>? links = null, DateTimeOffset startTime = default, [System.Runtime.CompilerServices.CallerMemberName] string name = "") { throw null; }
public static void AddActivityListener(System.Diagnostics.ActivityListener listener) { throw null; }
public void Dispose() { throw null; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Threading;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Diagnostics
{
Expand Down Expand Up @@ -76,7 +77,7 @@ public bool HasListeners()
/// <param name="name">The operation name of the Activity</param>
/// <param name="kind">The <see cref="ActivityKind"/></param>
/// <returns>The created <see cref="Activity"/> object or null if there is no any event listener.</returns>
public Activity? StartActivity(string name, ActivityKind kind = ActivityKind.Internal)
public Activity? StartActivity([CallerMemberName] string name = "", ActivityKind kind = ActivityKind.Internal)
=> StartActivity(name, kind, default, null, null, null, default);

/// <summary>
Expand Down Expand Up @@ -105,6 +106,19 @@ public bool HasListeners()
public Activity? StartActivity(string name, ActivityKind kind, string parentId, IEnumerable<KeyValuePair<string, object?>>? tags = null, IEnumerable<ActivityLink>? links = null, DateTimeOffset startTime = default)
=> StartActivity(name, kind, default, parentId, tags, links, startTime);

/// <summary>
/// Creates a new <see cref="Activity"/> object if there is any listener to the Activity events, returns null otherwise.
/// </summary>
/// <param name="kind">The <see cref="ActivityKind"/></param>
/// <param name="parentContext">The parent <see cref="ActivityContext"/> object to initialize the created Activity object with.</param>
/// <param name="tags">The optional tags list to initialize the created Activity object with.</param>
/// <param name="links">The optional <see cref="ActivityLink"/> list to initialize the created Activity object with.</param>
/// <param name="startTime">The optional start timestamp to set on the created Activity object.</param>
/// <param name="name">The operation name of the Activity.</param>
/// <returns>The created <see cref="Activity"/> object or null if there is no any listener.</returns>
public Activity? StartActivity(ActivityKind kind, ActivityContext parentContext = default, IEnumerable<KeyValuePair<string, object?>>? tags = null, IEnumerable<ActivityLink>? links = null, DateTimeOffset startTime = default, [CallerMemberName] string name = "")
=> StartActivity(name, kind, parentContext, null, tags, links, startTime);

private Activity? StartActivity(string name, ActivityKind kind, ActivityContext context, string? parentId, IEnumerable<KeyValuePair<string, object?>>? tags, IEnumerable<ActivityLink>? links, DateTimeOffset startTime)
{
// _listeners can get assigned to null in Dispose.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,55 @@ public void TestActivityWithListenerActivityCreateAndAllDataRequested()
}).Dispose();
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void TestActivityTriggeringCallerMemberNameAttribute()
{
RemoteExecutor.Invoke(() => {
using (ActivitySource aSource = new ActivitySource("SourceActivityTriggeringCallerMemberNameAttribute"))
{
using ActivityListener listener = new ActivityListener();
listener.ShouldListenTo = (activitySource) => object.ReferenceEquals(aSource, activitySource);
listener.Sample = (ref ActivityCreationOptions<ActivityContext> activityOptions) => ActivitySamplingResult.AllData;

ActivitySource.AddActivityListener(listener);

string methodName = MethodBase.GetCurrentMethod().Name;

using (Activity activity = aSource.StartActivity()) // passing default name should trigger CallerMemberName attribute.
{
Assert.NotNull(activity);
Assert.True(methodName.IndexOf(activity.OperationName, StringComparison.Ordinal) >= 0);

using (Activity activity1 = aSource.StartActivity(ActivityKind.Client)) // passing default name should trigger CallerMemberName attribute.
{
Assert.NotNull(activity1);
Assert.True(methodName.IndexOf(activity1.OperationName, StringComparison.Ordinal) >= 0);
Assert.Equal(ActivityKind.Client, activity1.Kind);
}

ActivityContext parentContext = new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None);
List<KeyValuePair<string, object>> tags = new List<KeyValuePair<string, object>>() { new KeyValuePair<string, object>("Key", "Value") };
List<ActivityLink> links = new List<ActivityLink>() { new ActivityLink(new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.None, "key-value")) };
DateTimeOffset startTime = DateTimeOffset.UtcNow;

using (Activity activity2 = aSource.StartActivity(ActivityKind.Server, parentContext, tags, links, startTime))
{
Assert.NotNull(activity2);
Assert.True(methodName.IndexOf(activity2.OperationName, StringComparison.Ordinal) >= 0);
Assert.Equal(ActivityKind.Server, activity2.Kind);
Assert.Equal(tags, activity2.TagObjects);
Assert.Equal(links, activity2.Links);
Assert.Equal(startTime, activity2.StartTimeUtc);
Assert.Equal(parentContext.TraceId, activity2.TraceId);
Assert.Equal(parentContext.SpanId, activity2.ParentSpanId);
Assert.Equal(parentContext.TraceFlags, activity2.ActivityTraceFlags);
Assert.Equal(parentContext.TraceState, activity2.TraceStateString);
}
}
}
}).Dispose();
}

[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
public void TestActivitySourceAttachedObject()
{
Expand Down