Skip to content
Permalink
Browse files

Request/response logging (#6)

  • Loading branch information
elanderson committed Dec 10, 2019
1 parent 506c43c commit c1b24de0d44dfc45d379b91d721842656c4ba3d8
@@ -16,6 +16,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.0.0" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.2.0" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="3.0.0" />
<PackageReference Include="NSwag.AspNetCore" Version="13.1.3" />
</ItemGroup>
@@ -0,0 +1,88 @@
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.IO;

namespace ContactsApi.Middleware
{
public class RequestResponseLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;

public RequestResponseLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
_next = next;
_logger = loggerFactory.CreateLogger<RequestResponseLoggingMiddleware>();
_recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
}

public async Task Invoke(HttpContext context)
{
await LogRequest(context);
await LogResponse(context);
}

private async Task LogRequest(HttpContext context)
{
context.Request.EnableBuffering();

await using var requestStream = _recyclableMemoryStreamManager.GetStream();
await context.Request.Body.CopyToAsync(requestStream);
_logger.LogInformation($"Http Request Information:{Environment.NewLine}" +
$"Schema:{context.Request.Scheme} " +
$"Host: {context.Request.Host} " +
$"Path: {context.Request.Path} " +
$"QueryString: {context.Request.QueryString} " +
$"Request Body: {ReadStreamInChunks(requestStream)}");
context.Request.Body.Position = 0;
}

private async Task LogResponse(HttpContext context)
{
var originalBodyStream = context.Response.Body;

await using var responseBody = _recyclableMemoryStreamManager.GetStream();
context.Response.Body = responseBody;

await _next(context);

context.Response.Body.Seek(0, SeekOrigin.Begin);
var text = await new StreamReader(context.Response.Body).ReadToEndAsync();
context.Response.Body.Seek(0, SeekOrigin.Begin);

_logger.LogInformation($"Http Response Information:{Environment.NewLine}" +
$"Schema:{context.Request.Scheme} " +
$"Host: {context.Request.Host} " +
$"Path: {context.Request.Path} " +
$"QueryString: {context.Request.QueryString} " +
$"Response Body: {text}");

await responseBody.CopyToAsync(originalBodyStream);
}

private static string ReadStreamInChunks(Stream stream)
{
const int readChunkBufferLength = 4096;

stream.Seek(0, SeekOrigin.Begin);

using var textWriter = new StringWriter();
using var reader = new StreamReader(stream);

var readChunk = new char[readChunkBufferLength];
int readChunkLength;

do
{
readChunkLength = reader.ReadBlock(readChunk, 0, readChunkBufferLength);
textWriter.Write(readChunk, 0, readChunkLength);
} while (readChunkLength > 0);

return textWriter.ToString();
}
}
}
@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Builder;

namespace ContactsApi.Middleware
{
public static class RequestResponseLoggingMiddlewareExtensions
{
public static IApplicationBuilder UseRequestResponseLogging(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestResponseLoggingMiddleware>();
}
}
}
@@ -1,4 +1,5 @@
using ContactsApi.Data;
using ContactsApi.Middleware;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
@@ -47,6 +48,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseDeveloperExceptionPage();
}

app.UseRequestResponseLogging();

app.UseCors(AllowAllCors);

app.UseHttpsRedirection();

0 comments on commit c1b24de

Please sign in to comment.
You can’t perform that action at this time.