Skip to content

Commit 89c29bb

Browse files
authored
[AspNet.Telemetry] Fix end of time (#3171)
1 parent fb89d09 commit 89c29bb

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Licensed to the .NET Foundation under one or more agreements.
5+
// The .NET Foundation licenses this file to you under the MIT license.
6+
// https://github.com/dotnet/runtime/blob/75662173e3918f2176b74e467dc8e41d4f01d4d4/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.DateTime.netfx.cs
7+
8+
// Adjusted to our coding standards and moved to separate class
9+
10+
using System.Diagnostics;
11+
12+
namespace OpenTelemetry.Instrumentation.AspNet;
13+
14+
internal static class ActivityDateTimeHelper
15+
{
16+
#pragma warning disable CA1823 // suppress unused field warning, as it's used to keep the timer alive
17+
private static readonly Timer SyncTimeUpdater = InitializeSyncTimer();
18+
#pragma warning restore CA1823
19+
private static readonly double TickFrequency = (double)TimeSpan.TicksPerSecond / Stopwatch.Frequency;
20+
21+
private static TimeSync timeSync = new();
22+
23+
/// <summary>
24+
/// Returns high resolution (1 DateTime tick) current UTC DateTime.
25+
/// </summary>
26+
/// <returns>High resolution UTC DateTime.</returns>
27+
internal static DateTime GetUtcNow()
28+
{
29+
// DateTime.UtcNow accuracy on .NET Framework is ~16ms, this method
30+
// uses combination of Stopwatch and DateTime to calculate accurate UtcNow.
31+
32+
var tmp = timeSync;
33+
34+
// Timer ticks need to be converted to DateTime ticks
35+
long dateTimeTicksDiff = (long)((Stopwatch.GetTimestamp() - tmp.SyncStopwatchTicks) * TickFrequency);
36+
37+
// DateTime.AddSeconds (or Milliseconds) rounds value to 1 ms, use AddTicks to prevent it
38+
return tmp.SyncUtcNow.AddTicks(dateTimeTicksDiff);
39+
}
40+
41+
private static void Sync()
42+
{
43+
// wait for DateTime.UtcNow update to the next granular value
44+
Thread.Sleep(1);
45+
timeSync = new TimeSync();
46+
}
47+
48+
[System.Security.SecuritySafeCritical]
49+
private static Timer InitializeSyncTimer()
50+
{
51+
Timer timer;
52+
53+
// Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
54+
bool restoreFlow = false;
55+
try
56+
{
57+
if (!ExecutionContext.IsFlowSuppressed())
58+
{
59+
ExecutionContext.SuppressFlow();
60+
restoreFlow = true;
61+
}
62+
63+
timer = new Timer(static _ => Sync(), null, 0, 7_200_000); // 2 hours
64+
}
65+
finally
66+
{
67+
// Restore the current ExecutionContext
68+
if (restoreFlow)
69+
{
70+
ExecutionContext.RestoreFlow();
71+
}
72+
}
73+
74+
return timer;
75+
}
76+
77+
private sealed class TimeSync
78+
{
79+
public readonly DateTime SyncUtcNow = DateTime.UtcNow;
80+
public readonly long SyncStopwatchTicks = Stopwatch.GetTimestamp();
81+
}
82+
}

src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/ActivityHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public static void StopAspNetActivity(TextMapPropagator textMapPropagator, Activ
120120
// Note that the activity must not be stopped before the callback is called.
121121
if (aspNetActivity.Duration == TimeSpan.Zero)
122122
{
123-
aspNetActivity.SetEndTime(DateTime.UtcNow);
123+
aspNetActivity.SetEndTime(ActivityDateTimeHelper.GetUtcNow());
124124
}
125125

126126
try

src/OpenTelemetry.Instrumentation.AspNet.TelemetryHttpModule/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
responsible for providing function returning `Activity`.
1212
([#3151](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3151))
1313

14+
* Fixed an inaccurate span end of time.
15+
([#3171](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/3171))
16+
1417
## 1.12.0-beta.2
1518

1619
Released 2025-Sep-18

0 commit comments

Comments
 (0)