Skip to content

Commit a3717a3

Browse files
authored
Add more load balancing logging (#1791)
1 parent ca40f28 commit a3717a3

File tree

3 files changed

+89
-8
lines changed

3 files changed

+89
-8
lines changed

src/Grpc.Net.Client/Balancer/Subchannel.cs

+68-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#if SUPPORT_LOAD_BALANCING
2020
using System;
2121
using System.Collections.Generic;
22+
using System.Diagnostics;
2223
using System.Linq;
2324
using System.Net;
2425
using System.Threading;
@@ -56,12 +57,13 @@ public sealed class Subchannel : IDisposable
5657
/// </summary>
5758
internal ConnectivityState State => _state;
5859

59-
private readonly ConnectionManager _manager;
60+
internal readonly ConnectionManager _manager;
6061
private readonly ILogger _logger;
6162

6263
private ConnectContext? _connectContext;
6364
private ConnectivityState _state;
6465
private TaskCompletionSource<object?>? _delayInterruptTcs;
66+
private int _currentRegistrationId;
6567

6668
/// <summary>
6769
/// Gets the current connected address.
@@ -101,25 +103,40 @@ public IDisposable OnStateChanged(Action<SubchannelState> callback)
101103
return registration;
102104
}
103105

106+
private string GetNextRegistrationId()
107+
{
108+
var registrationId = Interlocked.Increment(ref _currentRegistrationId);
109+
return Id + "-" + registrationId;
110+
}
111+
104112
private sealed class StateChangedRegistration : IDisposable
105113
{
106114
private readonly Subchannel _subchannel;
107115
private readonly Action<SubchannelState> _callback;
108116

117+
public string RegistrationId { get; }
118+
109119
public StateChangedRegistration(Subchannel subchannel, Action<SubchannelState> callback)
110120
{
111121
_subchannel = subchannel;
112122
_callback = callback;
123+
RegistrationId = subchannel.GetNextRegistrationId();
124+
125+
SubchannelLog.StateChangedRegistrationCreated(_subchannel._logger, _subchannel.Id, RegistrationId);
113126
}
114127

115128
public void Invoke(SubchannelState state)
116129
{
130+
SubchannelLog.ExecutingStateChangedRegistration(_subchannel._logger, _subchannel.Id, RegistrationId);
117131
_callback(state);
118132
}
119133

120134
public void Dispose()
121135
{
122-
_subchannel._stateChangedRegistrations.Remove(this);
136+
if (_subchannel._stateChangedRegistrations.Remove(this))
137+
{
138+
SubchannelLog.StateChangedRegistrationRemoved(_subchannel._logger, _subchannel.Id, RegistrationId);
139+
}
123140
}
124141
}
125142

@@ -348,6 +365,10 @@ internal void RaiseStateChanged(ConnectivityState state, Status status)
348365
registration.Invoke(subchannelState);
349366
}
350367
}
368+
else
369+
{
370+
SubchannelLog.NoStateChangedRegistrations(_logger, Id);
371+
}
351372
}
352373

