From 3d75927d2fc8698d866bf6ffa1ab7298c253cde5 Mon Sep 17 00:00:00 2001 From: Jon Sagara Date: Sun, 24 Sep 2023 10:14:44 -0700 Subject: [PATCH] Use high performance logging in RedisCache. --- Directory.Build.props | 2 +- src/Sagara.Core.Caching/RedisAdminCache.cs | 2 +- src/Sagara.Core.Caching/RedisCache.cs | 30 ++++++++--------- src/Sagara.Core.Caching/RedisCacheLogger.cs | 32 +++++++++++++++++++ .../Sagara.Core.Caching.csproj | 3 -- 5 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 src/Sagara.Core.Caching/RedisCacheLogger.cs diff --git a/Directory.Build.props b/Directory.Build.props index fd10f77..a318a5d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ 12.0 - 2.0.0-rc2 + 2.0.0-rc3 2.0.0 2.0.0 Jon Sagara diff --git a/src/Sagara.Core.Caching/RedisAdminCache.cs b/src/Sagara.Core.Caching/RedisAdminCache.cs index 679918b..f5723e0 100644 --- a/src/Sagara.Core.Caching/RedisAdminCache.cs +++ b/src/Sagara.Core.Caching/RedisAdminCache.cs @@ -53,7 +53,7 @@ await server catch (Exception ex) { // Don't let the cache server bring down the application. - _logger.LogError(ex, "Unhandled exception while trying to delete all the keys of all databases on the server."); + RedisCacheLogger.UnhandledException(_logger, ex, command: "FLUSHALL", key: "(all keys)"); } } diff --git a/src/Sagara.Core.Caching/RedisCache.cs b/src/Sagara.Core.Caching/RedisCache.cs index d6a409a..b54b3bd 100644 --- a/src/Sagara.Core.Caching/RedisCache.cs +++ b/src/Sagara.Core.Caching/RedisCache.cs @@ -56,22 +56,22 @@ protected ConnectionMultiplexer InitializeConnectionMultiplexer(ConfigurationOpt // Log connection and error events. multiplexer.ConnectionFailed += (sender, e) => { - _logger.LogError(e.Exception, "{LogPrefix}ConnectionFailed: Connection type '{ConnectionType}' on EndPoint '{EndPoint}' reported ConnectionFailureType '{FailureType}'", logPrefix, e.ConnectionType, e.EndPoint, e.FailureType); + RedisCacheLogger.OnConnectionFailed(_logger, e.Exception, logPrefix, e.ConnectionType, e.EndPoint, e.FailureType); }; multiplexer.ConnectionRestored += (sender, e) => { - _logger.LogInformation(e.Exception, "{LogPrefix}ConnectionRestored: Connection type '{ConnectionType}' on EndPoint '{EndPoint}' reported ConnectionFailureType '{FailureType}'", logPrefix, e.ConnectionType, e.EndPoint, e.FailureType); + RedisCacheLogger.OnConnectionRestored(_logger, e.Exception, logPrefix, e.ConnectionType, e.EndPoint, e.FailureType); }; multiplexer.ErrorMessage += (sender, e) => { - _logger.LogError("{LogPrefix}ErrorMessage: Server '{EndPoint}' reported this error message: {Message}", logPrefix, e.EndPoint, e.Message); + RedisCacheLogger.OnErrorMessage(_logger, logPrefix, e.EndPoint, e.Message); }; multiplexer.ServerMaintenanceEvent += (sender, e) => { - _logger.LogWarning("{LogPrefix}ServerMaintenanceEvent: Server maintenance event received at {ReceivedTimeUtc}. Expected start time is {StartTimeUtc}. Raw message: {RawMessage}", logPrefix, e.ReceivedTimeUtc, e.StartTimeUtc, e.RawMessage); + RedisCacheLogger.OnServerMaintenanceEvent(_logger, logPrefix, e.ReceivedTimeUtc, e.StartTimeUtc, e.RawMessage); }; return multiplexer; @@ -107,7 +107,7 @@ protected ConnectionMultiplexer InitializeConnectionMultiplexer(ConfigurationOpt catch (Exception ex) { // Don't let cache server unavailability bring down the application. - _logger.LogError(ex, "Unhandled exception trying to async GET {Key}", key); + RedisCacheLogger.UnhandledException(_logger, ex, command: "GET", key: key); } return default; @@ -155,7 +155,7 @@ protected ConnectionMultiplexer InitializeConnectionMultiplexer(ConfigurationOpt catch (Exception ex) { // Don't let cache server unavailability bring down the application. - _logger.LogError(ex, "Unhandled exception trying to async GET/EXPIRE {Key}", key); + RedisCacheLogger.UnhandledException(_logger, ex, command: "GET/EXPIRE", key: key); } return default; @@ -189,7 +189,7 @@ protected ConnectionMultiplexer InitializeConnectionMultiplexer(ConfigurationOpt catch (Exception ex) { // Don't let cache server unavailability bring down the application. - _logger.LogError(ex, "Unhandled exception trying to GET/EXPIRE {Key}", key); + RedisCacheLogger.UnhandledException(_logger, ex, command: "GET/EXPIRE", key: key); } return default; @@ -219,7 +219,7 @@ public async Task SetAsync(string key, object value, TimeSpan? expiry = nu catch (Exception ex) { // Don't let cache server unavailability bring down the application. - _logger.LogError(ex, "Unhandled exception trying to async SET {Key}", key); + RedisCacheLogger.UnhandledException(_logger, ex, command: "SET", key: key); } return false; @@ -247,7 +247,7 @@ public bool Set(string key, object value, TimeSpan? expiry = null) catch (Exception ex) { // Don't let cache server unavailability bring down the application. - _logger.LogError(ex, "Unhandled exception trying to SET {Key}", key); + RedisCacheLogger.UnhandledException(_logger, ex, command: "SET", key: key); } return false; @@ -274,7 +274,7 @@ public bool Set(string key, object value, TimeSpan? expiry = null) // catch (Exception ex) // { // // Don't let cache server unavailability bring down the application. - // _logger.LogError(ex, "Unhandled exception trying to INCR {Key}", key); + // RedisCacheLogger.UnhandledException(_logger, ex, command: "INCR", key: key); // } // return 0L; @@ -300,7 +300,7 @@ public async Task RemoveAsync(string key) catch (Exception ex) { // Don't let cache server unavailability bring down the application. - _logger.LogError(ex, "Unhandled exception trying to async DEL {Key}", key); + RedisCacheLogger.UnhandledException(_logger, ex, command: "DEL", key: key); } return false; @@ -331,7 +331,7 @@ public async Task RemoveAsync(IReadOnlyCollection keys) catch (Exception ex) { // Don't let cache server unavailability bring down the application. - _logger.LogError(ex, "Unhandled exception trying to async DEL {KeysJoined}", string.Join(" ", keys)); + RedisCacheLogger.UnhandledException(_logger, ex, command: "DEL", key: string.Join(" ", keys)); } } @@ -380,7 +380,7 @@ public async Task IncrementAndExpireOnCreateAsync(string key, TimeSpan exp catch (Exception ex) { // Don't let cache server unavailability bring down the application. - _logger.LogError(ex, "Unhandled exception trying to INCR and EXPIRE On Create of the key {Key}", key); + RedisCacheLogger.UnhandledException(_logger, ex, command: "INCR and EXPIRE On Create", key: key); } return 0L; @@ -414,7 +414,7 @@ await GetSubscriber() catch (Exception ex) { // Don't let cache server unavailability bring down the application. - _logger.LogError(ex, "Unhandled exception trying to SUBSCRIBE {Channel}", channel); + RedisCacheLogger.UnhandledSubscribeException(_logger, ex, channel); } } @@ -432,7 +432,7 @@ public async Task PublishAsync(RedisChannel channel, RedisValue message) catch (Exception ex) { // Don't let cache server unavailability bring down the application. - _logger.LogError(ex, "Unhandled exception trying to async PUBLISH {Channel} {Message}", channel, message); + RedisCacheLogger.UnhandledPublishException(_logger, ex, channel, message); } return 0L; diff --git a/src/Sagara.Core.Caching/RedisCacheLogger.cs b/src/Sagara.Core.Caching/RedisCacheLogger.cs new file mode 100644 index 0000000..0194517 --- /dev/null +++ b/src/Sagara.Core.Caching/RedisCacheLogger.cs @@ -0,0 +1,32 @@ +using System.Net; +using Microsoft.Extensions.Logging; +using StackExchange.Redis; + +namespace Sagara.Core.Caching; + +/// +/// High-performance logging for ASP.NET Core. See: https://learn.microsoft.com/en-us/dotnet/core/extensions/logger-message-generator +/// +internal static partial class RedisCacheLogger +{ + [LoggerMessage(EventId = 0, Level = LogLevel.Error, Message = "{LogPrefix}ConnectionFailed: Connection type '{ConnectionType}' on EndPoint '{EndPoint}' reported ConnectionFailureType '{FailureType}'")] + public static partial void OnConnectionFailed(ILogger logger, Exception? ex, string logPrefix, ConnectionType connectionType, EndPoint? endPoint, ConnectionFailureType failureType); + + [LoggerMessage(EventId = 0, Level = LogLevel.Information, Message = "{LogPrefix}ConnectionRestored: Connection type '{ConnectionType}' on EndPoint '{EndPoint}' reported ConnectionFailureType '{FailureType}'")] + public static partial void OnConnectionRestored(ILogger logger, Exception? ex, string logPrefix, ConnectionType connectionType, EndPoint? endPoint, ConnectionFailureType failureType); + + [LoggerMessage(EventId = 0, Level = LogLevel.Error, Message = "{LogPrefix}ErrorMessage: Server '{EndPoint}' reported this error message: {Message}")] + public static partial void OnErrorMessage(ILogger logger, string logPrefix, EndPoint? endPoint, string message); + + [LoggerMessage(EventId = 0, Level = LogLevel.Warning, Message = "{LogPrefix}ServerMaintenanceEvent: Server maintenance event received at {ReceivedTimeUtc}. Expected start time is {StartTimeUtc}. Raw message: {RawMessage}")] + public static partial void OnServerMaintenanceEvent(ILogger logger, string logPrefix, DateTime receivedTimeUtc, DateTime? startTimeUtc, string? rawMessage); + + [LoggerMessage(EventId = 0, Level = LogLevel.Error, Message = "Unhandled exception trying to async {Command} {Key}")] + public static partial void UnhandledException(ILogger logger, Exception ex, string command, string key); + + [LoggerMessage(EventId = 0, Level = LogLevel.Error, Message = "Unhandled exception trying to SUBSCRIBE {Channel}")] + public static partial void UnhandledSubscribeException(ILogger logger, Exception ex, RedisChannel channel); + + [LoggerMessage(EventId = 0, Level = LogLevel.Error, Message = "Unhandled exception trying to async PUBLISH {Channel} {Message}")] + public static partial void UnhandledPublishException(ILogger logger, Exception ex, RedisChannel channel, RedisValue message); +} diff --git a/src/Sagara.Core.Caching/Sagara.Core.Caching.csproj b/src/Sagara.Core.Caching/Sagara.Core.Caching.csproj index 98ee584..ea13263 100644 --- a/src/Sagara.Core.Caching/Sagara.Core.Caching.csproj +++ b/src/Sagara.Core.Caching/Sagara.Core.Caching.csproj @@ -19,9 +19,6 @@ snupkg true True - - - $(NoWarn);CA1848