From 28e4b185a6f13ba84087b53e491d8871b7fd5c1e Mon Sep 17 00:00:00 2001 From: Carlos Neto Date: Mon, 13 Nov 2023 15:07:54 +0000 Subject: [PATCH] Stopping activity as before, and using ticks timestamp to compute duration instead of activity durationCalculating the metrics duration on the metrics handler instead of stopping asp.net activity --- .../ActivityHelper.cs | 8 +---- .../Implementation/HttpInMetricsListener.cs | 29 ++++++++++++++++--- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/ActivityHelper.cs b/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/ActivityHelper.cs index fadcd4b7fa..7e66bec332 100644 --- a/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/ActivityHelper.cs +++ b/src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/ActivityHelper.cs @@ -133,12 +133,7 @@ public static void StopAspNetActivity(TextMapPropagator textMapPropagator, Activ var currentActivity = Activity.Current; context.Items[ContextKey] = null; - // Make sure that the activity has a proper end time before onRequestStoppedCallback is called. - // Note that the activity must not be stopped before the callback is called. - if (aspNetActivity.Duration == TimeSpan.Zero) - { - aspNetActivity.SetEndTime(DateTime.UtcNow); - } + aspNetActivity.Stop(); try { @@ -149,7 +144,6 @@ public static void StopAspNetActivity(TextMapPropagator textMapPropagator, Activ AspNetTelemetryEventSource.Log.CallbackException(aspNetActivity, "OnStopped", callbackEx); } - aspNetActivity.Stop(); AspNetTelemetryEventSource.Log.ActivityStopped(aspNetActivity); if (textMapPropagator is not TraceContextPropagator) diff --git a/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInMetricsListener.cs b/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInMetricsListener.cs index 8ce43d5675..eb7c5e112a 100644 --- a/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInMetricsListener.cs +++ b/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInMetricsListener.cs @@ -24,30 +24,41 @@ namespace OpenTelemetry.Instrumentation.AspNet.Implementation; internal sealed class HttpInMetricsListener : IDisposable { + private static long syncStopwatchTicks; private readonly Histogram httpServerDuration; private readonly AspNetMetricsInstrumentationOptions options; public HttpInMetricsListener(Meter meter, AspNetMetricsInstrumentationOptions options) { this.httpServerDuration = meter.CreateHistogram("http.server.duration", "ms", "Measures the duration of inbound HTTP requests."); + TelemetryHttpModule.Options.OnRequestStartedCallback += this.OnStartActivity; TelemetryHttpModule.Options.OnRequestStoppedCallback += this.OnStopActivity; this.options = options; } public void Dispose() { + TelemetryHttpModule.Options.OnRequestStartedCallback -= this.OnStartActivity; TelemetryHttpModule.Options.OnRequestStoppedCallback -= this.OnStopActivity; } + private static long TimestampDifference() + { + return (long)((Stopwatch.GetTimestamp() - syncStopwatchTicks) * 10000000L / + (double)Stopwatch.Frequency); + } + + private void OnStartActivity(Activity activity, HttpContext context) + { + syncStopwatchTicks = Stopwatch.GetTimestamp(); + } + private void OnStopActivity(Activity activity, HttpContext context) { - // TODO: This is just a minimal set of attributes. See the spec for additional attributes: - // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/semantic_conventions/http-metrics.md#http-server var tags = new TagList { { SemanticConventions.AttributeHttpMethod, context.Request.HttpMethod }, { SemanticConventions.AttributeHttpScheme, context.Request.Url.Scheme }, - { SemanticConventions.AttributeHttpStatusCode, context.Response.StatusCode }, }; if (this.options.Enrich is not null) @@ -62,6 +73,16 @@ private void OnStopActivity(Activity activity, HttpContext context) } } - this.httpServerDuration.Record(activity.Duration.TotalMilliseconds, tags); + TimeSpan duration = activity.Duration; + if (duration == TimeSpan.Zero) + { + duration = activity.StartTimeUtc.AddTicks(TimestampDifference()) - activity.StartTimeUtc; + if (duration.Ticks <= 0) + { + duration = new TimeSpan(1); + } + } + + this.httpServerDuration.Record(duration.TotalMilliseconds, tags); } }