diff --git a/src/rm.DelegatingHandlers/LoggingRequestHandler.cs b/src/rm.DelegatingHandlers/LoggingRequestHandler.cs new file mode 100644 index 0000000..dbd7965 --- /dev/null +++ b/src/rm.DelegatingHandlers/LoggingRequestHandler.cs @@ -0,0 +1,41 @@ +using System; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using rm.DelegatingHandlers.Formatting; +using Serilog; + +namespace rm.DelegatingHandlers; + +/// +/// Logs . +/// +public class LoggingRequestHandler : DelegatingHandler +{ + private readonly ILogger logger; + private readonly ILoggingFormatter loggingFormatter; + + /// + public LoggingRequestHandler( + ILogger logger, + ILoggingFormatter loggingFormatter) + { + this.logger = logger?.ForContext(GetType()) + ?? throw new ArgumentNullException(nameof(logger)); + this.loggingFormatter = loggingFormatter + ?? throw new ArgumentNullException(nameof(loggingFormatter)); + } + + protected override async Task SendAsync( + HttpRequestMessage request, + CancellationToken cancellationToken) + { + ILogger lRequest = logger; + lRequest = await lRequest.ForContextAsync(request, loggingFormatter) + .ConfigureAwait(false); + lRequest.Information("request/"); + + return await base.SendAsync(request, cancellationToken) + .ConfigureAwait(false); + } +} diff --git a/src/rm.DelegatingHandlers/LoggingHandler.cs b/src/rm.DelegatingHandlers/LoggingRequestResponseHandler.cs similarity index 86% rename from src/rm.DelegatingHandlers/LoggingHandler.cs rename to src/rm.DelegatingHandlers/LoggingRequestResponseHandler.cs index 54abd71..77563f8 100644 --- a/src/rm.DelegatingHandlers/LoggingHandler.cs +++ b/src/rm.DelegatingHandlers/LoggingRequestResponseHandler.cs @@ -12,13 +12,13 @@ namespace rm.DelegatingHandlers; /// Logs , and with /// exception, if any, along with its elapsed time. /// -public class LoggingHandler : DelegatingHandler +public class LoggingRequestResponseHandler : DelegatingHandler { private readonly ILogger logger; private readonly ILoggingFormatter loggingFormatter; - /// - public LoggingHandler( + /// + public LoggingRequestResponseHandler( ILogger logger, ILoggingFormatter loggingFormatter) { @@ -32,11 +32,6 @@ protected override async Task SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { - ILogger lRequest = logger; - lRequest = await lRequest.ForContextAsync(request, loggingFormatter) - .ConfigureAwait(false); - lRequest.Information("request/"); - var stopwatch = Stopwatch.StartNew(); try { diff --git a/tests/rm.DelegatingHandlersTest/Http2HandlerTests.cs b/tests/rm.DelegatingHandlersTest/Http2HandlerTests.cs index a4abcf1..43df778 100644 --- a/tests/rm.DelegatingHandlersTest/Http2HandlerTests.cs +++ b/tests/rm.DelegatingHandlersTest/Http2HandlerTests.cs @@ -26,13 +26,14 @@ public async Task Sends_Http2() new HttpRequestMessage(method, uri); var http2Handler = new Http2Handler(); - var loggingHandler = new LoggingHandler(logger, new LoggingFormatter()); + var loggingRequestResponseHandler = new LoggingRequestResponseHandler(logger, new LoggingFormatter()); + var loggingRequestHandler = new LoggingRequestHandler(logger, new LoggingFormatter()); using var httpclient = HttpClientFactory.Create( #if NETFRAMEWORK new WinHttpHandler(), #endif - http2Handler, loggingHandler); + loggingRequestResponseHandler, http2Handler, loggingRequestHandler); using var _ = await httpclient.SendAsync(request, CancellationToken.None); @@ -40,6 +41,11 @@ public async Task Sends_Http2() .HaveMessage("request/").Appearing().Once() .WithProperty($"request.Version").WithValue(version) ; + + InMemorySink.Instance.Should() + .HaveMessage("request/response").Appearing().Once() + .WithProperty($"request.Version").WithValue(version) + ; InMemorySink.Instance.Should() .HaveMessage("request/response").Appearing().Once() .WithProperty($"response.Version").WithValue(version) diff --git a/tests/rm.DelegatingHandlersTest/LoggingRequestHandlerTests.cs b/tests/rm.DelegatingHandlersTest/LoggingRequestHandlerTests.cs new file mode 100644 index 0000000..f699d42 --- /dev/null +++ b/tests/rm.DelegatingHandlersTest/LoggingRequestHandlerTests.cs @@ -0,0 +1,80 @@ +using System.Text; +using FluentAssertions; +using NUnit.Framework; +using rm.DelegatingHandlers; +using rm.DelegatingHandlers.Formatting; +using Serilog; +using Serilog.Events; +using Serilog.Formatting.Json; +using Serilog.Sinks.InMemory; +using Serilog.Sinks.InMemory.Assertions; + +namespace rm.DelegatingHandlersTest; + +[TestFixture] +public class LoggingRequestHandlerTests +{ + public class Formatter + { + [Test] + public async Task Logs_Request() + { + var logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.InMemory() + .WriteTo.Console(new JsonFormatter()) + .CreateLogger(); + var version = "2.0"; + var method = HttpMethod.Post; + var uri = "/health"; + var requestContent = "woot?!"; + var encoding = Encoding.UTF8; + var mimeType = MediaTypeNames.Application.Json; + var header1 = "header1"; + var headerValue1 = "headerValue1"; + var header2 = "header02"; + var headerValue2 = "headerValue02"; + var property1 = "property1"; + var propertyValue1 = "propertyValue1"; + var property2 = "property02"; + var propertyValue2 = "propertyValue02"; + using var request = + new HttpRequestMessage(method, uri) + { + Version = new Version(version), + Content = new StringContent(requestContent, encoding, mimeType), + }; + request.Headers.Add(header1, headerValue1); + request.Headers.Add(header2, headerValue2); +#pragma warning disable CS0618 // Type or member is obsolete + request.Properties.Add(property1, propertyValue1); + request.Properties.Add(property2, propertyValue2); +#pragma warning restore CS0618 // Type or member is obsolete + + var shortCircuitingCannedResponseHandler = new ShortCircuitingCannedResponseHandler(new HttpResponseMessage()); + var loggingRequestHandler = new LoggingRequestHandler(logger, new LoggingFormatter()); + + using var invoker = HttpMessageInvokerFactory.Create( + loggingRequestHandler, shortCircuitingCannedResponseHandler); + + using var _ = await invoker.SendAsync(request, CancellationToken.None); + + InMemorySink.Instance.Should() + .HaveMessage("request/").Appearing().Once() + .WithLevel(LogEventLevel.Information) + .WithProperty($"request.Version").WithValue(version) + .And.WithProperty($"request.HttpMethod").WithValue(method.ToString()) + .And.WithProperty($"request.Uri").WithValue(uri) + .And.WithProperty($"request.Header.{header1}").WithValue(headerValue1) + .And.WithProperty($"request.Header.{header2}").WithValue(headerValue2) + .And.WithProperty($"request.Content.Header.Content-Type").WithValue($"{mimeType}; charset={encoding.BodyName}") +#if NET6_0_OR_GREATER + .And.WithProperty($"request.Content.Header.Content-Length").WithValue(requestContent.Length.ToString()) +#endif + .And.WithProperty($"request.Content").WithValue(requestContent) + .And.WithProperty($"request.Property.{property1}").WithValue(propertyValue1) + .And.WithProperty($"request.Property.{property2}").WithValue(propertyValue2) + ; + } + } +} diff --git a/tests/rm.DelegatingHandlersTest/LoggingHandlerTests.cs b/tests/rm.DelegatingHandlersTest/LoggingRequestResponseHandlerTests.cs similarity index 83% rename from tests/rm.DelegatingHandlersTest/LoggingHandlerTests.cs rename to tests/rm.DelegatingHandlersTest/LoggingRequestResponseHandlerTests.cs index c9af55e..1a69281 100644 --- a/tests/rm.DelegatingHandlersTest/LoggingHandlerTests.cs +++ b/tests/rm.DelegatingHandlersTest/LoggingRequestResponseHandlerTests.cs @@ -1,8 +1,9 @@ using System.Net; using System.Text; -using AutoFixture.AutoMoq; using AutoFixture; +using AutoFixture.AutoMoq; using FluentAssertions; +using Moq; using NUnit.Framework; using rm.DelegatingHandlers; using rm.DelegatingHandlers.Formatting; @@ -14,78 +15,16 @@ using Serilog.Formatting.Json; using Serilog.Sinks.InMemory; using Serilog.Sinks.InMemory.Assertions; -using Moq; namespace rm.DelegatingHandlersTest; [TestFixture] -public class LoggingHandlerTests +public class LoggingRequestResponseHandlerTests { private static readonly Random rng = RandomFactory.GetThreadStaticRandom(); public class Formatter { - [Test] - public async Task Logs_Request() - { - var logger = new LoggerConfiguration() - .MinimumLevel.Verbose() - .WriteTo.InMemory() - .WriteTo.Console(new JsonFormatter()) - .CreateLogger(); - var version = "2.0"; - var method = HttpMethod.Post; - var uri = "/health"; - var requestContent = "woot?!"; - var encoding = Encoding.UTF8; - var mimeType = MediaTypeNames.Application.Json; - var header1 = "header1"; - var headerValue1 = "headerValue1"; - var header2 = "header02"; - var headerValue2 = "headerValue02"; - var property1 = "property1"; - var propertyValue1 = "propertyValue1"; - var property2 = "property02"; - var propertyValue2 = "propertyValue02"; - using var request = - new HttpRequestMessage(method, uri) - { - Version = new Version(version), - Content = new StringContent(requestContent, encoding, mimeType), - }; - request.Headers.Add(header1, headerValue1); - request.Headers.Add(header2, headerValue2); -#pragma warning disable CS0618 // Type or member is obsolete - request.Properties.Add(property1, propertyValue1); - request.Properties.Add(property2, propertyValue2); -#pragma warning restore CS0618 // Type or member is obsolete - - var shortCircuitingCannedResponseHandler = new ShortCircuitingCannedResponseHandler(new HttpResponseMessage()); - var loggingHandler = new LoggingHandler(logger, new LoggingFormatter()); - - using var invoker = HttpMessageInvokerFactory.Create( - loggingHandler, shortCircuitingCannedResponseHandler); - - using var _ = await invoker.SendAsync(request, CancellationToken.None); - - InMemorySink.Instance.Should() - .HaveMessage("request/").Appearing().Once() - .WithLevel(LogEventLevel.Information) - .WithProperty($"request.Version").WithValue(version) - .And.WithProperty($"request.HttpMethod").WithValue(method.ToString()) - .And.WithProperty($"request.Uri").WithValue(uri) - .And.WithProperty($"request.Header.{header1}").WithValue(headerValue1) - .And.WithProperty($"request.Header.{header2}").WithValue(headerValue2) - .And.WithProperty($"request.Content.Header.Content-Type").WithValue($"{mimeType}; charset={encoding.BodyName}") -#if NET6_0_OR_GREATER - .And.WithProperty($"request.Content.Header.Content-Length").WithValue(requestContent.Length.ToString()) -#endif - .And.WithProperty($"request.Content").WithValue(requestContent) - .And.WithProperty($"request.Property.{property1}").WithValue(propertyValue1) - .And.WithProperty($"request.Property.{property2}").WithValue(propertyValue2) - ; - } - [Test] public async Task Logs_Request_Response() { @@ -147,10 +86,10 @@ public async Task Logs_Request_Response() #pragma warning restore CS0618 // Type or member is obsolete return Task.FromResult(response); }); - var loggingHandler = new LoggingHandler(logger, new LoggingFormatter()); + var loggingRequestResponseHandler = new LoggingRequestResponseHandler(logger, new LoggingFormatter()); using var invoker = HttpMessageInvokerFactory.Create( - loggingHandler, delegateHandler, shortCircuitingCannedResponseHandler); + loggingRequestResponseHandler, delegateHandler, shortCircuitingCannedResponseHandler); using var _ = await invoker.SendAsync(request, CancellationToken.None); @@ -235,11 +174,11 @@ public async Task Logs_Request_Exception() response.Headers.Add(header2, headerValue2); var swallowingHandler = new SwallowingHandler(ex => ex is TurnDownForWhatException); - var loggingHandler = new LoggingHandler(logger, new LoggingFormatter()); + var loggingRequestResponseHandler = new LoggingRequestResponseHandler(logger, new LoggingFormatter()); var throwingHandler = new ThrowingHandler(new TurnDownForWhatException()); using var invoker = HttpMessageInvokerFactory.Create( - swallowingHandler, loggingHandler, throwingHandler); + swallowingHandler, loggingRequestResponseHandler, throwingHandler); using var _ = await invoker.SendAsync(request, CancellationToken.None); @@ -316,10 +255,10 @@ public async Task Logs_Request_Response_Compact() #endif var shortCircuitingCannedResponseHandler = new ShortCircuitingCannedResponseHandler(response); - var loggingHandler = new LoggingHandler(logger, new CompactLoggingFormatter()); + var loggingRequestResponseHandler = new LoggingRequestResponseHandler(logger, new CompactLoggingFormatter()); using var invoker = HttpMessageInvokerFactory.Create( - loggingHandler, shortCircuitingCannedResponseHandler); + loggingRequestResponseHandler, shortCircuitingCannedResponseHandler); using var _ = await invoker.SendAsync(request, CancellationToken.None); @@ -404,10 +343,10 @@ public async Task Logs_Request_Exception_Compact() var swallowingHandler = new SwallowingHandler(ex => ex is TurnDownForWhatException); var throwingHandler = new ThrowingHandler(new TurnDownForWhatException()); - var loggingHandler = new LoggingHandler(logger, new CompactLoggingFormatter()); + var loggingRequestResponseHandler = new LoggingRequestResponseHandler(logger, new CompactLoggingFormatter()); using var invoker = HttpMessageInvokerFactory.Create( - swallowingHandler, loggingHandler, throwingHandler); + swallowingHandler, loggingRequestResponseHandler, throwingHandler); using var _ = await invoker.SendAsync(request, CancellationToken.None); @@ -489,10 +428,10 @@ public async Task Logs_Request_Response_Sampling() using var request = new HttpRequestMessage(HttpMethod.Get, $"/{id}"); var shortCircuitingCannedResponseHandler = new ShortCircuitingCannedResponseHandler(new HttpResponseMessage()); - var loggingHandler = new LoggingHandler(logger, new CompactLoggingFormatter()); + var loggingRequestResponseHandler = new LoggingRequestResponseHandler(logger, new CompactLoggingFormatter()); using var invoker = HttpMessageInvokerFactory.Create( - loggingHandler, shortCircuitingCannedResponseHandler); + loggingRequestResponseHandler, shortCircuitingCannedResponseHandler); using var _ = await invoker.SendAsync(request, CancellationToken.None);