DeviceBridge/Common/RequestLoggingMiddleware.cs (81 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
namespace DeviceBridge.Common
{
internal class RequestLoggingMiddleware
{
private static readonly NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();
private readonly RequestDelegate _next;
public RequestLoggingMiddleware(RequestDelegate next)
{
this._next = next;
}
public async Task Invoke(HttpContext context)
{
var request = await FormatRequest(context.Request);
var logger = _logger.WithProperty("cv", Utils.GuidFromString(context.TraceIdentifier));
logger.SetProperty("path", context.Request.Path.Value);
var regexResult = Regex.Match(context.Request.Path, @"(?<=devices\/).*?(?=\/)");
if (regexResult.Success)
{
var deviceId = regexResult.Groups[0].Value;
logger.SetProperty("deviceId", deviceId);
}
logger.Info(request);
var originalBodyStream = context.Response.Body;
using (var responseBody = new MemoryStream())
{
context.Response.Body = responseBody;
try
{
await _next(context);
}
catch (Exception e)
{
var tmpResponse = FormatResponse(context.Response);
logger.Error(e, tmpResponse);
await responseBody.CopyToAsync(originalBodyStream);
return;
}
var response = FormatResponse(context.Response);
logger.Info(response);
await responseBody.CopyToAsync(originalBodyStream);
}
}
private async Task<string> FormatRequest(HttpRequest request)
{
request.EnableBuffering();
var buffer = new byte[Convert.ToInt32(request.ContentLength)];
await request.Body.ReadAsync(buffer, 0, buffer.Length);
var requestBody = Encoding.UTF8.GetString(buffer);
request.Body.Seek(0, SeekOrigin.Begin);
var builder = new StringBuilder(Environment.NewLine);
builder.AppendLine("{ headers: {");
foreach (var header in request.Headers)
{
var redactedHeaderValue = RedactHeaderValue(header);
builder.AppendLine($"{header.Key}:{redactedHeaderValue},");
}
builder.AppendLine($"}},body:{requestBody}}}");
return builder.ToString().Replace("\r\n", string.Empty);
}
private string RedactHeaderValue(System.Collections.Generic.KeyValuePair<string, StringValues> header)
{
if (header.Key.Equals("x-api-key"))
{
return "redacted";
}
return header.Value;
}
private string FormatResponse(HttpResponse response)
{
response.Body.Seek(0, SeekOrigin.Begin);
string responseBody = new StreamReader(response.Body).ReadToEnd();
response.Body.Seek(0, SeekOrigin.Begin);
return $"Response: {response.StatusCode}, {responseBody}";
}
}
}