Skip to content

Commit bb98152

Browse files
authored
fix #1108 - introduce LogProxy as an intermediary between the TextWriter; move the sync to there - allows safe detach from the logging (#1116)
1 parent 93ee0fb commit bb98152

File tree

9 files changed

+241
-205
lines changed

9 files changed

+241
-205
lines changed

src/StackExchange.Redis/ConfigurationOptions.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Security.Cryptography.X509Certificates;
1010
using System.Text;
1111
using System.Threading.Tasks;
12+
using static StackExchange.Redis.ConnectionMultiplexer;
1213

1314
namespace StackExchange.Redis
1415
{
@@ -523,7 +524,7 @@ internal bool HasDnsEndPoints()
523524
return false;
524525
}
525526

526-
internal async Task ResolveEndPointsAsync(ConnectionMultiplexer multiplexer, TextWriter log)
527+
internal async Task ResolveEndPointsAsync(ConnectionMultiplexer multiplexer, LogProxy log)
527528
{
528529
var cache = new Dictionary<string, IPAddress>(StringComparer.OrdinalIgnoreCase);
529530
for (int i = 0; i < EndPoints.Count; i++)
@@ -542,12 +543,12 @@ internal async Task ResolveEndPointsAsync(ConnectionMultiplexer multiplexer, Tex
542543
}
543544
else
544545
{
545-
multiplexer.LogLocked(log, "Using DNS to resolve '{0}'...", dns.Host);
546+
log?.WriteLine($"Using DNS to resolve '{dns.Host}'...");
546547
var ips = await Dns.GetHostAddressesAsync(dns.Host).ObserveErrors().ForAwait();
547548
if (ips.Length == 1)
548549
{
549550
ip = ips[0];
550-
multiplexer.LogLocked(log, "'{0}' => {1}", dns.Host, ip);
551+
log?.WriteLine($"'{dns.Host}' => {ip}");
551552
cache[dns.Host] = ip;
552553
EndPoints[i] = new IPEndPoint(ip, dns.Port);
553554
}
@@ -556,7 +557,7 @@ internal async Task ResolveEndPointsAsync(ConnectionMultiplexer multiplexer, Tex
556557
catch (Exception ex)
557558
{
558559
multiplexer.OnInternalError(ex);
559-
multiplexer.LogLocked(log, ex.Message);
560+
log?.WriteLine(ex.Message);
560561
}
561562
}
562563
}

src/StackExchange.Redis/ConnectionMultiplexer.cs

Lines changed: 195 additions & 168 deletions
Large diffs are not rendered by default.

src/StackExchange.Redis/DebuggingAids.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ static partial void OnTraceWithoutContext(string message, string category)
2020
Debug.WriteLine(message, Environment.CurrentManagedThreadId + " ~ " + category);
2121
}
2222

