Skip to content

Commit 911f92c

Browse files
Kahbazihalter73
authored andcommitted
Log heartbeat duration for slow heartbeats (#15273)
1 parent a23dd41 commit 911f92c

File tree

6 files changed

+19
-14
lines changed

6 files changed

+19
-14
lines changed

src/Servers/Kestrel/Core/src/Internal/Infrastructure/Heartbeat.cs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -18,6 +18,7 @@ internal class Heartbeat : IDisposable
1818
private readonly TimeSpan _interval;
1919
private Timer _timer;
2020
private int _executingOnHeartbeat;
21+
private long _lastHeartbeatTicks;
2122

2223
public Heartbeat(IHeartbeatHandler[] callbacks, ISystemClock systemClock, IDebugger debugger, IKestrelTrace trace)
2324
{
@@ -46,6 +47,8 @@ internal void OnHeartbeat()
4647

4748
if (Interlocked.Exchange(ref _executingOnHeartbeat, 1) == 0)
4849
{
50+
Volatile.Write(ref _lastHeartbeatTicks, now.Ticks);
51+
4952
try
5053
{
5154
foreach (var callback in _callbacks)
@@ -66,7 +69,9 @@ internal void OnHeartbeat()
6669
{
6770
if (!_debugger.IsAttached)
6871
{
69-
_trace.HeartbeatSlow(_interval, now);
72+
var lastHeartbeatTicks = Volatile.Read(ref _lastHeartbeatTicks);
73+
74+
_trace.HeartbeatSlow(TimeSpan.FromTicks(now.Ticks - lastHeartbeatTicks), _interval, now);
7075
}
7176
}
7277
}

src/Servers/Kestrel/Core/src/Internal/Infrastructure/IKestrelTrace.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ internal interface IKestrelTrace : ILogger
3939

4040
void NotAllConnectionsAborted();
4141

42-
void HeartbeatSlow(TimeSpan interval, DateTimeOffset now);
42+
void HeartbeatSlow(TimeSpan heartbeatDuration, TimeSpan interval, DateTimeOffset now);
4343

4444
void ApplicationNeverCompleted(string connectionId);
4545

src/Servers/Kestrel/Core/src/Internal/Infrastructure/KestrelTrace.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ internal class KestrelTrace : IKestrelTrace
4747
private static readonly Action<ILogger, Exception> _notAllConnectionsAborted =
4848
LoggerMessage.Define(LogLevel.Debug, new EventId(21, nameof(NotAllConnectionsAborted)), "Some connections failed to abort during server shutdown.");
4949

50-
private static readonly Action<ILogger, TimeSpan, DateTimeOffset, Exception> _heartbeatSlow =
51-
LoggerMessage.Define<TimeSpan, DateTimeOffset>(LogLevel.Warning, new EventId(22, nameof(HeartbeatSlow)), @"Heartbeat took longer than ""{interval}"" at ""{now}"". This could be caused by thread pool starvation.");
50+
private static readonly Action<ILogger, TimeSpan, TimeSpan, DateTimeOffset, Exception> _heartbeatSlow =
51+
LoggerMessage.Define<TimeSpan, TimeSpan, DateTimeOffset>(LogLevel.Warning, new EventId(22, nameof(HeartbeatSlow)), @"As of ""{now}"", the heartbeat has been running for ""{heartbeatDuration}"" which is longer than ""{interval}"". This could be caused by thread pool starvation.");
5252

5353
private static readonly Action<ILogger, string, Exception> _applicationNeverCompleted =
5454
LoggerMessage.Define<string>(LogLevel.Critical, new EventId(23, nameof(ApplicationNeverCompleted)), @"Connection id ""{ConnectionId}"" application never completed");
@@ -190,9 +190,9 @@ public virtual void NotAllConnectionsAborted()
190190
_notAllConnectionsAborted(_logger, null);
191191
}
192192

193-
public virtual void HeartbeatSlow(TimeSpan interval, DateTimeOffset now)
193+
public virtual void HeartbeatSlow(TimeSpan heartbeatDuration, TimeSpan interval, DateTimeOffset now)
194194
{
195-
_heartbeatSlow(_logger, interval, now, null);
195+
_heartbeatSlow(_logger, heartbeatDuration, interval, now, null);
196196
}
197197

198198
public virtual void ApplicationNeverCompleted(string connectionId)

src/Servers/Kestrel/Core/test/HeartbeatTests.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -54,7 +54,7 @@ public async Task BlockedHeartbeatDoesntCauseOverlapsAndIsLoggedAsError()
5454
await blockedHeartbeatTask.DefaultTimeout();
5555

5656
heartbeatHandler.Verify(h => h.OnHeartbeat(systemClock.UtcNow), Times.Once());
57-
kestrelTrace.Verify(t => t.HeartbeatSlow(Heartbeat.Interval, systemClock.UtcNow), Times.Once());
57+
kestrelTrace.Verify(t => t.HeartbeatSlow(TimeSpan.Zero, Heartbeat.Interval, systemClock.UtcNow), Times.Once());
5858
}
5959

6060
[Fact]
@@ -91,7 +91,7 @@ public async Task BlockedHeartbeatIsNotLoggedAsErrorIfDebuggerAttached()
9191
await blockedHeartbeatTask.DefaultTimeout();
9292

9393
heartbeatHandler.Verify(h => h.OnHeartbeat(systemClock.UtcNow), Times.Once());
94-
kestrelTrace.Verify(t => t.HeartbeatSlow(Heartbeat.Interval, systemClock.UtcNow), Times.Never());
94+
kestrelTrace.Verify(t => t.HeartbeatSlow(TimeSpan.Zero, Heartbeat.Interval, systemClock.UtcNow), Times.Never());
9595
}
9696

9797
[Fact]

src/Servers/Kestrel/perf/Kestrel.Performance/Mocks/MockTrace.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
3838
public void NotAllConnectionsAborted() { }
3939
public void NotAllConnectionsClosedGracefully() { }
4040
public void RequestProcessingError(string connectionId, Exception ex) { }
41-
public void HeartbeatSlow(TimeSpan interval, DateTimeOffset now) { }
41+
public void HeartbeatSlow(TimeSpan heartbeatDuration, TimeSpan interval, DateTimeOffset now) { }
4242
public void ApplicationNeverCompleted(string connectionId) { }
4343
public void RequestBodyStart(string connectionId, string traceIdentifier) { }
4444
public void RequestBodyDone(string connectionId, string traceIdentifier) { }

src/Servers/Kestrel/shared/test/CompositeKestrelTrace.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,10 @@ public void NotAllConnectionsAborted()
122122
_trace2.NotAllConnectionsAborted();
123123
}
124124

125-
public void HeartbeatSlow(TimeSpan interval, DateTimeOffset now)
125+
public void HeartbeatSlow(TimeSpan heartbeatDuration, TimeSpan interval, DateTimeOffset now)
126126
{
127-
_trace1.HeartbeatSlow(interval, now);
128-
_trace2.HeartbeatSlow(interval, now);
127+
_trace1.HeartbeatSlow(heartbeatDuration, interval, now);
128+
_trace2.HeartbeatSlow(heartbeatDuration, interval, now);
129129
}
130130

131131
public void ApplicationNeverCompleted(string connectionId)

0 commit comments

Comments
 (0)