353374
/// <inheritdocs />
@@ -379,6 +400,11 @@ public IReadOnlyList<BalancerAddress> GetAddresses()
379400
public void Dispose()
380401
{
381402
UpdateConnectivityState(ConnectivityState.Shutdown, "Subchannel disposed.");
403+
404+
foreach (var registration in _stateChangedRegistrations)
405+
{
406+
SubchannelLog.StateChangedRegistrationRemoved(_logger, Id, registration.RegistrationId);
407+
}
382408
_stateChangedRegistrations.Clear();
383409

384410
CancelInProgressConnect();
@@ -421,6 +447,21 @@ internal static class SubchannelLog
421447
private static readonly Action<ILogger, int, ConnectivityState, string, Exception?> _subchannelStateChanged =
422448
LoggerMessage.Define<int, ConnectivityState, string>(LogLevel.Debug, new EventId(11, "SubchannelStateChanged"), "Subchannel id '{SubchannelId}' state changed to {State}. Detail: '{Detail}'.");
423449

450+
private static readonly Action<ILogger, int, string, Exception?> _stateChangedRegistrationCreated =
451+
LoggerMessage.Define<int, string>(LogLevel.Trace, new EventId(12, "StateChangedRegistrationCreated"), "Subchannel id '{SubchannelId}' state changed registration '{RegistrationId}' created.");
452+
453+
private static readonly Action<ILogger, int, string, Exception?> _stateChangedRegistrationRemoved =
454+
LoggerMessage.Define<int, string>(LogLevel.Trace, new EventId(13, "StateChangedRegistrationRemoved"), "Subchannel id '{SubchannelId}' state changed registration '{RegistrationId}' removed.");
455+
456+
private static readonly Action<ILogger, int, string, Exception?> _executingStateChangedRegistration =
457+
LoggerMessage.Define<int, string>(LogLevel.Trace, new EventId(14, "ExecutingStateChangedRegistration"), "Subchannel id '{SubchannelId}' executing state changed registration '{RegistrationId}'.");
458+
459+
private static readonly Action<ILogger, int, Exception?> _noStateChangedRegistrations =
460+
LoggerMessage.Define<int>(LogLevel.Trace, new EventId(15, "NoStateChangedRegistrations"), "Subchannel id '{SubchannelId}' has no state changed registrations.");
461+
462+
private static readonly Action<ILogger, int, BalancerAddress, Exception?> _subchannelPreserved =
463+
LoggerMessage.Define<int, BalancerAddress>(LogLevel.Trace, new EventId(16, "SubchannelPreserved"), "Subchannel id '{SubchannelId}' matches address '{Address}' and is preserved.");
464+
424465
public static void SubchannelCreated(ILogger logger, int subchannelId, IReadOnlyList<BalancerAddress> addresses)
425466
{
426467
if (logger.IsEnabled(LogLevel.Debug))
@@ -479,6 +520,31 @@ public static void SubchannelStateChanged(ILogger logger, int subchannelId, Conn
479520
{
480521
_subchannelStateChanged(logger, subchannelId, state, status.Detail, status.DebugException);
481522
}
523+
524+
public static void ExecutingStateChangedRegistration(ILogger logger, int subchannelId, string registrationId)
525+
{
526+
_executingStateChangedRegistration(logger, subchannelId, registrationId, null);
527+
}
528+
529+
public static void NoStateChangedRegistrations(ILogger logger, int subchannelId)
530+
{
531+
_noStateChangedRegistrations(logger, subchannelId, null);
532+
}
533+
534+
public static void StateChangedRegistrationCreated(ILogger logger, int subchannelId, string registrationId)
535+
{
536+
_stateChangedRegistrationCreated(logger, subchannelId, registrationId, null);
537+
}
538+
539+
public static void StateChangedRegistrationRemoved(ILogger logger, int subchannelId, string registrationId)
540+
{
541+
_stateChangedRegistrationRemoved(logger, subchannelId, registrationId, null);
542+
}
543+
544+
public static void SubchannelPreserved(ILogger logger, int subchannelId, BalancerAddress address)
545+
{
546+
_subchannelPreserved(logger, subchannelId, address, null);
547+
}
482548
}
483549
}
484550
#endif

src/Grpc.Net.Client/Balancer/SubchannelsLoadBalancer.cs

+20-5
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#if SUPPORT_LOAD_BALANCING
2020
using System;
2121
using System.Collections.Generic;
22+
using System.Globalization;
2223
using System.Linq;
2324
using System.Net;
2425
using Grpc.Core;
@@ -133,15 +134,17 @@ public override void UpdateChannelState(ChannelState state)
133134
// Check existing subchannels for a match.
134135
var i = FindSubchannelByAddress(currentSubchannels, address);
135136

136-
AddressSubchannel newOrCurrentSubConnection;
137+
AddressSubchannel newOrCurrentSubchannel;
137138
if (i != null)
138139
{
139140
// There is a match so take current subchannel.
140-
newOrCurrentSubConnection = currentSubchannels[i.GetValueOrDefault()];
141+
newOrCurrentSubchannel = currentSubchannels[i.GetValueOrDefault()];
141142

142143
// Remove from current collection because any subchannels
143144
// remaining in this collection at the end will be disposed.
144145
currentSubchannels.RemoveAt(i.GetValueOrDefault());
146+
147+
SubchannelLog.SubchannelPreserved(_logger, newOrCurrentSubchannel.Subchannel.Id, address);
145148
}
146149
else
147150
{
@@ -150,10 +153,10 @@ public override void UpdateChannelState(ChannelState state)
150153
c.OnStateChanged(s => UpdateSubchannelState(c, s));
151154

152155
newSubchannels.Add(c);
153-
newOrCurrentSubConnection = new AddressSubchannel(c, address);
156+
newOrCurrentSubchannel = new AddressSubchannel(c, address);
154157
}
155158

156-
allUpdatedSubchannels.Add(newOrCurrentSubConnection);
159+
allUpdatedSubchannels.Add(newOrCurrentSubchannel);
157160
}
158161

