From 2d98b78be782bc1a4bb0499cf7ce7d7230daac86 Mon Sep 17 00:00:00 2001 From: skwasjer <11424653+skwasjer@users.noreply.github.com> Date: Sat, 3 Feb 2024 04:54:13 +0100 Subject: [PATCH] perf(CA1848): Use the LoggerMessage delegates --- src/MockHttp.Server/Server/Log.cs | 24 +++++++++++ .../Server/ServerRequestHandler.cs | 14 ++---- test/MockHttp.Server.Tests/Server/LogTests.cs | 43 +++++++++++++++++++ 3 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 src/MockHttp.Server/Server/Log.cs create mode 100644 test/MockHttp.Server.Tests/Server/LogTests.cs diff --git a/src/MockHttp.Server/Server/Log.cs b/src/MockHttp.Server/Server/Log.cs new file mode 100644 index 00000000..cee35dc2 --- /dev/null +++ b/src/MockHttp.Server/Server/Log.cs @@ -0,0 +1,24 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace MockHttp.Server; + +internal static partial class Log +{ + internal const string LogRequestMessageTemplate = "Connection id \"{ConnectionId}\", Request id \"{RequestId}\": {Message}"; + +#if NET6_0_OR_GREATER + [LoggerMessage( + EventId = 0, + Level = LogLevel.Debug, + Message = LogRequestMessageTemplate)] + private static partial void LogDebugRequestMessage(ILogger logger, string connectionId, string requestId, string message, Exception? exception); +#else + private static readonly Action LogDebugRequestMessage = LoggerMessage.Define(LogLevel.Debug, new EventId(0), LogRequestMessageTemplate); +#endif + + public static void LogRequestMessage(this ILogger logger, HttpContext httpContext, string message, Exception? exception = null) + { + LogDebugRequestMessage(logger, httpContext.Connection.Id, httpContext.TraceIdentifier, message, exception); + } +} diff --git a/src/MockHttp.Server/Server/ServerRequestHandler.cs b/src/MockHttp.Server/Server/ServerRequestHandler.cs index 1cbbd8d3..76765288 100644 --- a/src/MockHttp.Server/Server/ServerRequestHandler.cs +++ b/src/MockHttp.Server/Server/ServerRequestHandler.cs @@ -25,7 +25,7 @@ public async Task HandleAsync(HttpContext httpContext, Func _) throw new ArgumentNullException(nameof(httpContext)); } - LogRequestMessage(httpContext, Resources.Debug_HandlingRequest); + _logger.LogRequestMessage(httpContext, Resources.Debug_HandlingRequest); CancellationToken cancellationToken = httpContext.RequestAborted; HttpResponse response = httpContext.Response; @@ -40,7 +40,7 @@ public async Task HandleAsync(HttpContext httpContext, Func _) } catch (Exception ex) { - LogRequestMessage(httpContext, Resources.Error_VerifyMockSetup); + _logger.LogRequestMessage(httpContext, Resources.Error_VerifyMockSetup); #pragma warning disable CA2000 // Dispose objects before losing scope httpResponseMessage = new HttpResponseMessage(HttpStatusCode.InternalServerError) @@ -52,7 +52,7 @@ public async Task HandleAsync(HttpContext httpContext, Func _) } finally { - LogRequestMessage(httpContext, Resources.Debug_RequestHandled); + _logger.LogRequestMessage(httpContext, Resources.Debug_RequestHandled); } // Dispose message when response is done. @@ -67,12 +67,4 @@ public async Task HandleAsync(HttpContext httpContext, Func _) } await httpResponseMessage.MapToFeatureAsync(responseFeature, responseBodyFeature, cancellationToken).ConfigureAwait(false); } - - private void LogRequestMessage(HttpContext httpContext, string message, LogLevel logLevel = LogLevel.Debug, Exception? ex = null) - { - string formattedMessage = Resources.RequestLogMessage + message; -#pragma warning disable CA2254 // Template should be a static expression - _logger.Log(logLevel, ex, formattedMessage, httpContext.Connection.Id, httpContext.TraceIdentifier); -#pragma warning restore CA2254 // Template should be a static expression - } } diff --git a/test/MockHttp.Server.Tests/Server/LogTests.cs b/test/MockHttp.Server.Tests/Server/LogTests.cs new file mode 100644 index 00000000..bf29c8e7 --- /dev/null +++ b/test/MockHttp.Server.Tests/Server/LogTests.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace MockHttp.Server; + +public sealed class LogTests +{ + [Fact] + public void Log_should_produce_expected_output() + { + ILogger? logger = Substitute.For(); + logger.IsEnabled(Arg.Any()).Returns(true); + + string traceId = Guid.NewGuid().ToString("D"); + string connId = Guid.NewGuid().ToString("D"); + var httpContext = new DefaultHttpContext { TraceIdentifier = traceId, Connection = { Id = connId } }; + + const string customMessage = "hello world"; + var ex = new InvalidOperationException(); + + Func>, bool> assertState = state => + { + state.Should().ContainKey("{OriginalFormat}").WhoseValue.Should().Be(Log.LogRequestMessageTemplate); + state.Should().ContainKey("RequestId").WhoseValue.Should().Be(traceId); + state.Should().ContainKey("ConnectionId").WhoseValue.Should().Be(connId); + state.Should().ContainKey("Message").WhoseValue.Should().Be(customMessage); + return true; + }; + + // Act + logger.LogRequestMessage(httpContext, customMessage, ex); + + // Assert + logger.Received(1) + .Log( + LogLevel.Debug, + Arg.Is(e => e.Id == 0), + Arg.Is>>(state => assertState(state)), + ex, + Arg.Any>, Exception?, string>>() + ); + } +}