From a889ca3dccc2a927a1203590931b41a02262e0a6 Mon Sep 17 00:00:00 2001 From: Meir Blachman Date: Wed, 23 Jul 2025 18:50:59 +0300 Subject: [PATCH 1/2] Migrates logging to structured LoggerMessage methods Replaces manual string interpolation with compile-time generated LoggerMessage methods for better performance and structured logging. Adds 16 new LoggerMessage extension methods covering response logging and auto-configuration scenarios for Redis server connections. Improves logging efficiency by eliminating runtime string formatting overhead and enables better log analysis through consistent message templates. --- src/StackExchange.Redis/LoggerExtensions.cs | 97 +++++++++++++++++++++ src/StackExchange.Redis/ResultProcessor.cs | 34 ++++---- 2 files changed, 114 insertions(+), 17 deletions(-) diff --git a/src/StackExchange.Redis/LoggerExtensions.cs b/src/StackExchange.Redis/LoggerExtensions.cs index 877de6257..c656401b8 100644 --- a/src/StackExchange.Redis/LoggerExtensions.cs +++ b/src/StackExchange.Redis/LoggerExtensions.cs @@ -488,4 +488,101 @@ internal static void LogWithThreadPoolStats(this ILogger? log, string message) EventId = 70, Message = "{Server}: Flushing outbound buffer")] internal static partial void LogInformationFlushingOutboundBuffer(this ILogger logger, ServerEndPointLogValue server); + + // ResultProcessor logging methods + [LoggerMessage( + Level = LogLevel.Information, + EventId = 71, + Message = "Response from {BridgeName} / {CommandAndKey}: {Result}")] + internal static partial void LogInformationResponse(this ILogger logger, string? bridgeName, string commandAndKey, RawResult result); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 72, + Message = "{Server}: Auto-configured role: replica")] + internal static partial void LogInformationAutoConfiguredRoleReplica(this ILogger logger, ServerEndPointLogValue server); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 73, + Message = "{Server}: Auto-configured (CLIENT) connection-id: {ConnectionId}")] + internal static partial void LogInformationAutoConfiguredClientConnectionId(this ILogger logger, ServerEndPointLogValue server, long connectionId); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 74, + Message = "{Server}: Auto-configured (INFO) role: {Role}")] + internal static partial void LogInformationAutoConfiguredInfoRole(this ILogger logger, ServerEndPointLogValue server, string role); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 75, + Message = "{Server}: Auto-configured (INFO) version: {Version}")] + internal static partial void LogInformationAutoConfiguredInfoVersion(this ILogger logger, ServerEndPointLogValue server, Version version); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 76, + Message = "{Server}: Auto-configured (INFO) server-type: {ServerType}")] + internal static partial void LogInformationAutoConfiguredInfoServerType(this ILogger logger, ServerEndPointLogValue server, ServerType serverType); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 77, + Message = "{Server}: Auto-configured (SENTINEL) server-type: sentinel")] + internal static partial void LogInformationAutoConfiguredSentinelServerType(this ILogger logger, ServerEndPointLogValue server); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 78, + Message = "{Server}: Auto-configured (CONFIG) timeout: {TimeoutSeconds}s")] + internal static partial void LogInformationAutoConfiguredConfigTimeout(this ILogger logger, ServerEndPointLogValue server, int timeoutSeconds); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 79, + Message = "{Server}: Auto-configured (CONFIG) databases: {DatabaseCount}")] + internal static partial void LogInformationAutoConfiguredConfigDatabases(this ILogger logger, ServerEndPointLogValue server, int databaseCount); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 80, + Message = "{Server}: Auto-configured (CONFIG) read-only replica: true")] + internal static partial void LogInformationAutoConfiguredConfigReadOnlyReplicaTrue(this ILogger logger, ServerEndPointLogValue server); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 81, + Message = "{Server}: Auto-configured (CONFIG) read-only replica: false")] + internal static partial void LogInformationAutoConfiguredConfigReadOnlyReplicaFalse(this ILogger logger, ServerEndPointLogValue server); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 82, + Message = "{Server}: Auto-configured (HELLO) server-version: {Version}")] + internal static partial void LogInformationAutoConfiguredHelloServerVersion(this ILogger logger, ServerEndPointLogValue server, Version version); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 83, + Message = "{Server}: Auto-configured (HELLO) protocol: {Protocol}")] + internal static partial void LogInformationAutoConfiguredHelloProtocol(this ILogger logger, ServerEndPointLogValue server, RedisProtocol protocol); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 84, + Message = "{Server}: Auto-configured (HELLO) connection-id: {ConnectionId}")] + internal static partial void LogInformationAutoConfiguredHelloConnectionId(this ILogger logger, ServerEndPointLogValue server, long connectionId); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 85, + Message = "{Server}: Auto-configured (HELLO) server-type: {ServerType}")] + internal static partial void LogInformationAutoConfiguredHelloServerType(this ILogger logger, ServerEndPointLogValue server, ServerType serverType); + + [LoggerMessage( + Level = LogLevel.Information, + EventId = 86, + Message = "{Server}: Auto-configured (HELLO) role: {Role}")] + internal static partial void LogInformationAutoConfiguredHelloRole(this ILogger logger, ServerEndPointLogValue server, string role); } diff --git a/src/StackExchange.Redis/ResultProcessor.cs b/src/StackExchange.Redis/ResultProcessor.cs index 982ee565d..eade40ab3 100644 --- a/src/StackExchange.Redis/ResultProcessor.cs +++ b/src/StackExchange.Redis/ResultProcessor.cs @@ -233,7 +233,7 @@ public virtual bool SetResult(PhysicalConnection connection, Message message, in { try { - logging.Log?.LogInformation($"Response from {bridge?.Name} / {message.CommandAndKey}: {result}"); + logging.Log?.LogInformationResponse(bridge?.Name, message.CommandAndKey, result); } catch { } } @@ -816,7 +816,7 @@ public override bool SetResult(PhysicalConnection connection, Message message, i if (bridge != null) { var server = bridge.ServerEndPoint; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured role: replica"); + Log?.LogInformationAutoConfiguredRoleReplica(new(server)); server.IsReplica = true; } } @@ -837,7 +837,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes if (result.TryGetInt64(out long clientId)) { connection.ConnectionId = clientId; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (CLIENT) connection-id: {clientId}"); + Log?.LogInformationAutoConfiguredClientConnectionId(new(server), clientId); SetResult(message, true); return true; @@ -871,7 +871,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes if (TryParseRole(val, out bool isReplica)) { server.IsReplica = isReplica; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (INFO) role: {(isReplica ? "replica" : "primary")}"); + Log?.LogInformationAutoConfiguredInfoRole(new(server), isReplica ? "replica" : "primary"); } } else if ((val = Extract(line, "master_host:")) != null) @@ -887,7 +887,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes if (Format.TryParseVersion(val, out Version? version)) { server.Version = version; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (INFO) version: " + version); + Log?.LogInformationAutoConfiguredInfoVersion(new(server), version); } } else if ((val = Extract(line, "redis_mode:")) != null) @@ -895,7 +895,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes if (TryParseServerType(val, out var serverType)) { server.ServerType = serverType; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (INFO) server-type: {serverType}"); + Log?.LogInformationAutoConfiguredInfoServerType(new(server), serverType); } } else if ((val = Extract(line, "run_id:")) != null) @@ -913,7 +913,7 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes else if (message?.Command == RedisCommand.SENTINEL) { server.ServerType = ServerType.Sentinel; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (SENTINEL) server-type: sentinel"); + Log?.LogInformationAutoConfiguredSentinelServerType(new(server)); } SetResult(message, true); return true; @@ -941,14 +941,14 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes { targetSeconds = (timeoutSeconds * 3) / 4; } - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (CONFIG) timeout: " + targetSeconds + "s"); + Log?.LogInformationAutoConfiguredConfigTimeout(new(server), targetSeconds); server.WriteEverySeconds = targetSeconds; } } else if (key.IsEqual(CommonReplies.databases) && val.TryGetInt64(out i64)) { int dbCount = checked((int)i64); - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (CONFIG) databases: " + dbCount); + Log?.LogInformationAutoConfiguredConfigDatabases(new(server), dbCount); server.Databases = dbCount; if (dbCount > 1) { @@ -960,12 +960,12 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes if (val.IsEqual(CommonReplies.yes)) { server.ReplicaReadOnly = true; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (CONFIG) read-only replica: true"); + Log?.LogInformationAutoConfiguredConfigReadOnlyReplicaTrue(new(server)); } else if (val.IsEqual(CommonReplies.no)) { server.ReplicaReadOnly = false; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (CONFIG) read-only replica: false"); + Log?.LogInformationAutoConfiguredConfigReadOnlyReplicaFalse(new(server)); } } } @@ -982,34 +982,34 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes if (key.IsEqual(CommonReplies.version) && Format.TryParseVersion(val.GetString(), out var version)) { server.Version = version; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (HELLO) server-version: {version}"); + Log?.LogInformationAutoConfiguredHelloServerVersion(new(server), version); } else if (key.IsEqual(CommonReplies.proto) && val.TryGetInt64(out var i64)) { connection.SetProtocol(i64 >= 3 ? RedisProtocol.Resp3 : RedisProtocol.Resp2); - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (HELLO) protocol: {connection.Protocol}"); + Log?.LogInformationAutoConfiguredHelloProtocol(new(server), connection.Protocol ?? RedisProtocol.Resp2); } else if (key.IsEqual(CommonReplies.id) && val.TryGetInt64(out i64)) { connection.ConnectionId = i64; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (HELLO) connection-id: {i64}"); + Log?.LogInformationAutoConfiguredHelloConnectionId(new(server), i64); } else if (key.IsEqual(CommonReplies.mode) && TryParseServerType(val.GetString(), out var serverType)) { server.ServerType = serverType; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (HELLO) server-type: {serverType}"); + Log?.LogInformationAutoConfiguredHelloServerType(new(server), serverType); } else if (key.IsEqual(CommonReplies.role) && TryParseRole(val.GetString(), out bool isReplica)) { server.IsReplica = isReplica; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (HELLO) role: {(isReplica ? "replica" : "primary")}"); + Log?.LogInformationAutoConfiguredHelloRole(new(server), isReplica ? "replica" : "primary"); } } } else if (message?.Command == RedisCommand.SENTINEL) { server.ServerType = ServerType.Sentinel; - Log?.LogInformation($"{Format.ToString(server)}: Auto-configured (SENTINEL) server-type: sentinel"); + Log?.LogInformationAutoConfiguredSentinelServerType(new(server)); } SetResult(message, true); return true; From 02c1b9b4f96d370d7419e5d9a16120456e8eb64b Mon Sep 17 00:00:00 2001 From: Marc Gravell Date: Thu, 24 Jul 2025 12:37:04 +0100 Subject: [PATCH 2/2] merge read-only-replica methods --- src/StackExchange.Redis/LoggerExtensions.cs | 10 ++-------- src/StackExchange.Redis/ResultProcessor.cs | 4 ++-- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/StackExchange.Redis/LoggerExtensions.cs b/src/StackExchange.Redis/LoggerExtensions.cs index c656401b8..3cb2ec6fb 100644 --- a/src/StackExchange.Redis/LoggerExtensions.cs +++ b/src/StackExchange.Redis/LoggerExtensions.cs @@ -544,17 +544,11 @@ internal static void LogWithThreadPoolStats(this ILogger? log, string message) Message = "{Server}: Auto-configured (CONFIG) databases: {DatabaseCount}")] internal static partial void LogInformationAutoConfiguredConfigDatabases(this ILogger logger, ServerEndPointLogValue server, int databaseCount); - [LoggerMessage( - Level = LogLevel.Information, - EventId = 80, - Message = "{Server}: Auto-configured (CONFIG) read-only replica: true")] - internal static partial void LogInformationAutoConfiguredConfigReadOnlyReplicaTrue(this ILogger logger, ServerEndPointLogValue server); - [LoggerMessage( Level = LogLevel.Information, EventId = 81, - Message = "{Server}: Auto-configured (CONFIG) read-only replica: false")] - internal static partial void LogInformationAutoConfiguredConfigReadOnlyReplicaFalse(this ILogger logger, ServerEndPointLogValue server); + Message = "{Server}: Auto-configured (CONFIG) read-only replica: {ReadOnlyReplica}")] + internal static partial void LogInformationAutoConfiguredConfigReadOnlyReplica(this ILogger logger, ServerEndPointLogValue server, bool readOnlyReplica); [LoggerMessage( Level = LogLevel.Information, diff --git a/src/StackExchange.Redis/ResultProcessor.cs b/src/StackExchange.Redis/ResultProcessor.cs index eade40ab3..627953941 100644 --- a/src/StackExchange.Redis/ResultProcessor.cs +++ b/src/StackExchange.Redis/ResultProcessor.cs @@ -960,12 +960,12 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes if (val.IsEqual(CommonReplies.yes)) { server.ReplicaReadOnly = true; - Log?.LogInformationAutoConfiguredConfigReadOnlyReplicaTrue(new(server)); + Log?.LogInformationAutoConfiguredConfigReadOnlyReplica(new(server), true); } else if (val.IsEqual(CommonReplies.no)) { server.ReplicaReadOnly = false; - Log?.LogInformationAutoConfiguredConfigReadOnlyReplicaFalse(new(server)); + Log?.LogInformationAutoConfiguredConfigReadOnlyReplica(new(server), false); } } }