159162
// Any sub-connections still in this collection are no longer returned by the resolver.
@@ -227,6 +230,7 @@ private void UpdateBalancingState(Status status)
227230
}
228231
else
229232
{
233+
SubchannelsLoadBalancerLog.CreatingReadyPicker(_logger, readySubchannels);
230234
UpdateChannelState(ConnectivityState.Ready, CreatePicker(readySubchannels));
231235
}
232236
}
@@ -298,7 +302,7 @@ protected override void Dispose(bool disposing)
298302
/// <returns>A subchannel picker.</returns>
299303
protected abstract SubchannelPicker CreatePicker(IReadOnlyList<Subchannel> readySubchannels);
300304

301-
private class AddressSubchannel
305+
private sealed class AddressSubchannel
302306
{
303307
private ConnectivityState _lastKnownState;
304308

@@ -340,6 +344,9 @@ internal static class SubchannelsLoadBalancerLog
340344
private static readonly Action<ILogger, int, ConnectivityState, Exception?> _requestingConnectionForSubchannel =
341345
LoggerMessage.Define<int, ConnectivityState>(LogLevel.Trace, new EventId(5, "RequestingConnectionForSubchannel"), "Requesting connection for subchannel id '{SubchannelId}' because it is in state {State}.");
342346

347+
private static readonly Action<ILogger, int, string, Exception?> _creatingReadyPicker =
348+
LoggerMessage.Define<int, string>(LogLevel.Trace, new EventId(6, "CreatingReadyPicker"), "Creating ready picker with {SubchannelCount} subchannels: {Subchannels}");
349+
343350
public static void ProcessingSubchannelStateChanged(ILogger logger, int subchannelId, ConnectivityState state, Status status)
344351
{
345352
_processingSubchannelStateChanged(logger, subchannelId, state, status.Detail, status.DebugException);
@@ -364,6 +371,14 @@ public static void RequestingConnectionForSubchannel(ILogger logger, int subchan
364371
{
365372
_requestingConnectionForSubchannel(logger, subchannelId, state, null);
366373
}
374+
375+
public static void CreatingReadyPicker(ILogger logger, List<Subchannel> readySubchannels)
376+
{
377+
if (logger.IsEnabled(LogLevel.Trace))
378+
{
379+
_creatingReadyPicker(logger, readySubchannels.Count, string.Join(", ", readySubchannels.Select(s => $"id '{s.Id}' ({string.Join(",", s.GetAddresses())})")), null);
380+
}
381+
}
367382
}
368383
}
369384
#endif

test/FunctionalTests/Balancer/BalancerHelpers.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ public TestSubchannelTransportFactory(TimeSpan socketPingInterval, TimeSpan? con
259259
public ISubchannelTransport Create(Subchannel subchannel)
260260
{
261261
#if NET5_0_OR_GREATER
262-
return new SocketConnectivitySubchannelTransport(subchannel, _socketPingInterval, _connectTimeout, NullLoggerFactory.Instance);
262+
return new SocketConnectivitySubchannelTransport(subchannel, _socketPingInterval, _connectTimeout, subchannel._manager.LoggerFactory);
263263
#else
264264
return new PassiveSubchannelTransport(subchannel);
265265
#endif

0 commit comments

Comments
 (0)