using System.Diagnostics;
using CoreAgent.Infrastructure.Options;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace CoreAgent.Infrastructure.Extensions.Logging;
///
/// 请求日志中间件
///
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
private readonly RequestLoggingOptions _options;
public RequestLoggingMiddleware(
RequestDelegate next,
ILogger logger,
IOptions options)
{
_next = next;
_logger = logger;
_options = options.Value;
}
public async Task InvokeAsync(HttpContext context)
{
if (ShouldSkipLogging(context))
{
await _next(context);
return;
}
var sw = Stopwatch.StartNew();
var requestBody = string.Empty;
try
{
if (_options.LogRequestBody && context.Request.Body != null)
{
requestBody = await ReadRequestBodyAsync(context.Request);
}
_logger.LogInformation(
"Request started: {Method} {Path} {QueryString} {RequestBody}",
context.Request.Method,
context.Request.Path,
context.Request.QueryString,
requestBody);
await _next(context);
}
finally
{
sw.Stop();
_logger.LogInformation(
"Request completed: {Method} {Path} in {ElapsedMilliseconds}ms with status code {StatusCode}",
context.Request.Method,
context.Request.Path,
sw.ElapsedMilliseconds,
context.Response.StatusCode);
}
}
private bool ShouldSkipLogging(HttpContext context)
{
if (_options.ExcludePaths.Any(p => context.Request.Path.StartsWithSegments(p)))
{
return true;
}
if (_options.ExcludeMethods.Contains(context.Request.Method))
{
return true;
}
return false;
}
private async Task ReadRequestBodyAsync(HttpRequest request)
{
if (!request.Body.CanRead || !request.Body.CanSeek)
{
return string.Empty;
}
var originalPosition = request.Body.Position;
request.Body.Position = 0;
try
{
using var reader = new StreamReader(
request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: 1024 * 45,
leaveOpen: true);
var body = await reader.ReadToEndAsync();
return body.Length > _options.MaxRequestBodySize
? body.Substring(0, _options.MaxRequestBodySize) + "..."
: body;
}
finally
{
request.Body.Position = originalPosition;
}
}
}