Skip to content

Commit 667f7ca

Browse files
authored
Don't fire DiagnosticSource.StopActivity in some cases (#9595)
- Don't fire the event if DiagnosticSource.StartActivity was never called. This avoids allocating the anonymous object and extra strings.
1 parent f0ea4fc commit 667f7ca

File tree

3 files changed

+61
-5
lines changed

3 files changed

+61
-5
lines changed

src/Hosting/Hosting/src/Internal/HostingApplication.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ public struct Context
6262
public long StartTimestamp { get; set; }
6363
public bool EventLogEnabled { get; set; }
6464
public Activity Activity { get; set; }
65+
internal bool HasDiagnosticListener { get; set; }
6566
}
6667
}
6768
}

src/Hosting/Hosting/src/Internal/HostingApplicationDiagnostics.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ public void BeginRequest(HttpContext httpContext, ref HostingApplication.Context
4848

4949
if (loggingEnabled || (diagnosticListenerEnabled && _diagnosticListener.IsEnabled(ActivityName, httpContext)))
5050
{
51-
context.Activity = StartActivity(httpContext);
51+
context.Activity = StartActivity(httpContext, out var hasDiagnosticListener);
52+
context.HasDiagnosticListener = hasDiagnosticListener;
5253
}
5354

5455
if (diagnosticListenerEnabled)
@@ -132,7 +133,7 @@ public void RequestEnd(HttpContext httpContext, Exception exception, HostingAppl
132133
// Always stop activity if it was started
133134
if (activity != null)
134135
{
135-
StopActivity(httpContext, activity);
136+
StopActivity(httpContext, activity, context.HasDiagnosticListener);
136137
}
137138

138139
if (context.EventLogEnabled && exception != null)
@@ -229,9 +230,10 @@ private static void RecordRequestStartEventLog(HttpContext httpContext)
229230
}
230231

231232
[MethodImpl(MethodImplOptions.NoInlining)]
232-
private Activity StartActivity(HttpContext httpContext)
233+
private Activity StartActivity(HttpContext httpContext, out bool hasDiagnosticListener)
233234
{
234235
var activity = new Activity(ActivityName);
236+
hasDiagnosticListener = false;
235237

236238
var headers = httpContext.Request.Headers;
237239
if (!headers.TryGetValue(HeaderNames.TraceParent, out var requestId))
@@ -266,6 +268,7 @@ private Activity StartActivity(HttpContext httpContext)
266268

267269
if (_diagnosticListener.IsEnabled(ActivityStartKey))
268270
{
271+
hasDiagnosticListener = true;
269272
_diagnosticListener.StartActivity(activity, new { HttpContext = httpContext });
270273
}
271274
else
@@ -277,9 +280,16 @@ private Activity StartActivity(HttpContext httpContext)
277280
}
278281

279282
[MethodImpl(MethodImplOptions.NoInlining)]
280-
private void StopActivity(HttpContext httpContext, Activity activity)
283+
private void StopActivity(HttpContext httpContext, Activity activity, bool hasDiagnosticListener)
281284
{
282-
_diagnosticListener.StopActivity(activity, new { HttpContext = httpContext });
285+
if (hasDiagnosticListener)
286+
{
287+
_diagnosticListener.StopActivity(activity, new { HttpContext = httpContext });
288+
}
289+
else
290+
{
291+
activity.Stop();
292+
}
283293
}
284294
}
285295
}

src/Hosting/Hosting/test/HostingApplicationTests.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,51 @@ public void CreateContextWithEnabledLoggerCreatesActivityAndSetsActivityIdInScop
5656
Assert.Equal(Activity.Current.Id, pairs["ActivityId"].ToString());
5757
}
5858

59+
[Fact]
60+
public void ActivityStopDoesNotFireIfNoListenerAttachedForStart()
61+
{
62+
// Arrange
63+
var diagnosticSource = new DiagnosticListener("DummySource");
64+
var logger = new LoggerWithScopes(isEnabled: true);
65+
var hostingApplication = CreateApplication(out var features, diagnosticSource: diagnosticSource, logger: logger);
66+
var startFired = false;
67+
var stopFired = false;
68+
69+
diagnosticSource.Subscribe(new CallbackDiagnosticListener(pair =>
70+
{
71+
// This should not fire
72+
if (pair.Key == "Microsoft.AspNetCore.Hosting.HttpRequestIn.Start")
73+
{
74+
startFired = true;
75+
}
76+
77+
// This should not fire
78+
if (pair.Key == "Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop")
79+
{
80+
stopFired = true;
81+
}
82+
}),
83+
(s, o, arg3) =>
84+
{
85+
// The events are off
86+
return false;
87+
});
88+
89+
90+
// Act
91+
var context = hostingApplication.CreateContext(features);
92+
93+
Assert.Single(logger.Scopes);
94+
var pairs = ((IReadOnlyList<KeyValuePair<string, object>>)logger.Scopes[0]).ToDictionary(p => p.Key, p => p.Value);
95+
Assert.Equal(Activity.Current.Id, pairs["ActivityId"].ToString());
96+
97+
hostingApplication.DisposeContext(context, exception: null);
98+
99+
Assert.False(startFired);
100+
Assert.False(stopFired);
101+
Assert.Null(Activity.Current);
102+
}
103+
59104
[Fact]
60105
public void ActivityIsNotCreatedWhenIsEnabledForActivityIsFalse()
61106
{

0 commit comments

Comments
 (0)