Skip to content

Commit 3ab7789

Browse files
committed
Add test for the order of activity and metrics with HTTP requests
1 parent 16fb943 commit 3ab7789

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,10 @@ public void RequestEnd(HttpContext httpContext, Exception? exception, HostingApp
208208
}
209209

210210
var activity = context.Activity;
211-
// Always stop activity if it was started
211+
// Always stop activity if it was started.
212+
// The HTTP activity must be stopped after the HTTP request duration metric is recorded.
213+
// This order means the activity is ongoing while the metric is recorded and libraries like OTEL
214+
// can capture the activity as a metric exemplar.
212215
if (activity is not null)
213216
{
214217
StopActivity(httpContext, activity, context.HasDiagnosticListener);

src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,17 +156,61 @@ public void EventCountersEnabled()
156156
}
157157

158158
[Fact]
159-
public void MetricsEnabled()
159+
public void Metrics_RequestDuration_RecordedWithHttpActivity()
160160
{
161161
// Arrange
162-
var hostingEventSource = new HostingEventSource(Guid.NewGuid().ToString());
162+
using var activityListener = new ActivityListener
163+
{
164+
ShouldListenTo = activitySource => activitySource.Name == "Microsoft.AspNetCore",
165+
Sample = (ref ActivityCreationOptions<ActivityContext> _) => ActivitySamplingResult.AllData
166+
};
167+
ActivitySource.AddActivityListener(activityListener);
163168

169+
var testMeterFactory = new TestMeterFactory();
170+
171+
var meterListener = new MeterListener();
172+
meterListener.InstrumentPublished = (i, l) =>
173+
{
174+
if (i.Meter.Scope == testMeterFactory && i.Meter.Name == HostingMetrics.MeterName && i.Name == "http.server.request.duration")
175+
{
176+
l.EnableMeasurementEvents(i);
177+
}
178+
};
179+
180+
Activity measurementActivity = null;
181+
var measureCount = 0;
182+
meterListener.SetMeasurementEventCallback<double>((i, m, t, s) =>
183+
{
184+
if (Interlocked.Increment(ref measureCount) > 1)
185+
{
186+
throw new Exception("Unexpected measurement count.");
187+
}
188+
189+
measurementActivity = Activity.Current;
190+
});
191+
meterListener.Start();
192+
193+
// Act
194+
var hostingApplication = CreateApplication(out var features, meterFactory: testMeterFactory);
195+
var context = hostingApplication.CreateContext(features);
196+
hostingApplication.DisposeContext(context, null);
197+
198+
// Assert
199+
Assert.Equal(1, measureCount);
200+
Assert.NotNull(measurementActivity);
201+
Assert.Equal(HostingApplicationDiagnostics.ActivityName, measurementActivity.OperationName);
202+
}
203+
204+
[Fact]
205+
public void MetricsEnabled()
206+
{
207+
// Arrange
164208
var testMeterFactory = new TestMeterFactory();
165209
using var activeRequestsCollector = new MetricCollector<long>(testMeterFactory, HostingMetrics.MeterName, "http.server.active_requests");
166210
using var requestDurationCollector = new MetricCollector<double>(testMeterFactory, HostingMetrics.MeterName, "http.server.request.duration");
167211

168212
// Act
169-
var hostingApplication = CreateApplication(out var features, eventSource: hostingEventSource, meterFactory: testMeterFactory);
213+
var hostingApplication = CreateApplication(out var features, meterFactory: testMeterFactory);
170214
var context = hostingApplication.CreateContext(features);
171215

172216
// Assert

0 commit comments

Comments
 (0)