23-
partial void OnTraceLog(TextWriter log, string caller)
23+
partial void OnTraceLog(LogProxy log, string caller)
2424
{
2525
lock (UniqueId)
2626
{

src/StackExchange.Redis/Message.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,21 @@
88
using System.Threading;
99
using System.Threading.Tasks;
1010
using StackExchange.Redis.Profiling;
11+
using static StackExchange.Redis.ConnectionMultiplexer;
1112

1213
namespace StackExchange.Redis
1314
{
1415
internal sealed class LoggingMessage : Message
1516
{
16-
public readonly TextWriter log;
17+
public readonly LogProxy log;
1718
private readonly Message tail;
1819

19-
public static Message Create(TextWriter log, Message tail)
20+
public static Message Create(LogProxy log, Message tail)
2021
{
2122
return log == null ? tail : new LoggingMessage(log, tail);
2223
}
2324

24-
private LoggingMessage(TextWriter log, Message tail) : base(tail.Db, tail.Flags, tail.Command)
25+
private LoggingMessage(LogProxy log, Message tail) : base(tail.Db, tail.Flags, tail.Command)
2526
{
2627
this.log = log;
2728
this.tail = tail;
@@ -39,14 +40,14 @@ protected override void WriteImpl(PhysicalConnection physical)
3940
try
4041
{
4142
var bridge = physical.BridgeCouldBeNull;
42-
bridge?.Multiplexer?.LogLocked(log, "Writing to {0}: {1}", bridge, tail.CommandAndKey);
43+
log?.WriteLine($"Writing to {bridge}: {tail.CommandAndKey}");
4344
}
4445
catch { }
4546
tail.WriteTo(physical);
4647
}
4748
public override int ArgCount => tail.ArgCount;
4849

49-
public TextWriter Log => log;
50+
public LogProxy Log => log;
5051
}
5152

5253
internal abstract class Message : ICompletable

src/StackExchange.Redis/PhysicalBridge.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using Pipelines.Sockets.Unofficial;
1111
using Pipelines.Sockets.Unofficial.Threading;
1212
using static Pipelines.Sockets.Unofficial.Threading.MutexSlim;
13+
using static StackExchange.Redis.ConnectionMultiplexer;
1314
using PendingSubscriptionState = global::StackExchange.Redis.ConnectionMultiplexer.Subscription.PendingSubscriptionState;
1415

1516
namespace StackExchange.Redis
@@ -129,7 +130,7 @@ public void ReportNextFailure()
129130

130131
public override string ToString() => ConnectionType + "/" + Format.ToString(ServerEndPoint.EndPoint);
131132

132-
public void TryConnect(TextWriter log) => GetConnection(log);
133+
public void TryConnect(LogProxy log) => GetConnection(log);
133134

134135
private WriteResult QueueOrFailMessage(Message message)
135136
{
@@ -380,7 +381,7 @@ internal void KeepAlive()
380381
}
381382
}
382383

383-
internal async Task OnConnectedAsync(PhysicalConnection connection, TextWriter log)
384+
internal async Task OnConnectedAsync(PhysicalConnection connection, LogProxy log)
384385
{
385386
Trace("OnConnected");
386387
if (physical == connection && !isDisposed && ChangeState(State.Connecting, State.ConnectedEstablishing))
@@ -1097,15 +1098,15 @@ private bool ChangeState(State oldState, State newState)
10971098
return result;
10981099
}
10991100

1100-
private PhysicalConnection GetConnection(TextWriter log)
1101+
private PhysicalConnection GetConnection(LogProxy log)
11011102
{
11021103
if (state == (int)State.Disconnected)
11031104
{
11041105
try
11051106
{
11061107
if (!Multiplexer.IsDisposed)
11071108
{
1108-
Multiplexer.LogLocked(log, "Connecting {0}...", Name);
1109+
log?.WriteLine($"Connecting {Name}...");
11091110
Multiplexer.Trace("Connecting...", Name);
11101111
if (ChangeState(State.Disconnected, State.Connecting))
11111112
{
@@ -1122,7 +1123,7 @@ private PhysicalConnection GetConnection(TextWriter log)
11221123
}
11231124
catch (Exception ex)
11241125
{
1125-
Multiplexer.LogLocked(log, "Connect {0} failed: {1}", Name, ex.Message);
1126+
log?.WriteLine($"Connect {Name} failed: {ex.Message}");
11261127
Multiplexer.Trace("Connect failed: " + ex.Message, Name);
11271128
ChangeState(State.Disconnected);
11281129
OnInternalError(ex);

src/StackExchange.Redis/PhysicalConnection.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Threading.Tasks;
1919
using Pipelines.Sockets.Unofficial;
2020
using Pipelines.Sockets.Unofficial.Arenas;
21+
using static StackExchange.Redis.ConnectionMultiplexer;
2122

2223
namespace StackExchange.Redis
2324
{
@@ -85,7 +86,7 @@ public PhysicalConnection(PhysicalBridge bridge)
8586
OnCreateEcho();
8687
}
8788

88-
internal async Task BeginConnectAsync(TextWriter log)
89+
internal async Task BeginConnectAsync(LogProxy log)
8990
{
9091
var bridge = BridgeCouldBeNull;
9192
var endpoint = bridge?.ServerEndPoint?.EndPoint;
@@ -97,7 +98,7 @@ internal async Task BeginConnectAsync(TextWriter log)
9798
Trace("Connecting...");
9899
_socket = SocketManager.CreateSocket(endpoint);
99100
bridge.Multiplexer.OnConnecting(endpoint, bridge.ConnectionType);
100-
bridge.Multiplexer.LogLocked(log, "BeginConnect: {0}", Format.ToString(endpoint));
101+
log?.WriteLine($"BeginConnect: {Format.ToString(endpoint)}");
101102

102103
CancellationTokenSource timeoutSource = null;
103104
try
@@ -141,7 +142,7 @@ internal async Task BeginConnectAsync(TextWriter log)
141142
}
142143
else if (await ConnectedAsync(x, log, bridge.Multiplexer.SocketManager).ForAwait())
143144
{
144-
bridge.Multiplexer.LogLocked(log, "Starting read");
145+
log?.WriteLine("Starting read");
145146
try
146147
{
147148
StartReading();
@@ -161,7 +162,7 @@ internal async Task BeginConnectAsync(TextWriter log)
161162
}
162163
catch (ObjectDisposedException)
163164
{
164-
bridge.Multiplexer.LogLocked(log, "(socket shutdown)");
165+
log?.WriteLine("(socket shutdown)");
165166
try { RecordConnectionFailed(ConnectionFailureType.UnableToConnect, isInitialConnect: true); }
166167
catch (Exception inner)
167168
{
@@ -1251,7 +1252,7 @@ private static LocalCertificateSelectionCallback GetAmbientClientCertificateCall
12511252
return null;
12521253
}
12531254

1254-
internal async ValueTask<bool> ConnectedAsync(Socket socket, TextWriter log, SocketManager manager)
1255+
internal async ValueTask<bool> ConnectedAsync(Socket socket, LogProxy log, SocketManager manager)
12551256
{
12561257
var bridge = BridgeCouldBeNull;
12571258
if (bridge == null) return false;
@@ -1270,7 +1271,7 @@ internal async ValueTask<bool> ConnectedAsync(Socket socket, TextWriter log, Soc
12701271

12711272
if (config.Ssl)
12721273
{
1273-
bridge.Multiplexer.LogLocked(log, "Configuring SSL");
1274+
log?.WriteLine("Configuring TLS");
12741275
var host = config.SslHost;
12751276
if (string.IsNullOrWhiteSpace(host)) host = Format.ToStringHostOnly(bridge.ServerEndPoint.EndPoint);
12761277

@@ -1290,7 +1291,7 @@ internal async ValueTask<bool> ConnectedAsync(Socket socket, TextWriter log, Soc
12901291
bridge.Multiplexer?.SetAuthSuspect();
12911292
throw;
12921293
}
1293-
bridge.Multiplexer.LogLocked(log, $"SSL connection established successfully using protocol: {ssl.SslProtocol}");
1294+
log?.WriteLine($"TLS connection established successfully using protocol: {ssl.SslProtocol}");
12941295
}
12951296
catch (AuthenticationException authexception)
12961297
{
@@ -1308,7 +1309,7 @@ internal async ValueTask<bool> ConnectedAsync(Socket socket, TextWriter log, Soc
13081309

13091310
_ioPipe = pipe;
13101311

1311-
bridge.Multiplexer.LogLocked(log, "Connected {0}", bridge);
1312+
log?.WriteLine($"Connected {bridge}");
13121313

13131314
await bridge.OnConnectedAsync(this, log).ForAwait();
13141315
return true;

src/StackExchange.Redis/RedisServer.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Security.Cryptography;
77
using System.Text;
88
using System.Threading.Tasks;
9+
using static StackExchange.Redis.ConnectionMultiplexer;
910

1011
#pragma warning disable RCS1231 // Make parameter ref read-only.
1112

@@ -320,7 +321,10 @@ public Task<DateTime> LastSaveAsync(CommandFlags flags = CommandFlags.None)
320321

321322
public void MakeMaster(ReplicationChangeOptions options, TextWriter log = null)
322323
{
323-
multiplexer.MakeMaster(server, options, log);
324+
using (var proxy = LogProxy.TryCreate(log))
325+
{
326+
multiplexer.MakeMaster(server, options, proxy);
327+
}
324328
}
325329

326330
public void Save(SaveType type, CommandFlags flags = CommandFlags.None)

src/StackExchange.Redis/ResultProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ public virtual bool SetResult(PhysicalConnection connection, Message message, in
175175
{
176176
try
177177
{
178-
bridge?.Multiplexer?.LogLocked(logging.Log, "Response from {0} / {1}: {2}", bridge, message.CommandAndKey, result);
178+
logging.Log?.WriteLine($"Response from {bridge} / {message.CommandAndKey}: {result}");
179179
}
180180
catch { }
181181
}

src/StackExchange.Redis/ServerEndPoint.cs

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Text.RegularExpressions;
1010
using System.Threading;
1111
using System.Threading.Tasks;
12+
using static StackExchange.Redis.ConnectionMultiplexer;
1213
using static StackExchange.Redis.PhysicalBridge;
1314

1415
namespace StackExchange.Redis
@@ -155,7 +156,7 @@ public void Dispose()
155156
tmp?.Dispose();
156157
}
157158

158-
public PhysicalBridge GetBridge(ConnectionType type, bool create = true, TextWriter log = null)
159+
public PhysicalBridge GetBridge(ConnectionType type, bool create = true, LogProxy log = null)
159160
{
160161
if (isDisposed) return null;
161162
switch (type)
@@ -237,7 +238,7 @@ public void SetUnselectable(UnselectableFlags flags)
237238

238239
public ValueTask<WriteResult> TryWriteAsync(Message message) => GetBridge(message.Command)?.TryWriteAsync(message, isSlave) ?? new ValueTask<WriteResult>(WriteResult.NoConnectionAvailable);
239240

240-
internal void Activate(ConnectionType type, TextWriter log)
241+
internal void Activate(ConnectionType type, LogProxy log)
241242
{
242243
GetBridge(type, true, log);
243244
}
@@ -467,7 +468,7 @@ internal bool IsSelectable(RedisCommand command, bool allowDisconnected = false)
467468
return bridge != null && (allowDisconnected || bridge.IsConnected);
468469
}
469470

470-
internal Task OnEstablishingAsync(PhysicalConnection connection, TextWriter log)
471+
internal Task OnEstablishingAsync(PhysicalConnection connection, LogProxy log)
471472
{
472473
try
473474
{
@@ -624,7 +625,7 @@ internal void ReportNextFailure()
624625
subscription?.ReportNextFailure();
625626
}
626627

627-
internal Task<bool> SendTracer(TextWriter log = null)
628+
internal Task<bool> SendTracer(LogProxy log = null)
628629
{
629630
var msg = GetTracerMessage(false);
630631
msg = LoggingMessage.Create(log, msg);
@@ -727,7 +728,7 @@ internal void WriteDirectOrQueueFireAndForgetSync<T>(PhysicalConnection connecti
727728
}
728729
}
729730

730-
private PhysicalBridge CreateBridge(ConnectionType type, TextWriter log)
731+
private PhysicalBridge CreateBridge(ConnectionType type, LogProxy log)
731732
{
732733
if (Multiplexer.IsDisposed) return null;
733734
Multiplexer.Trace(type.ToString());
@@ -736,9 +737,9 @@ private PhysicalBridge CreateBridge(ConnectionType type, TextWriter log)
736737
return bridge;
737738
}
738739

739-
private async Task HandshakeAsync(PhysicalConnection connection, TextWriter log)
740+
private async Task HandshakeAsync(PhysicalConnection connection, LogProxy log)
740741
{
741-
Multiplexer.LogLocked(log, "Server handshake");
742+
log?.WriteLine("Server handshake");
742743
if (connection == null)
743744
{
744745
Multiplexer.Trace("No connection!?");
@@ -748,7 +749,7 @@ private async Task HandshakeAsync(PhysicalConnection connection, TextWriter log)
748749
string password = Multiplexer.RawConfig.Password;
749750
if (!string.IsNullOrWhiteSpace(password))
750751
{
751-
Multiplexer.LogLocked(log, "Authenticating (password)");
752+
log?.WriteLine("Authenticating (password)");
752753
msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.AUTH, (RedisValue)password);
753754
msg.SetInternalCall();
754755
await WriteDirectOrQueueFireAndForgetAsync(connection, msg, ResultProcessor.DemandOK).ForAwait();
@@ -762,7 +763,7 @@ private async Task HandshakeAsync(PhysicalConnection connection, TextWriter log)
762763
name = nameSanitizer.Replace(name, "");
763764
if (!string.IsNullOrWhiteSpace(name))
764765
{
765-
Multiplexer.LogLocked(log, "Setting client name: {0}", name);
766+
log?.WriteLine($"Setting client name: {name}");
766767
msg = Message.Create(-1, CommandFlags.FireAndForget, RedisCommand.CLIENT, RedisLiterals.SETNAME, (RedisValue)name);
767768
msg.SetInternalCall();
768769
await WriteDirectOrQueueFireAndForgetAsync(connection, msg, ResultProcessor.DemandOK).ForAwait();
@@ -779,10 +780,10 @@ private async Task HandshakeAsync(PhysicalConnection connection, TextWriter log)
779780

780781
if (connType == ConnectionType.Interactive)
781782
{
782-
Multiplexer.LogLocked(log, "Auto-configure...");
783+
log?.WriteLine("Auto-configure...");
783784
AutoConfigure(connection);
784785
}
785-
Multiplexer.LogLocked(log, "Sending critical tracer: {0}", bridge);
786+
log?.WriteLine($"Sending critical tracer: {bridge}");
786787
var tracer = GetTracerMessage(true);
787788
tracer = LoggingMessage.Create(log, tracer);
788789
await WriteDirectOrQueueFireAndForgetAsync(connection, tracer, ResultProcessor.EstablishConnection).ForAwait();
@@ -798,7 +799,7 @@ private async Task HandshakeAsync(PhysicalConnection connection, TextWriter log)
798799
await WriteDirectOrQueueFireAndForgetAsync(connection, msg, ResultProcessor.TrackSubscriptions).ForAwait();
799800
}
800801
}
801-
Multiplexer.LogLocked(log, "Flushing outbound buffer");
802+
log?.WriteLine("Flushing outbound buffer");
802803
await connection.FlushAsync().ForAwait();
803804
}
804805

0 commit comments

Comments
 (0)